From cfa8d5302557a512ac2d4e22ae647e232836b27c Mon Sep 17 00:00:00 2001 From: SirSengir Date: Fri, 2 May 2014 21:31:20 +0200 Subject: [PATCH] Initial commit for GitHub. --- CLA.txt | 11 + CONTRIBUTING.md.txt | 16 + LICENSE.txt | 64 + README.md.txt | 28 + build.gradle | 123 ++ build.number | 3 + build.xml | 352 +++++ .../forestry/apiculture/BeekeepingLogic.java | 325 +++++ .../apiculture/CommandBeekeepingMode.java | 245 ++++ .../forestry/apiculture/CommandGiveBee.java | 117 ++ .../apiculture/FlowerProviderCacti.java | 81 ++ .../apiculture/FlowerProviderEnd.java | 58 + .../apiculture/FlowerProviderGourd.java | 76 + .../apiculture/FlowerProviderJungle.java | 82 ++ .../apiculture/FlowerProviderMushroom.java | 100 ++ .../apiculture/FlowerProviderNetherwart.java | 73 + .../apiculture/FlowerProviderVanilla.java | 109 ++ .../apiculture/FlowerProviderWheat.java | 76 + .../apiculture/GuiHandlerApiculture.java | 164 +++ .../forestry/apiculture/MaterialBeehive.java | 22 + .../apiculture/PacketHandlerApiculture.java | 51 + .../SaveEventHandlerApiculture.java | 30 + .../apiculture/SpeciesNotFoundException.java | 20 + .../apiculture/TemplateNotFoundException.java | 22 + .../apiculture/VillageHandlerApiculture.java | 74 + .../apiculture/entities/EntityBee.java | 88 ++ .../apiculture/gadgets/BlockAlveary.java | 229 ++++ .../apiculture/gadgets/BlockBeehives.java | 166 +++ .../apiculture/gadgets/BlockCandle.java | 416 ++++++ .../apiculture/gadgets/BlockStump.java | 80 ++ .../gadgets/StructureLogicAlveary.java | 116 ++ .../apiculture/gadgets/TileAlveary.java | 262 ++++ .../gadgets/TileAlvearyClimatiser.java | 157 +++ .../apiculture/gadgets/TileAlvearyFan.java | 19 + .../apiculture/gadgets/TileAlvearyHeater.java | 22 + .../gadgets/TileAlvearyHygroregulator.java | 294 ++++ .../apiculture/gadgets/TileAlvearyPlain.java | 839 ++++++++++++ .../apiculture/gadgets/TileAlvearySieve.java | 179 +++ .../gadgets/TileAlvearyStabiliser.java | 115 ++ .../gadgets/TileAlvearySwarmer.java | 305 +++++ .../apiculture/gadgets/TileApiaristChest.java | 21 + .../apiculture/gadgets/TileApiary.java | 352 +++++ .../apiculture/gadgets/TileBeehouse.java | 438 ++++++ .../apiculture/gadgets/TileCandle.java | 82 ++ .../apiculture/gadgets/TileSwarm.java | 52 + .../apiculture/genetics/AIAvoidPlayers.java | 87 ++ .../apiculture/genetics/AlleleBeeSpecies.java | 233 ++++ .../genetics/AlleleEffectAggressive.java | 67 + .../genetics/AlleleEffectCreeper.java | 111 ++ .../genetics/AlleleEffectExploration.java | 43 + .../genetics/AlleleEffectGlacial.java | 70 + .../genetics/AlleleEffectHeroic.java | 44 + .../genetics/AlleleEffectIgnition.java | 92 ++ .../genetics/AlleleEffectMiasmic.java | 86 ++ .../genetics/AlleleEffectMisanthrope.java | 64 + .../apiculture/genetics/AlleleEffectNone.java | 69 + .../genetics/AlleleEffectPotion.java | 50 + .../genetics/AlleleEffectRadioactive.java | 122 ++ .../genetics/AlleleEffectRepulsion.java | 55 + .../genetics/AlleleEffectResurrection.java | 108 ++ .../genetics/AlleleEffectSnowing.java | 79 ++ .../genetics/AlleleEffectThrottled.java | 114 ++ .../apiculture/genetics/AlleleFlowers.java | 37 + .../apiculture/genetics/ApiaristTracker.java | 110 ++ .../forestry/apiculture/genetics/Bee.java | 713 ++++++++++ .../apiculture/genetics/BeeGenome.java | 145 ++ .../apiculture/genetics/BeeHelper.java | 331 +++++ .../apiculture/genetics/BeeMutation.java | 126 ++ .../apiculture/genetics/BeeTemplates.java | 595 ++++++++ .../apiculture/genetics/BeekeepingMode.java | 174 +++ .../apiculture/genetics/BranchBees.java | 18 + .../apiculture/genetics/HiveDrop.java | 75 + .../genetics/IJubilanceProvider.java | 16 + .../apiculture/genetics/JubilanceDefault.java | 44 + .../apiculture/genetics/JubilanceNone.java | 21 + .../genetics/JubilanceProviderHermit.java | 36 + .../apiculture/genetics/JubilanceReqRes.java | 40 + .../apiculture/genetics/MutationEMC.java | 93 ++ .../apiculture/genetics/MutationReqRes.java | 47 + .../genetics/MutationTimeLimited.java | 137 ++ .../apiculture/gui/ContainerAlveary.java | 66 + .../gui/ContainerAlvearyHygroregulator.java | 50 + .../apiculture/gui/ContainerAlvearySieve.java | 54 + .../gui/ContainerAlvearySwarmer.java | 41 + .../apiculture/gui/ContainerApiary.java | 86 ++ .../apiculture/gui/ContainerBeealyzer.java | 80 ++ .../gui/ContainerHabitatLocator.java | 74 + .../apiculture/gui/ContainerImprinter.java | 121 ++ .../forestry/apiculture/gui/GuiAlveary.java | 65 + .../gui/GuiAlvearyHygroregulator.java | 33 + .../apiculture/gui/GuiAlvearySieve.java | 23 + .../apiculture/gui/GuiAlvearySwarmer.java | 22 + .../forestry/apiculture/gui/GuiApiary.java | 72 + .../forestry/apiculture/gui/GuiBeealyzer.java | 321 +++++ .../apiculture/gui/GuiHabitatLocator.java | 189 +++ .../forestry/apiculture/gui/GuiImprinter.java | 127 ++ .../apiculture/items/ItemAlvearyBlock.java | 24 + .../apiculture/items/ItemArmorApiarist.java | 125 ++ .../forestry/apiculture/items/ItemBeeGE.java | 168 +++ .../apiculture/items/ItemBeealyzer.java | 164 +++ .../apiculture/items/ItemBiomefinder.java | 237 ++++ .../apiculture/items/ItemCandleBlock.java | 73 + .../apiculture/items/ItemHiveFrame.java | 95 ++ .../apiculture/items/ItemHoneycomb.java | 158 +++ .../apiculture/items/ItemImprinter.java | 226 +++ .../apiculture/items/ItemWaxCast.java | 33 + .../proxy/ClientProxyApiculture.java | 96 ++ .../apiculture/proxy/ProxyApiculture.java | 31 + .../apiculture/render/BeeItemRenderer.java | 223 +++ .../render/BlockCandleRenderer.java | 151 ++ .../apiculture/render/EntityBeeFX.java | 84 ++ .../apiculture/render/ModelAnalyzer.java | 112 ++ .../forestry/apiculture/render/ModelBee.java | 163 +++ .../apiculture/render/ParticleRenderer.java | 159 +++ .../forestry/apiculture/render/RenderBee.java | 39 + .../apiculture/render/TextureBiomefinder.java | 91 ++ .../apiculture/trigger/TriggerNoFrames.java | 44 + .../worldgen/ComponentVillageBeeHouse.java | 378 +++++ .../apiculture/worldgen/HiveDecorator.java | 74 + .../apiculture/worldgen/WorldGenHive.java | 88 ++ .../apiculture/worldgen/WorldGenHiveEnd.java | 27 + .../worldgen/WorldGenHiveForest.java | 31 + .../worldgen/WorldGenHiveJungle.java | 30 + .../worldgen/WorldGenHiveMeadows.java | 31 + .../worldgen/WorldGenHiveParched.java | 31 + .../apiculture/worldgen/WorldGenHiveSnow.java | 35 + .../worldgen/WorldGenHiveSwamer.java | 46 + .../worldgen/WorldGenHiveSwamp.java | 31 + .../forestry/plugins/PluginApiculture.java | 1218 +++++++++++++++++ .../apiculture/forestry/plugins/PluginEE.java | 92 ++ .../arboriculture/CommandSpawnForest.java | 44 + .../arboriculture/CommandSpawnTree.java | 47 + .../arboriculture/CommandTreekeepingMode.java | 241 ++++ .../EventHandlerArboriculture.java | 49 + .../arboriculture/FruitProviderNone.java | 127 ++ .../arboriculture/FruitProviderPod.java | 103 ++ .../arboriculture/FruitProviderRandom.java | 73 + .../arboriculture/FruitProviderRipening.java | 104 ++ .../GuiHandlerArboriculture.java | 74 + .../forestry/arboriculture/IWoodTyped.java | 14 + .../PacketHandlerArboriculture.java | 50 + .../VillageHandlerArboriculture.java | 55 + .../forestry/arboriculture/WoodType.java | 90 ++ .../arboriculture/WorldGenHelper.java | 34 + .../arboriculture/gadgets/BlockArbFence.java | 136 ++ .../arboriculture/gadgets/BlockArbStairs.java | 130 ++ .../arboriculture/gadgets/BlockFruitPod.java | 136 ++ .../arboriculture/gadgets/BlockLeaves.java | 334 +++++ .../arboriculture/gadgets/BlockLog.java | 203 +++ .../arboriculture/gadgets/BlockPlanks.java | 111 ++ .../arboriculture/gadgets/BlockSapling.java | 165 +++ .../arboriculture/gadgets/BlockSlab.java | 138 ++ .../gadgets/BlockTreeContainer.java | 42 + .../gadgets/TileArboristChest.java | 21 + .../arboriculture/gadgets/TileFruitPod.java | 194 +++ .../arboriculture/gadgets/TileLeaves.java | 425 ++++++ .../arboriculture/gadgets/TileSapling.java | 67 + .../arboriculture/gadgets/TileStairs.java | 78 ++ .../gadgets/TileTreeContainer.java | 160 +++ .../arboriculture/genetics/AlleleFruit.java | 37 + .../arboriculture/genetics/AlleleGrowth.java | 32 + .../genetics/AlleleLeafEffectNone.java | 58 + .../genetics/AlleleTreeSpecies.java | 289 ++++ .../genetics/ArboristTracker.java | 42 + .../arboriculture/genetics/BranchTrees.java | 18 + .../genetics/GrowthProvider.java | 133 ++ .../genetics/GrowthProviderTropical.java | 44 + .../forestry/arboriculture/genetics/Tree.java | 394 ++++++ .../arboriculture/genetics/TreeGenome.java | 143 ++ .../arboriculture/genetics/TreeHelper.java | 391 ++++++ .../arboriculture/genetics/TreeMutation.java | 58 + .../arboriculture/genetics/TreeTemplates.java | 385 ++++++ .../genetics/TreekeepingMode.java | 77 ++ .../gui/ContainerTreealyzer.java | 83 ++ .../arboriculture/gui/GuiTreealyzer.java | 343 +++++ .../arboriculture/items/ItemGermlingGE.java | 185 +++ .../arboriculture/items/ItemGrafter.java | 67 + .../arboriculture/items/ItemStairs.java | 73 + .../arboriculture/items/ItemTreealyzer.java | 169 +++ .../arboriculture/items/ItemWoodBlock.java | 42 + .../network/PacketLeafUpdate.java | 100 ++ .../proxy/ClientProxyArboriculture.java | 62 + .../proxy/ProxyArboriculture.java | 36 + .../render/FenceRenderingHandler.java | 97 ++ .../render/FruitPodRenderingHandler.java | 191 +++ .../render/LeavesRenderingHandler.java | 96 ++ .../render/SaplingRenderHandler.java | 117 ++ .../render/StairItemRenderer.java | 104 ++ .../arboriculture/worldgen/BlockTypeLeaf.java | 28 + .../arboriculture/worldgen/BlockTypeVoid.java | 29 + .../worldgen/WorldGenAcacia.java | 54 + .../worldgen/WorldGenArboriculture.java | 169 +++ .../arboriculture/worldgen/WorldGenBalsa.java | 52 + .../worldgen/WorldGenBaobab.java | 70 + .../arboriculture/worldgen/WorldGenBirch.java | 26 + .../worldgen/WorldGenCherry.java | 46 + .../worldgen/WorldGenChestnut.java | 50 + .../arboriculture/worldgen/WorldGenDate.java | 43 + .../arboriculture/worldgen/WorldGenEbony.java | 67 + .../worldgen/WorldGenGiganteum.java | 37 + .../worldgen/WorldGenGreenheart.java | 61 + .../worldgen/WorldGenJungle.java | 44 + .../arboriculture/worldgen/WorldGenKapok.java | 60 + .../arboriculture/worldgen/WorldGenLarch.java | 47 + .../arboriculture/worldgen/WorldGenLemon.java | 41 + .../arboriculture/worldgen/WorldGenLime.java | 44 + .../arboriculture/worldgen/WorldGenMahoe.java | 41 + .../worldgen/WorldGenMahogany.java | 49 + .../arboriculture/worldgen/WorldGenMaple.java | 50 + .../arboriculture/worldgen/WorldGenOak.java | 26 + .../worldgen/WorldGenPapaya.java | 41 + .../arboriculture/worldgen/WorldGenPine.java | 50 + .../arboriculture/worldgen/WorldGenPlum.java | 41 + .../worldgen/WorldGenPoplar.java | 42 + .../worldgen/WorldGenSequoia.java | 61 + .../worldgen/WorldGenSpruce.java | 48 + .../arboriculture/worldgen/WorldGenTeak.java | 49 + .../arboriculture/worldgen/WorldGenTree.java | 93 ++ .../worldgen/WorldGenWalnut.java | 52 + .../arboriculture/worldgen/WorldGenWenge.java | 49 + .../worldgen/WorldGenWillow.java | 53 + .../forestry/plugins/PluginArboriculture.java | 1130 +++++++++++++++ forestry_common/core/forestry/Forestry.java | 96 ++ .../forestry/api/apiculture/BeeManager.java | 48 + .../api/apiculture/EnumBeeChromosome.java | 105 ++ .../forestry/api/apiculture/EnumBeeType.java | 26 + .../api/apiculture/FlowerManager.java | 21 + .../api/apiculture/IAlleleBeeEffect.java | 38 + .../api/apiculture/IAlleleBeeSpecies.java | 55 + .../api/apiculture/IAlvearyComponent.java | 34 + .../api/apiculture/IApiaristTracker.java | 59 + .../api/apiculture/IArmorApiarist.java | 31 + .../core/forestry/api/apiculture/IBee.java | 93 ++ .../forestry/api/apiculture/IBeeGenome.java | 50 + .../forestry/api/apiculture/IBeeHousing.java | 29 + .../forestry/api/apiculture/IBeeListener.java | 48 + .../forestry/api/apiculture/IBeeModifier.java | 73 + .../forestry/api/apiculture/IBeeMutation.java | 27 + .../forestry/api/apiculture/IBeeRoot.java | 119 ++ .../api/apiculture/IBeekeepingLogic.java | 29 + .../api/apiculture/IBeekeepingMode.java | 72 + .../forestry/api/apiculture/IHiveDrop.java | 40 + .../forestry/api/apiculture/IHiveFrame.java | 29 + .../forestry/api/apiculture/package-info.java | 10 + .../api/arboriculture/EnumGermlingType.java | 25 + .../arboriculture/EnumGrowthConditions.java | 12 + .../api/arboriculture/EnumTreeChromosome.java | 94 ++ .../api/arboriculture/IAlleleFruit.java | 19 + .../api/arboriculture/IAlleleGrowth.java | 19 + .../api/arboriculture/IAlleleLeafEffect.java | 22 + .../api/arboriculture/IAlleleTreeSpecies.java | 77 ++ .../api/arboriculture/IArboristTracker.java | 14 + .../api/arboriculture/IFruitProvider.java | 76 + .../api/arboriculture/IGrowthProvider.java | 40 + .../api/arboriculture/ILeafTickHandler.java | 14 + .../api/arboriculture/IToolGrafter.java | 26 + .../forestry/api/arboriculture/ITree.java | 101 ++ .../api/arboriculture/ITreeGenome.java | 48 + .../api/arboriculture/ITreeModifier.java | 47 + .../api/arboriculture/ITreeMutation.java | 36 + .../forestry/api/arboriculture/ITreeRoot.java | 85 ++ .../api/arboriculture/ITreekeepingMode.java | 24 + .../api/arboriculture/TreeManager.java | 18 + .../api/arboriculture/package-info.java | 10 + .../forestry/api/circuits/ChipsetManager.java | 15 + .../core/forestry/api/circuits/ICircuit.java | 34 + .../forestry/api/circuits/ICircuitBoard.java | 34 + .../forestry/api/circuits/ICircuitLayout.java | 18 + .../api/circuits/ICircuitLibrary.java | 12 + .../api/circuits/ICircuitRegistry.java | 44 + .../forestry/api/circuits/ISolderManager.java | 16 + .../forestry/api/circuits/package-info.java | 10 + .../forestry/api/core/BlockInterface.java | 42 + .../core/forestry/api/core/EnumHumidity.java | 79 ++ .../forestry/api/core/EnumTemperature.java | 152 ++ .../core/forestry/api/core/ForestryAPI.java | 54 + .../core/forestry/api/core/ForestryEvent.java | 60 + .../forestry/api/core/IArmorNaturalist.java | 27 + .../forestry/api/core/IForestryConstants.java | 26 + .../core/forestry/api/core/IGameMode.java | 43 + .../core/forestry/api/core/IIconProvider.java | 27 + .../core/forestry/api/core/INBTTagable.java | 16 + .../core/forestry/api/core/IPlugin.java | 39 + .../forestry/api/core/IStructureLogic.java | 22 + .../forestry/api/core/ITextureManager.java | 23 + .../forestry/api/core/ITileStructure.java | 65 + .../core/forestry/api/core/IToolScoop.java | 15 + .../core/forestry/api/core/ItemInterface.java | 51 + .../core/forestry/api/core/PluginInfo.java | 56 + .../core/forestry/api/core/Tabs.java | 21 + .../core/forestry/api/core/package-info.java | 10 + .../core/forestry/api/farming/Farmables.java | 22 + .../core/forestry/api/farming/ICrop.java | 23 + .../forestry/api/farming/IFarmComponent.java | 19 + .../forestry/api/farming/IFarmHousing.java | 76 + .../forestry/api/farming/IFarmInterface.java | 22 + .../forestry/api/farming/IFarmListener.java | 79 ++ .../core/forestry/api/farming/IFarmLogic.java | 43 + .../core/forestry/api/farming/IFarmable.java | 61 + .../forestry/api/farming/package-info.java | 10 + .../forestry/api/food/BeverageManager.java | 15 + .../forestry/api/food/IBeverageEffect.java | 19 + .../forestry/api/food/IInfuserManager.java | 24 + .../forestry/api/food/IIngredientManager.java | 18 + .../core/forestry/api/food/package-info.java | 10 + .../forestry/api/fuels/EngineBronzeFuel.java | 36 + .../forestry/api/fuels/EngineCopperFuel.java | 33 + .../forestry/api/fuels/FermenterFuel.java | 31 + .../core/forestry/api/fuels/FuelManager.java | 36 + .../forestry/api/fuels/GeneratorFuel.java | 37 + .../forestry/api/fuels/MoistenerFuel.java | 36 + .../forestry/api/fuels/RainSubstrate.java | 42 + .../core/forestry/api/fuels/package-info.java | 10 + .../forestry/api/genetics/AlleleManager.java | 31 + .../forestry/api/genetics/EnumTolerance.java | 18 + .../core/forestry/api/genetics/IAllele.java | 36 + .../forestry/api/genetics/IAlleleArea.java | 17 + .../forestry/api/genetics/IAlleleBoolean.java | 18 + .../forestry/api/genetics/IAlleleEffect.java | 28 + .../forestry/api/genetics/IAlleleFloat.java | 17 + .../forestry/api/genetics/IAlleleFlowers.java | 18 + .../forestry/api/genetics/IAlleleHandler.java | 43 + .../forestry/api/genetics/IAlleleInteger.java | 17 + .../api/genetics/IAllelePlantType.java | 18 + .../api/genetics/IAlleleRegistry.java | 229 ++++ .../forestry/api/genetics/IAlleleSpecies.java | 115 ++ .../api/genetics/IAlleleTolerance.java | 17 + .../api/genetics/IBreedingTracker.java | 101 ++ .../forestry/api/genetics/IChromosome.java | 27 + .../api/genetics/IChromosomeType.java | 26 + .../api/genetics/IClassification.java | 109 ++ .../forestry/api/genetics/IEffectData.java | 29 + .../api/genetics/IFlowerProvider.java | 58 + .../forestry/api/genetics/IFruitBearer.java | 52 + .../forestry/api/genetics/IFruitFamily.java | 34 + .../core/forestry/api/genetics/IGenome.java | 32 + .../core/forestry/api/genetics/IHousing.java | 54 + .../forestry/api/genetics/IIndividual.java | 59 + .../api/genetics/IIndividualLiving.java | 47 + .../forestry/api/genetics/ILegacyHandler.java | 17 + .../core/forestry/api/genetics/IMutation.java | 70 + .../forestry/api/genetics/IPollinatable.java | 50 + .../forestry/api/genetics/ISpeciesRoot.java | 167 +++ .../forestry/api/genetics/package-info.java | 10 + .../EnumButterflyChromosome.java | 100 ++ .../api/lepidopterology/EnumFlutterType.java | 17 + .../IAlleleButterflyEffect.java | 23 + .../IAlleleButterflySpecies.java | 61 + .../api/lepidopterology/IButterfly.java | 79 ++ .../api/lepidopterology/IButterflyGenome.java | 44 + .../lepidopterology/IButterflyMutation.java | 16 + .../lepidopterology/IButterflyNursery.java | 23 + .../api/lepidopterology/IButterflyRoot.java | 62 + .../api/lepidopterology/IEntityButterfly.java | 31 + .../ILepidopteristTracker.java | 16 + .../api/lepidopterology/package-info.java | 10 + .../core/forestry/api/mail/EnumPostage.java | 22 + .../core/forestry/api/mail/ILetter.java | 62 + .../forestry/api/mail/ILetterHandler.java | 15 + .../core/forestry/api/mail/IPostOffice.java | 32 + .../core/forestry/api/mail/IPostRegistry.java | 54 + .../forestry/api/mail/IPostalCarrier.java | 50 + .../core/forestry/api/mail/IPostalState.java | 16 + .../core/forestry/api/mail/IStamps.java | 16 + .../core/forestry/api/mail/ITradeStation.java | 26 + .../core/forestry/api/mail/MailAddress.java | 62 + .../core/forestry/api/mail/PostManager.java | 13 + .../forestry/api/mail/TradeStationInfo.java | 26 + .../core/forestry/api/mail/package-info.java | 10 + .../core/forestry/api/package-info.java | 10 + .../forestry/api/recipes/IBottlerManager.java | 42 + .../api/recipes/ICarpenterManager.java | 73 + .../api/recipes/ICentrifugeManager.java | 81 ++ .../api/recipes/ICraftingProvider.java | 19 + .../api/recipes/IFabricatorManager.java | 20 + .../api/recipes/IFermenterManager.java | 55 + .../forestry/api/recipes/IGenericCrate.java | 18 + .../api/recipes/IMoistenerManager.java | 35 + .../api/recipes/ISqueezerManager.java | 53 + .../forestry/api/recipes/IStillManager.java | 36 + .../api/recipes/IVariableFermentable.java | 23 + .../forestry/api/recipes/RecipeManagers.java | 51 + .../forestry/api/recipes/package-info.java | 10 + .../forestry/api/storage/BackpackEvent.java | 27 + .../forestry/api/storage/BackpackManager.java | 29 + .../api/storage/BackpackResupplyEvent.java | 26 + .../api/storage/BackpackStowEvent.java | 29 + .../api/storage/EnumBackpackType.java | 12 + .../api/storage/IBackpackDefinition.java | 61 + .../api/storage/IBackpackInterface.java | 24 + .../forestry/api/storage/package-info.java | 10 + .../core/forestry/api/world/ITreeGenData.java | 25 + .../api/world/IWorldGenInterface.java | 24 + .../forestry/api/world/WorldGenManager.java | 12 + .../core/forestry/api/world/package-info.java | 10 + .../core/forestry/core/CommandForestry.java | 166 +++ .../forestry/core/CreativeTabForestry.java | 58 + .../core/forestry/core/EnumErrorCode.java | 119 ++ .../core/forestry/core/EventHandlerCore.java | 97 ++ .../core/forestry/core/ForestryClient.java | 41 + .../core/forestry/core/ForestryConstants.java | 30 + .../core/forestry/core/ForestryCore.java | 251 ++++ .../core/forestry/core/GameMode.java | 204 +++ .../core/forestry/core/GuiHandler.java | 87 ++ .../core/forestry/core/GuiHandlerBase.java | 64 + .../core/forestry/core/PickupHandlerCore.java | 33 + .../forestry/core/SaveEventHandlerCore.java | 28 + .../core/forestry/core/TemperatureState.java | 26 + .../forestry/core/TickHandlerCoreClient.java | 76 + .../forestry/core/TickHandlerCoreServer.java | 36 + .../core/forestry/core/WorldGenerator.java | 78 ++ .../core/forestry/core/circuits/Circuit.java | 92 ++ .../forestry/core/circuits/CircuitBoard.java | 169 +++ .../core/circuits/CircuitBoardManager.java | 11 + .../forestry/core/circuits/CircuitId.java | 16 + .../forestry/core/circuits/CircuitLayout.java | 35 + .../core/circuits/CircuitLibrary.java | 29 + .../core/circuits/CircuitRegistry.java | 117 ++ .../core/circuits/ContainerSolderingIron.java | 121 ++ .../core/circuits/EnumCircuitBoardType.java | 23 + .../core/circuits/GuiSolderingIron.java | 77 ++ .../core/circuits/ISolderingIron.java | 12 + .../core/circuits/ItemCircuitBoard.java | 123 ++ .../core/circuits/ItemSolderingIron.java | 262 ++++ .../core/forestry/core/config/Config.java | 373 +++++ .../forestry/core/config/Configuration.java | 286 ++++ .../core/forestry/core/config/Defaults.java | 259 ++++ .../forestry/core/config/ForestryBlock.java | 81 ++ .../forestry/core/config/ForestryItem.java | 275 ++++ .../core/forestry/core/config/Property.java | 19 + .../forestry/core/config/SessionVars.java | 40 + .../core/forestry/core/config/Version.java | 208 +++ .../core/forestry/core/gadgets/BlockBase.java | 253 ++++ .../forestry/core/gadgets/BlockForestry.java | 72 + .../forestry/core/gadgets/BlockResource.java | 105 ++ .../core/forestry/core/gadgets/BlockSoil.java | 260 ++++ .../core/gadgets/BlockStainedGlass.java | 93 ++ .../forestry/core/gadgets/BlockStructure.java | 90 ++ .../core/forestry/core/gadgets/Engine.java | 432 ++++++ .../core/gadgets/IStructureBlockItem.java | 16 + .../core/gadgets/MachineDefinition.java | 204 +++ .../core/gadgets/MachineNBTDefinition.java | 56 + .../core/forestry/core/gadgets/Mill.java | 81 ++ .../forestry/core/gadgets/NaturalistGame.java | 411 ++++++ .../forestry/core/gadgets/StructureLogic.java | 181 +++ .../forestry/core/gadgets/TileAnalyzer.java | 453 ++++++ .../core/forestry/core/gadgets/TileBase.java | 118 ++ .../forestry/core/gadgets/TileEngine.java | 11 + .../forestry/core/gadgets/TileEscritoire.java | 246 ++++ .../forestry/core/gadgets/TileForestry.java | 371 +++++ .../forestry/core/gadgets/TileMachine.java | 388 ++++++ .../core/forestry/core/gadgets/TileMill.java | 11 + .../core/gadgets/TileNaturalistChest.java | 172 +++ .../forestry/core/gadgets/TilePowered.java | 210 +++ .../core/forestry/core/genetics/Allele.java | 693 ++++++++++ .../forestry/core/genetics/AlleleArea.java | 34 + .../forestry/core/genetics/AlleleBoolean.java | 30 + .../forestry/core/genetics/AlleleFloat.java | 30 + .../forestry/core/genetics/AlleleInteger.java | 30 + .../core/genetics/AllelePlantType.java | 36 + .../core/genetics/AlleleRegistry.java | 296 ++++ .../forestry/core/genetics/AlleleSpecies.java | 187 +++ .../core/genetics/AlleleTolerance.java | 70 + .../core/forestry/core/genetics/Branch.java | 16 + .../core/genetics/BreedingTracker.java | 178 +++ .../forestry/core/genetics/Chromosome.java | 137 ++ .../core/genetics/Classification.java | 92 ++ .../forestry/core/genetics/ClimateHelper.java | 159 +++ .../forestry/core/genetics/EffectData.java | 66 + .../core/genetics/EnumMutateChance.java | 35 + .../forestry/core/genetics/FruitFamily.java | 45 + .../core/genetics/GenericRatings.java | 38 + .../core/forestry/core/genetics/Genome.java | 112 ++ .../forestry/core/genetics/Individual.java | 78 ++ .../core/genetics/IndividualLiving.java | 135 ++ .../core/forestry/core/genetics/ItemGE.java | 103 ++ .../core/genetics/ItemResearchNote.java | 264 ++++ .../core/forestry/core/genetics/Mutation.java | 129 ++ .../forestry/core/genetics/SpeciesRoot.java | 105 ++ .../core/forestry/core/gui/ClimateLedger.java | 60 + .../forestry/core/gui/ContainerAnalyzer.java | 67 + .../forestry/core/gui/ContainerDummy.java | 20 + .../core/gui/ContainerEscritoire.java | 104 ++ .../forestry/core/gui/ContainerForestry.java | 211 +++ .../core/gui/ContainerItemInventory.java | 71 + .../core/gui/ContainerLiquidTanks.java | 123 ++ .../gui/ContainerNaturalistInventory.java | 71 + .../forestry/core/gui/ContainerSocketed.java | 85 ++ .../core/forestry/core/gui/ErrorLedger.java | 64 + .../core/forestry/core/gui/GuiAlyzer.java | 376 +++++ .../core/forestry/core/gui/GuiAnalyzer.java | 64 + .../core/forestry/core/gui/GuiEscritoire.java | 254 ++++ .../core/forestry/core/gui/GuiForestry.java | 545 ++++++++ .../core/gui/GuiNaturalistInventory.java | 255 ++++ .../core/forestry/core/gui/GuiTextBox.java | 107 ++ .../core/forestry/core/gui/HintLedger.java | 53 + .../forestry/core/gui/IGuiSelectable.java | 18 + .../forestry/core/gui/IPagedInventory.java | 20 + .../core/forestry/core/gui/Ledger.java | 146 ++ .../core/forestry/core/gui/LedgerManager.java | 117 ++ .../core/forestry/core/gui/OwnerLedger.java | 115 ++ .../core/forestry/core/gui/PlainLedger.java | 48 + .../core/forestry/core/gui/PowerLedger.java | 57 + .../core/forestry/core/gui/WidgetManager.java | 81 ++ .../core/gui/buttons/ButtonTextureSet.java | 45 + .../core/gui/buttons/GuiBetterButton.java | 140 ++ .../core/gui/buttons/GuiButtonSmall.java | 24 + .../core/gui/buttons/GuiMultiButton.java | 98 ++ .../core/gui/buttons/GuiToggleButton.java | 58 + .../gui/buttons/GuiToggleButtonSmall.java | 25 + .../core/gui/buttons/IButtonTextureSet.java | 24 + .../core/gui/buttons/IMultiButtonState.java | 27 + .../core/gui/buttons/LockButtonState.java | 42 + .../gui/buttons/MultiButtonController.java | 98 ++ .../buttons/StandardButtonTextureSets.java | 53 + .../forestry/core/gui/slots/SlotClosed.java | 24 + .../core/gui/slots/SlotCraftAuto.java | 35 + .../forestry/core/gui/slots/SlotCrafter.java | 58 + .../forestry/core/gui/slots/SlotCustom.java | 149 ++ .../forestry/core/gui/slots/SlotForestry.java | 132 ++ .../core/gui/slots/SlotItemInventory.java | 34 + .../core/gui/slots/SlotLiquidContainer.java | 57 + .../forestry/core/gui/slots/SlotLocked.java | 40 + .../forestry/core/gui/slots/SlotOutput.java | 27 + .../forestry/core/gui/slots/SlotWorking.java | 39 + .../core/gui/tooltips/IToolTipProvider.java | 21 + .../forestry/core/gui/tooltips/ToolTip.java | 90 ++ .../core/gui/tooltips/ToolTipLine.java | 43 + .../core/gui/widgets/ReservoirWidget.java | 64 + .../core/gui/widgets/SocketWidget.java | 80 ++ .../forestry/core/gui/widgets/TankWidget.java | 113 ++ .../forestry/core/gui/widgets/Widget.java | 78 ++ .../core/interfaces/IBlockRenderer.java | 16 + .../forestry/core/interfaces/IClimatised.java | 23 + .../core/interfaces/IContainerCrafting.java | 14 + .../forestry/core/interfaces/ICrafter.java | 21 + .../core/interfaces/ICraftingPlan.java | 14 + .../core/interfaces/IDescriptiveRecipe.java | 19 + .../core/interfaces/IErrorSource.java | 18 + .../forestry/core/interfaces/IHintSource.java | 14 + .../core/interfaces/IInventoriedItem.java | 12 + .../core/interfaces/ILiquidTankContainer.java | 18 + .../interfaces/IOreDictionaryHandler.java | 14 + .../forestry/core/interfaces/IOwnable.java | 33 + .../core/interfaces/IPacketHandler.java | 18 + .../core/interfaces/IPickupHandler.java | 17 + .../core/interfaces/IPowerHandler.java | 15 + .../core/interfaces/IRenderableMachine.java | 22 + .../core/interfaces/IResupplyHandler.java | 16 + .../core/interfaces/ISaveEventHandler.java | 20 + .../forestry/core/interfaces/ISocketable.java | 18 + .../forestry/core/inventory/ITileFilter.java | 20 + .../forestry/core/inventory/InvTools.java | 796 +++++++++++ .../core/inventory/InventoryConcatenator.java | 103 ++ .../core/inventory/InventorySorter.java | 27 + .../forestry/core/inventory/ItemStackMap.java | 219 +++ .../forestry/core/inventory/ItemStackSet.java | 151 ++ .../core/inventory/ItemStackSizeSorter.java | 36 + .../inventory/filters/ArrayStackFilter.java | 46 + .../core/inventory/filters/IStackFilter.java | 22 + .../filters/InvertedStackFilter.java | 31 + .../core/inventory/filters/StackFilter.java | 46 + .../manipulators/InventoryManipulator.java | 194 +++ .../manipulators/SpecialManipulator.java | 99 ++ .../core/inventory/wrappers/ChestWrapper.java | 190 +++ .../core/inventory/wrappers/IInvSlot.java | 30 + .../inventory/wrappers/InventoryCopy.java | 118 ++ .../inventory/wrappers/InventoryIterator.java | 97 ++ .../inventory/wrappers/InventoryMapper.java | 145 ++ .../wrappers/SidedInventoryIterator.java | 89 ++ .../wrappers/SidedInventoryMapper.java | 123 ++ .../wrappers/SpecialInventoryMapper.java | 44 + .../core/items/ItemArmorNaturalist.java | 75 + .../forestry/core/items/ItemAssemblyKit.java | 59 + .../core/forestry/core/items/ItemCrated.java | 95 ++ .../forestry/core/items/ItemForestry.java | 63 + .../core/items/ItemForestryBlock.java | 44 + .../forestry/core/items/ItemForestryFood.java | 109 ++ .../core/items/ItemForestryPickaxe.java | 31 + .../core/items/ItemForestryShovel.java | 29 + .../forestry/core/items/ItemForestryTool.java | 81 ++ .../core/forestry/core/items/ItemFruit.java | 100 ++ .../forestry/core/items/ItemInventoried.java | 32 + .../core/items/ItemLiquidContainer.java | 236 ++++ .../core/forestry/core/items/ItemLiquids.java | 35 + .../core/forestry/core/items/ItemMisc.java | 81 ++ .../core/forestry/core/items/ItemNBTTile.java | 30 + .../core/forestry/core/items/ItemOverlay.java | 129 ++ .../core/forestry/core/items/ItemPipette.java | 195 +++ .../core/forestry/core/items/ItemScoop.java | 62 + .../core/forestry/core/items/ItemWrench.java | 44 + .../core/forestry/core/network/ClassMap.java | 198 +++ .../forestry/core/network/EntityNetData.java | 20 + .../forestry/core/network/ForestryPacket.java | 120 ++ .../core/forestry/core/network/GuiId.java | 116 ++ .../forestry/core/network/ILocatedPacket.java | 15 + .../core/network/INetworkedEntity.java | 16 + .../forestry/core/network/IndexInPayload.java | 23 + .../core/network/PacketCoordinates.java | 65 + .../forestry/core/network/PacketFXSignal.java | 103 ++ .../forestry/core/network/PacketHandler.java | 297 ++++ .../core/forestry/core/network/PacketIds.java | 59 + .../core/network/PacketInventoryStack.java | 44 + .../core/forestry/core/network/PacketNBT.java | 51 + .../forestry/core/network/PacketPayload.java | 66 + .../core/network/PacketSocketUpdate.java | 51 + .../core/network/PacketTankUpdate.java | 28 + .../forestry/core/network/PacketTileNBT.java | 63 + .../core/network/PacketTileUpdate.java | 103 ++ .../forestry/core/network/PacketUpdate.java | 102 ++ .../core/proxy/ClientProxyCommon.java | 214 +++ .../core/proxy/ClientProxyNetwork.java | 18 + .../core/proxy/ClientProxyRender.java | 117 ++ .../core/forestry/core/proxy/Proxies.java | 21 + .../core/forestry/core/proxy/ProxyCommon.java | 259 ++++ .../core/forestry/core/proxy/ProxyLog.java | 119 ++ .../forestry/core/proxy/ProxyNetwork.java | 52 + .../core/forestry/core/proxy/ProxyRender.java | 62 + .../core/render/BlockRenderingHandler.java | 51 + .../forestry/core/render/EntityBiodustFX.java | 33 + .../core/render/EntityHoneydustFX.java | 33 + .../forestry/core/render/EntitySnowFX.java | 77 ++ .../forestry/core/render/ModelEscritoire.java | 193 +++ .../core/render/OverlayRenderingHandler.java | 110 ++ .../forestry/core/render/RenderAnalyzer.java | 89 ++ .../core/render/RenderEscritoire.java | 114 ++ .../forestry/core/render/RenderMachine.java | 228 +++ .../core/forestry/core/render/RenderMill.java | 198 +++ .../forestry/core/render/SpriteSheet.java | 24 + .../forestry/core/render/TextureManager.java | 103 ++ .../core/render/TileRendererIndex.java | 33 + .../core/triggers/ForestryTrigger.java | 43 + .../core/forestry/core/triggers/Trigger.java | 76 + .../core/triggers/TriggerHasWork.java | 36 + .../core/triggers/TriggerLowFuel.java | 50 + .../core/triggers/TriggerLowGermlings.java | 43 + .../core/triggers/TriggerLowResource.java | 43 + .../core/triggers/TriggerLowSoil.java | 43 + .../core/triggers/TriggerMissingDrone.java | 38 + .../core/triggers/TriggerMissingQueen.java | 36 + .../core/forestry/core/utils/BlockUtil.java | 189 +++ .../core/forestry/core/utils/CommandMC.java | 60 + .../core/utils/DamageSourceForestry.java | 35 + .../core/forestry/core/utils/DelayTimer.java | 27 + .../core/forestry/core/utils/EnumAccess.java | 31 + .../forestry/core/utils/EnumTankLevel.java | 21 + .../core/forestry/core/utils/FluidMap.java | 43 + .../forestry/core/utils/FluidStackMap.java | 44 + .../core/forestry/core/utils/Fluids.java | 55 + .../core/forestry/core/utils/FontColour.java | 47 + .../utils/ForestryModEnvWarningCallable.java | 66 + .../forestry/core/utils/ForestryResource.java | 20 + .../forestry/core/utils/ForestryTank.java | 83 ++ .../core/forestry/core/utils/IDAllocator.java | 88 ++ .../forestry/core/utils/InventoryAdapter.java | 391 ++++++ .../forestry/core/utils/ItemInventory.java | 221 +++ .../forestry/core/utils/ItemStackMap.java | 48 + .../forestry/core/utils/LiquidHelper.java | 266 ++++ .../forestry/core/utils/Localization.java | 102 ++ .../forestry/core/utils/PlainInventory.java | 111 ++ .../core/forestry/core/utils/RecipeUtil.java | 70 + .../core/forestry/core/utils/Schemata.java | 139 ++ .../core/utils/ShapedRecipeCustom.java | 251 ++++ .../core/forestry/core/utils/StackMap.java | 74 + .../core/forestry/core/utils/StackUtils.java | 431 ++++++ .../core/forestry/core/utils/StringUtil.java | 46 + .../core/utils/TileInventoryAdapter.java | 38 + .../core/forestry/core/utils/Utils.java | 410 ++++++ .../core/forestry/core/utils/Vect.java | 81 ++ .../forestry/core/worldgen/BlockType.java | 31 + .../forestry/core/worldgen/WorldGenBase.java | 117 ++ .../core/worldgen/WorldGenMinableMeta.java | 83 ++ .../core/forestry/plugins/NativePlugin.java | 86 ++ .../forestry/plugins/PluginBuildCraft.java | 159 +++ .../core/forestry/plugins/PluginCore.java | 608 ++++++++ .../core/forestry/plugins/PluginIC2.java | 194 +++ .../core/forestry/plugins/PluginManager.java | 256 ++++ .../forestry/energy/GuiHandlerEnergy.java | 86 ++ .../energy/circuits/CircuitElectricBoost.java | 18 + .../circuits/CircuitElectricChange.java | 60 + .../energy/circuits/CircuitElectricChoke.java | 17 + .../circuits/CircuitElectricEfficiency.java | 18 + .../energy/circuits/CircuitFireDampener.java | 46 + .../forestry/energy/gadgets/EngineBronze.java | 464 +++++++ .../energy/gadgets/EngineClockwork.java | 148 ++ .../forestry/energy/gadgets/EngineCopper.java | 511 +++++++ .../energy/gadgets/EngineDefinition.java | 60 + .../forestry/energy/gadgets/EngineTin.java | 366 +++++ .../energy/gadgets/MachineGenerator.java | 281 ++++ .../energy/gui/ContainerEngineBronze.java | 56 + .../energy/gui/ContainerEngineCopper.java | 60 + .../energy/gui/ContainerEngineTin.java | 53 + .../energy/gui/ContainerGenerator.java | 55 + .../energy/forestry/energy/gui/GuiEngine.java | 63 + .../forestry/energy/gui/GuiEngineBronze.java | 121 ++ .../forestry/energy/gui/GuiEngineCopper.java | 41 + .../forestry/energy/gui/GuiEngineTin.java | 63 + .../forestry/energy/gui/GuiGenerator.java | 42 + .../energy/proxy/ClientProxyEnergy.java | 19 + .../forestry/energy/proxy/ProxyEnergy.java | 16 + .../forestry/energy/render/RenderEngine.java | 203 +++ .../energy/forestry/plugins/PluginEnergy.java | 200 +++ .../forestry/factory/GuiHandlerFactory.java | 136 ++ .../factory/gadgets/MachineBottler.java | 508 +++++++ .../factory/gadgets/MachineCarpenter.java | 698 ++++++++++ .../factory/gadgets/MachineCentrifuge.java | 475 +++++++ .../factory/gadgets/MachineFabricator.java | 606 ++++++++ .../factory/gadgets/MachineFermenter.java | 700 ++++++++++ .../factory/gadgets/MachineMoistener.java | 728 ++++++++++ .../factory/gadgets/MachineRaintank.java | 313 +++++ .../factory/gadgets/MachineSqueezer.java | 558 ++++++++ .../factory/gadgets/MachineStill.java | 495 +++++++ .../factory/gadgets/MillRainmaker.java | 205 +++ .../factory/gadgets/TileWorktable.java | 539 ++++++++ .../factory/gui/ContainerBottler.java | 59 + .../factory/gui/ContainerCarpenter.java | 177 +++ .../factory/gui/ContainerCentrifuge.java | 57 + .../factory/gui/ContainerFabricator.java | 68 + .../factory/gui/ContainerFermenter.java | 60 + .../factory/gui/ContainerMoistener.java | 81 ++ .../factory/gui/ContainerRaintank.java | 57 + .../factory/gui/ContainerSqueezer.java | 63 + .../forestry/factory/gui/ContainerStill.java | 56 + .../factory/gui/ContainerWorktable.java | 129 ++ .../forestry/factory/gui/GuiBottler.java | 42 + .../forestry/factory/gui/GuiCarpenter.java | 51 + .../forestry/factory/gui/GuiCentrifuge.java | 38 + .../forestry/factory/gui/GuiFabricator.java | 47 + .../forestry/factory/gui/GuiFermenter.java | 49 + .../forestry/factory/gui/GuiMoistener.java | 50 + .../forestry/factory/gui/GuiRaintank.java | 43 + .../forestry/factory/gui/GuiSqueezer.java | 41 + .../forestry/factory/gui/GuiStill.java | 47 + .../forestry/factory/gui/GuiWorktable.java | 144 ++ .../factory/gui/InventoryCraftingAuto.java | 102 ++ .../forestry/factory/gui/SlotCraftMatrix.java | 37 + .../factory/recipes/CraftGuideBottler.java | 54 + .../factory/recipes/CraftGuideCarpenter.java | 63 + .../factory/recipes/CraftGuideCentrifuge.java | 62 + .../recipes/CraftGuideCustomRecipes.java | 55 + .../factory/recipes/CraftGuideFabricator.java | 63 + .../factory/recipes/CraftGuideFermenter.java | 66 + .../recipes/CraftGuideIntegration.java | 48 + .../factory/recipes/CraftGuideSqueezer.java | 60 + .../factory/recipes/CraftGuideStill.java | 52 + .../forestry/plugins/PluginFactory.java | 475 +++++++ .../forestry/farming/EventHandlerFarming.java | 36 + .../farming/forestry/farming/FarmHelper.java | 22 + .../farming/forestry/farming/FarmTarget.java | 50 + .../forestry/farming/GuiHandlerFarming.java | 55 + .../farming/circuits/CircuitFarmLogic.java | 74 + .../forestry/farming/gadgets/BlockFarm.java | 202 +++ .../farming/gadgets/BlockMushroom.java | 121 ++ .../farming/gadgets/StructureLogicFarm.java | 144 ++ .../forestry/farming/gadgets/TileControl.java | 101 ++ .../forestry/farming/gadgets/TileFarm.java | 359 +++++ .../farming/gadgets/TileFarmPlain.java | 965 +++++++++++++ .../forestry/farming/gadgets/TileGearbox.java | 119 ++ .../forestry/farming/gadgets/TileHatch.java | 339 +++++ .../forestry/farming/gadgets/TileValve.java | 71 + .../forestry/farming/gui/ContainerFarm.java | 177 +++ .../farming/forestry/farming/gui/GuiFarm.java | 162 +++ .../forestry/farming/items/ItemFarmBlock.java | 50 + .../farming/forestry/farming/logic/Crop.java | 64 + .../forestry/farming/logic/CropBlock.java | 48 + .../forestry/farming/logic/CropFruit.java | 57 + .../forestry/farming/logic/CropPeat.java | 43 + .../forestry/farming/logic/CropRubber.java | 37 + .../forestry/farming/logic/FarmLogic.java | 78 ++ .../farming/logic/FarmLogicArboreal.java | 246 ++++ .../farming/logic/FarmLogicCereal.java | 40 + .../farming/logic/FarmLogicCocoa.java | 219 +++ .../farming/logic/FarmLogicCrops.java | 137 ++ .../farming/logic/FarmLogicGourd.java | 95 ++ .../farming/logic/FarmLogicHomogenous.java | 112 ++ .../farming/logic/FarmLogicInfernal.java | 109 ++ .../farming/logic/FarmLogicOrchard.java | 180 +++ .../forestry/farming/logic/FarmLogicPeat.java | 85 ++ .../farming/logic/FarmLogicPoale.java | 106 ++ .../farming/logic/FarmLogicRubber.java | 175 +++ .../farming/logic/FarmLogicShroom.java | 63 + .../farming/logic/FarmLogicSucculent.java | 106 ++ .../farming/logic/FarmLogicVegetable.java | 40 + .../farming/logic/FarmLogicWatered.java | 182 +++ .../forestry/farming/logic/FarmableCocoa.java | 60 + .../farming/logic/FarmableFarmCraftory.java | 84 ++ .../forestry/farming/logic/FarmableGE.java | 59 + .../farming/logic/FarmableGenericCrop.java | 74 + .../farming/logic/FarmableGenericSapling.java | 83 ++ .../forestry/farming/logic/FarmableGourd.java | 71 + .../farming/logic/FarmableStacked.java | 58 + .../farming/logic/FarmableVanillaSapling.java | 47 + .../farming/logic/FarmableVanillaShroom.java | 48 + .../farming/proxy/ClientProxyFarming.java | 37 + .../forestry/farming/proxy/ProxyFarming.java | 18 + .../farming/render/FarmItemRenderer.java | 113 ++ .../farming/render/FarmRenderingHandler.java | 82 ++ .../triggers/TriggerLowFertilizer.java | 50 + .../farming/triggers/TriggerLowLiquid.java | 52 + .../farming/triggers/TriggerLowSoil.java | 65 + .../farming/worldgen/WorldGenBigMushroom.java | 149 ++ .../forestry/plugins/PluginFarmCraftory.java | 159 +++ .../forestry/plugins/PluginFarming.java | 359 +++++ .../forestry/plugins/PluginNatura.java | 107 ++ .../food/forestry/food/BeverageEffect.java | 48 + .../forestry/food/BeverageEffectAntidote.java | 45 + .../forestry/food/BeverageEffectDrunk.java | 33 + .../food/forestry/food/GuiHandlerFood.java | 52 + .../forestry/food/gui/ContainerInfuser.java | 68 + .../food/forestry/food/gui/GuiInfuser.java | 55 + .../forestry/food/items/ItemAmbrosia.java | 29 + .../forestry/food/items/ItemBeverage.java | 226 +++ .../food/forestry/food/items/ItemInfuser.java | 394 ++++++ .../food/forestry/plugins/PluginFood.java | 110 ++ .../lepidopterology/ButterflySpawner.java | 55 + .../GuiHandlerLepidopterology.java | 72 + .../lepidopterology/MatingRecipe.java | 76 + .../entities/AIButterflyBase.java | 58 + .../entities/AIButterflyFlee.java | 89 ++ .../entities/AIButterflyInteract.java | 159 +++ .../entities/AIButterflyRest.java | 67 + .../entities/AIButterflyWander.java | 82 ++ .../entities/EntityButterfly.java | 397 ++++++ .../gadgets/TileLepidopteristChest.java | 20 + .../genetics/AlleleButterflySpecies.java | 172 +++ .../genetics/AlleleEffectNone.java | 41 + .../lepidopterology/genetics/Butterfly.java | 291 ++++ .../genetics/ButterflyGenome.java | 115 ++ .../genetics/ButterflyHelper.java | 239 ++++ .../genetics/ButterflyTemplates.java | 304 ++++ .../genetics/LepidopteristTracker.java | 49 + .../gui/ContainerFlutterlyzer.java | 81 ++ .../lepidopterology/gui/GuiFlutterlyzer.java | 332 +++++ .../items/ItemButterflyGE.java | 214 +++ .../items/ItemFlutterlyzer.java | 162 +++ .../proxy/ClientProxyLepidopterology.java | 33 + .../proxy/ProxyLepidopterology.java | 18 + .../render/ButterflyItemRenderer.java | 223 +++ .../render/ModelButterfly.java | 99 ++ .../render/RenderButterfly.java | 43 + .../plugins/PluginLepidopterology.java | 325 +++++ .../mail/forestry/mail/CommandMail.java | 115 ++ .../mail/forestry/mail/EnumAddressee.java | 21 + .../mail/forestry/mail/EnumDeliveryState.java | 26 + .../mail/forestry/mail/EnumStationState.java | 26 + .../mail/forestry/mail/GuiHandlerMail.java | 119 ++ .../mail/forestry/mail/IMailContainer.java | 12 + .../mail/forestry/mail/Letter.java | 323 +++++ forestry_common/mail/forestry/mail/POBox.java | 149 ++ .../mail/forestry/mail/POBoxInfo.java | 22 + .../mail/forestry/mail/PacketHandlerMail.java | 113 ++ .../mail/forestry/mail/PostOffice.java | 201 +++ .../mail/forestry/mail/PostRegistry.java | 215 +++ .../mail/forestry/mail/PostalCarrier.java | 90 ++ .../forestry/mail/SaveEventHandlerMail.java | 33 + .../forestry/mail/TickHandlerMailClient.java | 32 + .../mail/forestry/mail/TradeStation.java | 492 +++++++ .../forestry/mail/gadgets/MachineMailbox.java | 275 ++++ .../mail/gadgets/MachinePhilatelist.java | 151 ++ .../forestry/mail/gadgets/MachineTrader.java | 402 ++++++ .../forestry/mail/gui/ContainerCatalogue.java | 243 ++++ .../forestry/mail/gui/ContainerLetter.java | 208 +++ .../forestry/mail/gui/ContainerMailbox.java | 61 + .../mail/gui/ContainerPhilatelist.java | 42 + .../forestry/mail/gui/ContainerTradeName.java | 59 + .../forestry/mail/gui/ContainerTrader.java | 78 ++ .../mail/forestry/mail/gui/GuiCatalogue.java | 144 ++ .../mail/forestry/mail/gui/GuiLetter.java | 244 ++++ .../mail/forestry/mail/gui/GuiMailbox.java | 23 + .../forestry/mail/gui/GuiMailboxInfo.java | 79 ++ .../forestry/mail/gui/GuiPhilatelist.java | 24 + .../mail/forestry/mail/gui/GuiTradeName.java | 99 ++ .../mail/forestry/mail/gui/GuiTrader.java | 43 + .../forestry/mail/items/ItemCatalogue.java | 37 + .../mail/forestry/mail/items/ItemLetter.java | 270 ++++ .../mail/forestry/mail/items/ItemStamps.java | 68 + .../mail/network/PacketPOBoxInfo.java | 51 + .../mail/network/PacketTradeInfo.java | 73 + .../forestry/mail/proxy/ClientProxyMail.java | 57 + .../mail/forestry/mail/proxy/ProxyMail.java | 40 + .../forestry/mail/triggers/TriggerBuffer.java | 42 + .../mail/triggers/TriggerHasMail.java | 33 + .../mail/triggers/TriggerLowInput.java | 41 + .../mail/triggers/TriggerLowPaper.java | 42 + .../mail/triggers/TriggerLowStamps.java | 42 + .../mail/forestry/plugins/PluginMail.java | 223 +++ .../forestry/plugins/PluginStorage.java | 594 ++++++++ .../forestry/storage/BackpackDefinition.java | 84 ++ .../forestry/storage/BackpackHelper.java | 26 + .../forestry/storage/BackpackMode.java | 12 + .../forestry/storage/GuiHandlerStorage.java | 154 +++ .../storage/PickupHandlerStorage.java | 99 ++ .../forestry/storage/ResupplyHandler.java | 127 ++ .../storage/gui/ContainerBackpack.java | 73 + .../gui/ContainerNaturalistBackpack.java | 81 ++ .../forestry/storage/gui/GuiBackpack.java | 29 + .../forestry/storage/gui/GuiBackpackT2.java | 22 + .../forestry/storage/items/ItemBackpack.java | 351 +++++ .../storage/items/ItemNaturalistBackpack.java | 61 + forestry_resources/CREDITS.txt | 27 + forestry_resources/README.txt | 17 + forestry_resources/assets/forestry/logo.png | Bin 0 -> 27326 bytes .../forestry/textures/blocks/analyzer.0.png | Bin 0 -> 688 bytes .../textures/blocks/analyzer_pedestal.png | Bin 0 -> 1129 bytes .../textures/blocks/analyzer_tower1.png | Bin 0 -> 884 bytes .../textures/blocks/analyzer_tower2.png | Bin 0 -> 982 bytes .../textures/blocks/apiaristchest.0.png | Bin 0 -> 432 bytes .../textures/blocks/apiaristchest.1.png | Bin 0 -> 503 bytes .../textures/blocks/apiaristchest.2.png | Bin 0 -> 467 bytes .../textures/blocks/apiaristchest.3.png | Bin 0 -> 531 bytes .../textures/blocks/apiaristchest.4.png | Bin 0 -> 467 bytes .../forestry/textures/blocks/apiary.0.png | Bin 0 -> 440 bytes .../forestry/textures/blocks/apiary.1.png | Bin 0 -> 421 bytes .../forestry/textures/blocks/apiary.2.png | Bin 0 -> 520 bytes .../forestry/textures/blocks/apiary.4.png | Bin 0 -> 510 bytes .../forestry/textures/blocks/apiary.7.png | Bin 0 -> 254 bytes .../blocks/apiculture/alveary.bottom.png | Bin 0 -> 441 bytes .../blocks/apiculture/alveary.entrance.png | Bin 0 -> 481 bytes .../blocks/apiculture/alveary.fan.off.png | Bin 0 -> 501 bytes .../blocks/apiculture/alveary.fan.on.png | Bin 0 -> 634 bytes .../blocks/apiculture/alveary.heater.off.png | Bin 0 -> 496 bytes .../blocks/apiculture/alveary.heater.on.png | Bin 0 -> 643 bytes .../blocks/apiculture/alveary.left.png | Bin 0 -> 483 bytes .../blocks/apiculture/alveary.plain.png | Bin 0 -> 456 bytes .../blocks/apiculture/alveary.right.png | Bin 0 -> 474 bytes .../blocks/apiculture/alveary.sieve.png | Bin 0 -> 582 bytes .../blocks/apiculture/alveary.stabiliser.png | Bin 0 -> 700 bytes .../blocks/apiculture/alveary.swarmer.off.png | Bin 0 -> 477 bytes .../blocks/apiculture/alveary.swarmer.on.png | Bin 0 -> 479 bytes .../blocks/apiculture/alveary.valve.png | Bin 0 -> 543 bytes .../forestry/textures/blocks/arbchest.0.png | Bin 0 -> 343 bytes .../forestry/textures/blocks/arbchest.1.png | Bin 0 -> 685 bytes .../forestry/textures/blocks/arbchest.2.png | Bin 0 -> 356 bytes .../forestry/textures/blocks/arbchest.3.png | Bin 0 -> 476 bytes .../forestry/textures/blocks/arbchest.4.png | Bin 0 -> 356 bytes .../forestry/textures/blocks/arbchest.7.png | Bin 0 -> 675 bytes .../blocks/beehives/beehive.1.side.png | Bin 0 -> 606 bytes .../blocks/beehives/beehive.1.top.png | Bin 0 -> 416 bytes .../blocks/beehives/beehive.2.side.png | Bin 0 -> 373 bytes .../blocks/beehives/beehive.2.top.png | Bin 0 -> 649 bytes .../blocks/beehives/beehive.3.side.png | Bin 0 -> 634 bytes .../blocks/beehives/beehive.3.top.png | Bin 0 -> 670 bytes .../blocks/beehives/beehive.4.side.png | Bin 0 -> 577 bytes .../blocks/beehives/beehive.4.top.png | Bin 0 -> 698 bytes .../blocks/beehives/beehive.5.side.png | Bin 0 -> 524 bytes .../blocks/beehives/beehive.5.top.png | Bin 0 -> 506 bytes .../blocks/beehives/beehive.6.side.png | Bin 0 -> 658 bytes .../blocks/beehives/beehive.6.top.png | Bin 0 -> 638 bytes .../blocks/beehives/beehive.7.side.png | Bin 0 -> 679 bytes .../blocks/beehives/beehive.7.top.png | Bin 0 -> 675 bytes .../blocks/beehives/beehive.8.side.png | Bin 0 -> 894 bytes .../blocks/beehives/beehive.8.top.png | Bin 0 -> 768 bytes .../forestry/textures/blocks/beehouse.0.png | Bin 0 -> 444 bytes .../forestry/textures/blocks/beehouse.1.png | Bin 0 -> 236 bytes .../forestry/textures/blocks/beehouse.2.png | Bin 0 -> 662 bytes .../forestry/textures/blocks/beehouse.4.png | Bin 0 -> 607 bytes .../forestry/textures/blocks/beehouse.7.png | Bin 0 -> 241 bytes .../forestry/textures/blocks/block_0_14.png | Bin 0 -> 309 bytes .../forestry/textures/blocks/block_12_13.png | Bin 0 -> 406 bytes .../forestry/textures/blocks/block_12_14.png | Bin 0 -> 406 bytes .../forestry/textures/blocks/block_12_15.png | Bin 0 -> 406 bytes .../forestry/textures/blocks/block_13_14.png | Bin 0 -> 406 bytes .../forestry/textures/blocks/block_13_15.png | Bin 0 -> 406 bytes .../forestry/textures/blocks/bottler.0.png | Bin 0 -> 304 bytes .../forestry/textures/blocks/bottler_base.png | Bin 0 -> 711 bytes .../blocks/bottler_tank_product_empty.png | Bin 0 -> 391 bytes .../blocks/bottler_tank_resource_empty.png | Bin 0 -> 345 bytes .../blocks/bottler_tank_resource_high.png | Bin 0 -> 348 bytes .../blocks/bottler_tank_resource_low.png | Bin 0 -> 351 bytes .../blocks/bottler_tank_resource_maximum.png | Bin 0 -> 344 bytes .../blocks/bottler_tank_resource_medium.png | Bin 0 -> 349 bytes .../forestry/textures/blocks/candle.png | Bin 0 -> 367 bytes .../textures/blocks/candleStumpLit.png | Bin 0 -> 1257 bytes .../textures/blocks/candleStumpUnlit.png | Bin 0 -> 1257 bytes .../forestry/textures/blocks/candleTipLit.png | Bin 0 -> 1256 bytes .../textures/blocks/candleTipUnlit.png | Bin 0 -> 1256 bytes .../forestry/textures/blocks/carpenter.0.png | Bin 0 -> 490 bytes .../textures/blocks/carpenter_base.png | Bin 0 -> 911 bytes .../blocks/carpenter_tank_product_empty.png | Bin 0 -> 894 bytes .../blocks/carpenter_tank_resource_empty.png | Bin 0 -> 846 bytes .../blocks/carpenter_tank_resource_high.png | Bin 0 -> 834 bytes .../blocks/carpenter_tank_resource_low.png | Bin 0 -> 855 bytes .../carpenter_tank_resource_maximum.png | Bin 0 -> 830 bytes .../blocks/carpenter_tank_resource_medium.png | Bin 0 -> 861 bytes .../forestry/textures/blocks/centrifuge.0.png | Bin 0 -> 490 bytes .../textures/blocks/centrifuge_base.png | Bin 0 -> 938 bytes .../blocks/centrifuge_tank_product_empty.png | Bin 0 -> 898 bytes .../blocks/centrifuge_tank_resource_empty.png | Bin 0 -> 898 bytes .../textures/blocks/engine_bronze_base.png | Bin 0 -> 973 bytes .../blocks/engine_bronze_extension.png | Bin 0 -> 480 bytes .../textures/blocks/engine_bronze_piston.png | Bin 0 -> 538 bytes .../textures/blocks/engine_clock_base.png | Bin 0 -> 1007 bytes .../blocks/engine_clock_extension.png | Bin 0 -> 489 bytes .../textures/blocks/engine_clock_piston.png | Bin 0 -> 556 bytes .../textures/blocks/engine_copper_base.png | Bin 0 -> 634 bytes .../blocks/engine_copper_extension.png | Bin 0 -> 480 bytes .../textures/blocks/engine_copper_piston.png | Bin 0 -> 459 bytes .../textures/blocks/engine_tin_base.png | Bin 0 -> 1496 bytes .../textures/blocks/engine_tin_extension.png | Bin 0 -> 526 bytes .../textures/blocks/engine_tin_piston.png | Bin 0 -> 1158 bytes .../textures/blocks/engine_trunk_high.png | Bin 0 -> 274 bytes .../textures/blocks/engine_trunk_higher.png | Bin 0 -> 273 bytes .../textures/blocks/engine_trunk_highest.png | Bin 0 -> 290 bytes .../textures/blocks/engine_trunk_low.png | Bin 0 -> 285 bytes .../textures/blocks/engine_trunk_medium.png | Bin 0 -> 278 bytes .../textures/blocks/enginebronze.0.png | Bin 0 -> 490 bytes .../textures/blocks/engineclockwork.0.png | Bin 0 -> 481 bytes .../textures/blocks/enginecopper.0.png | Bin 0 -> 426 bytes .../forestry/textures/blocks/enginetin.0.png | Bin 0 -> 688 bytes .../forestry/textures/blocks/escritoire.0.png | Bin 0 -> 752 bytes .../forestry/textures/blocks/escritoire.png | Bin 0 -> 1548 bytes .../forestry/textures/blocks/fabricator.0.png | Bin 0 -> 688 bytes .../forestry/textures/blocks/fabricator.1.png | Bin 0 -> 1134 bytes .../forestry/textures/blocks/fabricator.2.png | Bin 0 -> 922 bytes .../forestry/textures/blocks/fabricator.3.png | Bin 0 -> 1030 bytes .../forestry/textures/blocks/fabricator.4.png | Bin 0 -> 842 bytes .../forestry/textures/blocks/farm/band.png | Bin 0 -> 563 bytes .../forestry/textures/blocks/farm/control.png | Bin 0 -> 440 bytes .../forestry/textures/blocks/farm/gears.png | Bin 0 -> 530 bytes .../forestry/textures/blocks/farm/hatch.png | Bin 0 -> 504 bytes .../forestry/textures/blocks/farm/plain.png | Bin 0 -> 212 bytes .../forestry/textures/blocks/farm/reverse.png | Bin 0 -> 214 bytes .../forestry/textures/blocks/farm/top.png | Bin 0 -> 625 bytes .../forestry/textures/blocks/farm/valve.png | Bin 0 -> 418 bytes .../forestry/textures/blocks/fermenter.0.png | Bin 0 -> 524 bytes .../textures/blocks/fermenter_base.png | Bin 0 -> 911 bytes .../blocks/fermenter_tank_product_empty.png | Bin 0 -> 846 bytes .../blocks/fermenter_tank_product_high.png | Bin 0 -> 835 bytes .../blocks/fermenter_tank_product_low.png | Bin 0 -> 837 bytes .../blocks/fermenter_tank_product_maximum.png | Bin 0 -> 838 bytes .../blocks/fermenter_tank_product_medium.png | Bin 0 -> 838 bytes .../blocks/fermenter_tank_resource_empty.png | Bin 0 -> 846 bytes .../blocks/fermenter_tank_resource_high.png | Bin 0 -> 834 bytes .../blocks/fermenter_tank_resource_low.png | Bin 0 -> 855 bytes .../fermenter_tank_resource_maximum.png | Bin 0 -> 830 bytes .../blocks/fermenter_tank_resource_medium.png | Bin 0 -> 861 bytes .../forestry/textures/blocks/generator.0.png | Bin 0 -> 688 bytes .../textures/blocks/generator_base.png | Bin 0 -> 875 bytes .../blocks/generator_tank_product_empty.png | Bin 0 -> 1057 bytes .../blocks/generator_tank_resource_empty.png | Bin 0 -> 923 bytes .../blocks/generator_tank_resource_high.png | Bin 0 -> 970 bytes .../blocks/generator_tank_resource_low.png | Bin 0 -> 890 bytes .../generator_tank_resource_maximum.png | Bin 0 -> 882 bytes .../blocks/generator_tank_resource_medium.png | Bin 0 -> 896 bytes .../blocks/germlings/sapling.treeAcacia.png | Bin 0 -> 474 bytes .../blocks/germlings/sapling.treeBalsa.png | Bin 0 -> 452 bytes .../blocks/germlings/sapling.treeBaobab.png | Bin 0 -> 710 bytes .../blocks/germlings/sapling.treeCherry.png | Bin 0 -> 464 bytes .../blocks/germlings/sapling.treeChestnut.png | Bin 0 -> 577 bytes .../blocks/germlings/sapling.treeDate.png | Bin 0 -> 410 bytes .../blocks/germlings/sapling.treeEbony.png | Bin 0 -> 547 bytes .../blocks/germlings/sapling.treeGigant.png | Bin 0 -> 370 bytes .../blocks/germlings/sapling.treeKapok.png | Bin 0 -> 598 bytes .../blocks/germlings/sapling.treeLarch.png | Bin 0 -> 605 bytes .../blocks/germlings/sapling.treeLemon.png | Bin 0 -> 591 bytes .../blocks/germlings/sapling.treeLime.png | Bin 0 -> 451 bytes .../blocks/germlings/sapling.treeMahoe.png | Bin 0 -> 601 bytes .../blocks/germlings/sapling.treeMahogony.png | Bin 0 -> 584 bytes .../blocks/germlings/sapling.treeMaple.png | Bin 0 -> 518 bytes .../blocks/germlings/sapling.treePapaya.png | Bin 0 -> 412 bytes .../blocks/germlings/sapling.treePine.png | Bin 0 -> 436 bytes .../blocks/germlings/sapling.treePlum.png | Bin 0 -> 588 bytes .../blocks/germlings/sapling.treePoplar.png | Bin 0 -> 491 bytes .../blocks/germlings/sapling.treeRubber.png | Bin 0 -> 422 bytes .../blocks/germlings/sapling.treeSequioa.png | Bin 0 -> 482 bytes .../blocks/germlings/sapling.treeSipiri.png | Bin 0 -> 595 bytes .../blocks/germlings/sapling.treeTeak.png | Bin 0 -> 632 bytes .../blocks/germlings/sapling.treeWalnut.png | Bin 0 -> 623 bytes .../blocks/germlings/sapling.treeWenge.png | Bin 0 -> 569 bytes .../blocks/germlings/sapling.treeWillow.png | Bin 0 -> 640 bytes .../blocks/leaves/conifers.changed.png | Bin 0 -> 509 bytes .../textures/blocks/leaves/conifers.fancy.png | Bin 0 -> 463 bytes .../textures/blocks/leaves/conifers.plain.png | Bin 0 -> 426 bytes .../blocks/leaves/deciduous.changed.png | Bin 0 -> 750 bytes .../blocks/leaves/deciduous.fancy.png | Bin 0 -> 732 bytes .../blocks/leaves/deciduous.plain.png | Bin 0 -> 721 bytes .../textures/blocks/leaves/fruits.berries.png | Bin 0 -> 411 bytes .../textures/blocks/leaves/fruits.citrus.png | Bin 0 -> 281 bytes .../textures/blocks/leaves/fruits.nuts.png | Bin 0 -> 397 bytes .../textures/blocks/leaves/fruits.plums.png | Bin 0 -> 424 bytes .../textures/blocks/leaves/fruits.pomes.png | Bin 0 -> 454 bytes .../textures/blocks/leaves/jungle.changed.png | Bin 0 -> 543 bytes .../textures/blocks/leaves/jungle.fancy.png | Bin 0 -> 544 bytes .../textures/blocks/leaves/jungle.plain.png | Bin 0 -> 499 bytes .../textures/blocks/leaves/maple.changed.png | Bin 0 -> 931 bytes .../textures/blocks/leaves/maple.fancy.png | Bin 0 -> 931 bytes .../textures/blocks/leaves/maple.plain.png | Bin 0 -> 765 bytes .../textures/blocks/leaves/palm.changed.png | Bin 0 -> 613 bytes .../textures/blocks/leaves/palm.fancy.png | Bin 0 -> 613 bytes .../textures/blocks/leaves/palm.plain.png | Bin 0 -> 557 bytes .../textures/blocks/leaves/tile]-103.png | Bin 0 -> 409 bytes .../textures/blocks/leaves/tile]-52.png | Bin 0 -> 375 bytes .../textures/blocks/leaves/tile]-68.png | Bin 0 -> 362 bytes .../textures/blocks/leaves/tile]-98.png | Bin 0 -> 394 bytes .../textures/blocks/leaves/willow.changed.png | Bin 0 -> 440 bytes .../textures/blocks/leaves/willow.fancy.png | Bin 0 -> 440 bytes .../textures/blocks/leaves/willow.plain.png | Bin 0 -> 428 bytes .../forestry/textures/blocks/lepichest.0.png | Bin 0 -> 324 bytes .../forestry/textures/blocks/lepichest.1.png | Bin 0 -> 625 bytes .../forestry/textures/blocks/lepichest.2.png | Bin 0 -> 341 bytes .../forestry/textures/blocks/lepichest.3.png | Bin 0 -> 445 bytes .../forestry/textures/blocks/lepichest.4.png | Bin 0 -> 341 bytes .../forestry/textures/blocks/lepichest.7.png | Bin 0 -> 608 bytes .../textures/blocks/liquid/bioethanol.png | Bin 0 -> 10863 bytes .../blocks/liquid/bioethanol.png.mcmeta | 1 + .../textures/blocks/liquid/biomass.png | Bin 0 -> 11696 bytes .../textures/blocks/liquid/biomass.png.mcmeta | 1 + .../forestry/textures/blocks/liquid/glass.png | Bin 0 -> 10748 bytes .../textures/blocks/liquid/glass.png.mcmeta | 1 + .../forestry/textures/blocks/liquid/honey.png | Bin 0 -> 7230 bytes .../textures/blocks/liquid/honey.png.mcmeta | 1 + .../forestry/textures/blocks/liquid/ice.png | Bin 0 -> 11681 bytes .../textures/blocks/liquid/ice.png.mcmeta | 1 + .../forestry/textures/blocks/liquid/juice.png | Bin 0 -> 11823 bytes .../textures/blocks/liquid/juice.png.mcmeta | 1 + .../forestry/textures/blocks/liquid/milk.png | Bin 0 -> 2935 bytes .../textures/blocks/liquid/seedoil.png | Bin 0 -> 9934 bytes .../textures/blocks/liquid/seedoil.png.mcmeta | 1 + .../textures/blocks/liquid/short.mead.png | Bin 0 -> 11984 bytes .../blocks/liquid/short.mead.png.mcmeta | 1 + .../forestry/textures/blocks/mailbox.0.png | Bin 0 -> 716 bytes .../forestry/textures/blocks/mailbox.1.png | Bin 0 -> 796 bytes .../forestry/textures/blocks/mailbox.2.png | Bin 0 -> 675 bytes .../forestry/textures/blocks/mailbox.7.png | Bin 0 -> 802 bytes .../forestry/textures/blocks/moistener.0.png | Bin 0 -> 426 bytes .../textures/blocks/moistener_base.png | Bin 0 -> 842 bytes .../blocks/moistener_tank_product_empty.png | Bin 0 -> 727 bytes .../blocks/moistener_tank_resource_empty.png | Bin 0 -> 751 bytes .../blocks/moistener_tank_resource_high.png | Bin 0 -> 757 bytes .../blocks/moistener_tank_resource_low.png | Bin 0 -> 758 bytes .../moistener_tank_resource_maximum.png | Bin 0 -> 752 bytes .../blocks/moistener_tank_resource_medium.png | Bin 0 -> 759 bytes .../forestry/textures/blocks/ores/apatite.png | Bin 0 -> 567 bytes .../forestry/textures/blocks/ores/copper.png | Bin 0 -> 567 bytes .../forestry/textures/blocks/ores/tin.png | Bin 0 -> 565 bytes .../textures/blocks/philatelist.0.png | Bin 0 -> 716 bytes .../textures/blocks/philatelist.1.png | Bin 0 -> 796 bytes .../textures/blocks/philatelist.2.png | Bin 0 -> 675 bytes .../textures/blocks/philatelist.3.png | Bin 0 -> 723 bytes .../textures/blocks/philatelist.7.png | Bin 0 -> 802 bytes .../textures/blocks/pipes/pipe_prop.black.png | Bin 0 -> 409 bytes .../textures/blocks/pipes/pipe_prop.blue.png | Bin 0 -> 409 bytes .../textures/blocks/pipes/pipe_prop.empty.png | Bin 0 -> 402 bytes .../textures/blocks/pipes/pipe_prop.green.png | Bin 0 -> 409 bytes .../textures/blocks/pipes/pipe_prop.red.png | Bin 0 -> 409 bytes .../textures/blocks/pipes/pipe_prop.white.png | Bin 0 -> 409 bytes .../blocks/pipes/pipe_prop.yellow.png | Bin 0 -> 409 bytes .../forestry/textures/blocks/pods/dates.0.png | Bin 0 -> 352 bytes .../forestry/textures/blocks/pods/dates.1.png | Bin 0 -> 481 bytes .../forestry/textures/blocks/pods/dates.2.png | Bin 0 -> 563 bytes .../textures/blocks/pods/papaya.0.png | Bin 0 -> 352 bytes .../textures/blocks/pods/papaya.1.png | Bin 0 -> 489 bytes .../textures/blocks/pods/papaya.2.png | Bin 0 -> 601 bytes .../forestry/textures/blocks/rainmaker.0.png | Bin 0 -> 688 bytes .../textures/blocks/rainmaker_blade1.png | Bin 0 -> 657 bytes .../textures/blocks/rainmaker_blade2.png | Bin 0 -> 574 bytes .../textures/blocks/rainmaker_column_0.png | Bin 0 -> 301 bytes .../textures/blocks/rainmaker_column_1.png | Bin 0 -> 308 bytes .../textures/blocks/rainmaker_column_2.png | Bin 0 -> 332 bytes .../textures/blocks/rainmaker_column_3.png | Bin 0 -> 344 bytes .../textures/blocks/rainmaker_column_4.png | Bin 0 -> 343 bytes .../textures/blocks/rainmaker_column_5.png | Bin 0 -> 343 bytes .../textures/blocks/rainmaker_column_6.png | Bin 0 -> 330 bytes .../textures/blocks/rainmaker_column_7.png | Bin 0 -> 313 bytes .../textures/blocks/rainmaker_extension.png | Bin 0 -> 234 bytes .../textures/blocks/rainmaker_pedestal.png | Bin 0 -> 920 bytes .../forestry/textures/blocks/raintank.0.png | Bin 0 -> 473 bytes .../forestry/textures/blocks/raintank.1.png | Bin 0 -> 405 bytes .../forestry/textures/blocks/soil/bog.png | Bin 0 -> 475 bytes .../forestry/textures/blocks/soil/humus.png | Bin 0 -> 472 bytes .../forestry/textures/blocks/soil/peat.png | Bin 0 -> 410 bytes .../forestry/textures/blocks/squeezer.0.png | Bin 0 -> 490 bytes .../textures/blocks/squeezer_base.png | Bin 0 -> 938 bytes .../blocks/squeezer_tank_product_empty.png | Bin 0 -> 854 bytes .../blocks/squeezer_tank_product_high.png | Bin 0 -> 834 bytes .../blocks/squeezer_tank_product_low.png | Bin 0 -> 838 bytes .../blocks/squeezer_tank_product_maximum.png | Bin 0 -> 834 bytes .../blocks/squeezer_tank_product_medium.png | Bin 0 -> 836 bytes .../blocks/squeezer_tank_resource_empty.png | Bin 0 -> 864 bytes .../forestry/textures/blocks/stained/0.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/1.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/10.png | Bin 0 -> 398 bytes .../forestry/textures/blocks/stained/11.png | Bin 0 -> 398 bytes .../forestry/textures/blocks/stained/12.png | Bin 0 -> 398 bytes .../forestry/textures/blocks/stained/13.png | Bin 0 -> 398 bytes .../forestry/textures/blocks/stained/14.png | Bin 0 -> 398 bytes .../forestry/textures/blocks/stained/15.png | Bin 0 -> 398 bytes .../forestry/textures/blocks/stained/2.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/3.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/4.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/5.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/6.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/7.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/8.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/stained/9.png | Bin 0 -> 397 bytes .../forestry/textures/blocks/still.0.png | Bin 0 -> 473 bytes .../forestry/textures/blocks/still_base.png | Bin 0 -> 921 bytes .../blocks/still_tank_product_empty.png | Bin 0 -> 832 bytes .../blocks/still_tank_product_high.png | Bin 0 -> 830 bytes .../blocks/still_tank_product_low.png | Bin 0 -> 827 bytes .../blocks/still_tank_product_maximum.png | Bin 0 -> 823 bytes .../blocks/still_tank_product_medium.png | Bin 0 -> 832 bytes .../blocks/still_tank_resource_empty.png | Bin 0 -> 832 bytes .../blocks/still_tank_resource_high.png | Bin 0 -> 862 bytes .../blocks/still_tank_resource_low.png | Bin 0 -> 847 bytes .../blocks/still_tank_resource_maximum.png | Bin 0 -> 853 bytes .../blocks/still_tank_resource_medium.png | Bin 0 -> 829 bytes .../assets/forestry/textures/blocks/stump.png | Bin 0 -> 361 bytes .../textures/blocks/tradestation.0.png | Bin 0 -> 716 bytes .../textures/blocks/tradestation.1.png | Bin 0 -> 796 bytes .../textures/blocks/tradestation.2.png | Bin 0 -> 776 bytes .../textures/blocks/tradestation.3.png | Bin 0 -> 802 bytes .../textures/blocks/tradestation.4.png | Bin 0 -> 675 bytes .../textures/blocks/tradestation.7.png | Bin 0 -> 802 bytes .../textures/blocks/wood/bark.acacia.png | Bin 0 -> 673 bytes .../textures/blocks/wood/bark.balsa.png | Bin 0 -> 1317 bytes .../textures/blocks/wood/bark.baobab.png | Bin 0 -> 1353 bytes .../textures/blocks/wood/bark.cherry.png | Bin 0 -> 591 bytes .../textures/blocks/wood/bark.chestnut.png | Bin 0 -> 1062 bytes .../textures/blocks/wood/bark.citrus.png | Bin 0 -> 1338 bytes .../textures/blocks/wood/bark.ebony.png | Bin 0 -> 673 bytes .../textures/blocks/wood/bark.giganteum.png | Bin 0 -> 732 bytes .../textures/blocks/wood/bark.greenheart.png | Bin 0 -> 1169 bytes .../textures/blocks/wood/bark.kapok.png | Bin 0 -> 1356 bytes .../textures/blocks/wood/bark.larch.png | Bin 0 -> 1326 bytes .../textures/blocks/wood/bark.lime.png | Bin 0 -> 1326 bytes .../textures/blocks/wood/bark.mahoe.png | Bin 0 -> 1320 bytes .../textures/blocks/wood/bark.mahogany.png | Bin 0 -> 1320 bytes .../textures/blocks/wood/bark.maple.png | Bin 0 -> 1356 bytes .../textures/blocks/wood/bark.palm.png | Bin 0 -> 1353 bytes .../textures/blocks/wood/bark.papaya.png | Bin 0 -> 1359 bytes .../textures/blocks/wood/bark.pine.png | Bin 0 -> 1359 bytes .../textures/blocks/wood/bark.plum.png | Bin 0 -> 1088 bytes .../textures/blocks/wood/bark.poplar.png | Bin 0 -> 1356 bytes .../textures/blocks/wood/bark.sequoia.png | Bin 0 -> 1335 bytes .../textures/blocks/wood/bark.teak.png | Bin 0 -> 1311 bytes .../textures/blocks/wood/bark.walnut.png | Bin 0 -> 1359 bytes .../textures/blocks/wood/bark.wenge.png | Bin 0 -> 1356 bytes .../textures/blocks/wood/bark.willow.png | Bin 0 -> 1356 bytes .../textures/blocks/wood/heart.acacia.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.balsa.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.baobab.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.cherry.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.chestnut.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.citrus.png | Bin 0 -> 591 bytes .../textures/blocks/wood/heart.ebony.png | Bin 0 -> 579 bytes .../textures/blocks/wood/heart.giganteum.png | Bin 0 -> 622 bytes .../textures/blocks/wood/heart.greenheart.png | Bin 0 -> 643 bytes .../textures/blocks/wood/heart.kapok.png | Bin 0 -> 632 bytes .../textures/blocks/wood/heart.larch.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.lime.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.mahoe.png | Bin 0 -> 599 bytes .../textures/blocks/wood/heart.mahogany.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.maple.png | Bin 0 -> 588 bytes .../textures/blocks/wood/heart.palm.png | Bin 0 -> 614 bytes .../textures/blocks/wood/heart.papaya.png | Bin 0 -> 613 bytes .../textures/blocks/wood/heart.pine.png | Bin 0 -> 604 bytes .../textures/blocks/wood/heart.plum.png | Bin 0 -> 597 bytes .../textures/blocks/wood/heart.poplar.png | Bin 0 -> 611 bytes .../textures/blocks/wood/heart.sequoia.png | Bin 0 -> 647 bytes .../textures/blocks/wood/heart.teak.png | Bin 0 -> 631 bytes .../textures/blocks/wood/heart.walnut.png | Bin 0 -> 642 bytes .../textures/blocks/wood/heart.wenge.png | Bin 0 -> 618 bytes .../textures/blocks/wood/heart.willow.png | Bin 0 -> 640 bytes .../textures/blocks/wood/planks.acacia.png | Bin 0 -> 448 bytes .../textures/blocks/wood/planks.balsa.png | Bin 0 -> 449 bytes .../textures/blocks/wood/planks.baobab.png | Bin 0 -> 439 bytes .../textures/blocks/wood/planks.cherry.png | Bin 0 -> 474 bytes .../textures/blocks/wood/planks.chestnut.png | Bin 0 -> 439 bytes .../textures/blocks/wood/planks.citrus.png | Bin 0 -> 507 bytes .../textures/blocks/wood/planks.ebony.png | Bin 0 -> 449 bytes .../blocks/wood/planks.greenheart.png | Bin 0 -> 445 bytes .../textures/blocks/wood/planks.kapok.png | Bin 0 -> 449 bytes .../textures/blocks/wood/planks.larch.png | Bin 0 -> 448 bytes .../textures/blocks/wood/planks.lime.png | Bin 0 -> 448 bytes .../textures/blocks/wood/planks.mahoe.png | Bin 0 -> 528 bytes .../textures/blocks/wood/planks.mahogany.png | Bin 0 -> 449 bytes .../textures/blocks/wood/planks.maple.png | Bin 0 -> 506 bytes .../textures/blocks/wood/planks.palm.png | Bin 0 -> 517 bytes .../textures/blocks/wood/planks.papaya.png | Bin 0 -> 517 bytes .../textures/blocks/wood/planks.pine.png | Bin 0 -> 517 bytes .../textures/blocks/wood/planks.plum.png | Bin 0 -> 517 bytes .../textures/blocks/wood/planks.poplar.png | Bin 0 -> 517 bytes .../textures/blocks/wood/planks.sequoia.png | Bin 0 -> 439 bytes .../textures/blocks/wood/planks.teak.png | Bin 0 -> 448 bytes .../textures/blocks/wood/planks.walnut.png | Bin 0 -> 445 bytes .../textures/blocks/wood/planks.wenge.png | Bin 0 -> 439 bytes .../textures/blocks/wood/planks.willow.png | Bin 0 -> 445 bytes .../textures/blocks/wood/tile]-120.png | Bin 0 -> 507 bytes .../textures/blocks/wood/tile]-127.png | Bin 0 -> 560 bytes .../textures/blocks/wood/tile]-142.png | Bin 0 -> 1121 bytes .../textures/blocks/wood/tile]-143.png | Bin 0 -> 1320 bytes .../textures/blocks/wood/tile]-158.png | Bin 0 -> 620 bytes .../textures/blocks/wood/tile]-159.png | Bin 0 -> 652 bytes .../forestry/textures/blocks/worktable.0.png | Bin 0 -> 502 bytes .../forestry/textures/blocks/worktable.1.png | Bin 0 -> 767 bytes .../forestry/textures/blocks/worktable.2.png | Bin 0 -> 771 bytes .../forestry/textures/blocks/worktable.3.png | Bin 0 -> 748 bytes .../forestry/textures/blocks/worktable.4.png | Bin 0 -> 661 bytes .../forestry/textures/entity/beekeeper.png | Bin 0 -> 3951 bytes .../forestry/textures/entity/bees/endBee.png | Bin 0 -> 974 bytes .../textures/entity/bees/honeyBee.png | Bin 0 -> 1043 bytes .../forestry/textures/entity/bees/icyBee.png | Bin 0 -> 981 bytes .../textures/entity/bees/sinisterBee.png | Bin 0 -> 991 bytes .../textures/entity/bees/tropicalBee.png | Bin 0 -> 1043 bytes .../entity/butterflies/lepiAurora.png | Bin 0 -> 1526 bytes .../entity/butterflies/lepiBatesia.png | Bin 0 -> 1546 bytes .../entity/butterflies/lepiBlackSwallow.png | Bin 0 -> 1534 bytes .../entity/butterflies/lepiBlueDuke.png | Bin 0 -> 3505 bytes .../entity/butterflies/lepiBlueWing.png | Bin 0 -> 1537 bytes .../entity/butterflies/lepiBrimstone.png | Bin 0 -> 1540 bytes .../entity/butterflies/lepiCSpeckledWood.png | Bin 0 -> 1544 bytes .../entity/butterflies/lepiCabbageWhite.png | Bin 0 -> 1527 bytes .../entity/butterflies/lepiCitrusSwallow.png | Bin 0 -> 1540 bytes .../textures/entity/butterflies/lepiComma.png | Bin 0 -> 1535 bytes .../entity/butterflies/lepiDianaFrit.png | Bin 0 -> 1509 bytes .../entity/butterflies/lepiEmeraldPeacock.png | Bin 0 -> 1544 bytes .../entity/butterflies/lepiGlasswing.png | Bin 0 -> 1506 bytes .../entity/butterflies/lepiGlassyTiger.png | Bin 0 -> 1516 bytes .../entity/butterflies/lepiGozoraAzure.png | Bin 0 -> 1545 bytes .../entity/butterflies/lepiLLacewing.png | Bin 0 -> 1545 bytes .../entity/butterflies/lepiMBlueMorpho.png | Bin 0 -> 1537 bytes .../entity/butterflies/lepiMSpeckledWood.png | Bin 0 -> 1526 bytes .../entity/butterflies/lepiMalachite.png | Bin 0 -> 1558 bytes .../entity/butterflies/lepiMonarch.png | Bin 0 -> 1534 bytes .../entity/butterflies/lepiPBlueMorpho.png | Bin 0 -> 1532 bytes .../entity/butterflies/lepiPalaenoSulphur.png | Bin 0 -> 1536 bytes .../entity/butterflies/lepiPostillion.png | Bin 0 -> 1536 bytes .../entity/butterflies/lepiPostman.png | Bin 0 -> 1534 bytes .../entity/butterflies/lepiRBlueMorpho.png | Bin 0 -> 1543 bytes .../entity/butterflies/lepiReseda.png | Bin 0 -> 1538 bytes .../entity/butterflies/lepiSpeckledWood.png | Bin 0 -> 1553 bytes .../entity/butterflies/lepiSpicebush.png | Bin 0 -> 1549 bytes .../entity/butterflies/lepiSpringAzure.png | Bin 0 -> 1541 bytes .../entity/butterflies/lepiThoasSwallow.png | Bin 0 -> 1554 bytes .../entity/butterflies/lepiZebraSwallow.png | Bin 0 -> 1523 bytes .../textures/entity/butterflies/mothAtlas.png | Bin 0 -> 1544 bytes .../entity/butterflies/mothBrimstone.png | Bin 0 -> 1532 bytes .../entity/butterflies/mothLatticedHeath.png | Bin 0 -> 1556 bytes .../forestry/textures/entity/lumberjack.png | Bin 0 -> 3762 bytes .../assets/forestry/textures/gui/alveary.png | Bin 0 -> 3348 bytes .../assets/forestry/textures/gui/alyzer.png | Bin 0 -> 1995 bytes .../assets/forestry/textures/gui/analyzer.png | Bin 0 -> 1492 bytes .../textures/gui/apiaristinventory.png | Bin 0 -> 2300 bytes .../assets/forestry/textures/gui/apiary.png | Bin 0 -> 3391 bytes .../assets/forestry/textures/gui/atlas.png | Bin 0 -> 14233 bytes .../assets/forestry/textures/gui/backpack.png | Bin 0 -> 1945 bytes .../forestry/textures/gui/backpackT2.png | Bin 0 -> 2201 bytes .../forestry/textures/gui/beealyzer.png | Bin 0 -> 3389 bytes .../forestry/textures/gui/bioengine.png | Bin 0 -> 1722 bytes .../forestry/textures/gui/biomefinder.png | Bin 0 -> 2260 bytes .../assets/forestry/textures/gui/bottler.png | Bin 0 -> 2005 bytes .../assets/forestry/textures/gui/buttons.png | Bin 0 -> 10030 bytes .../forestry/textures/gui/carpenter.png | Bin 0 -> 2393 bytes .../forestry/textures/gui/centrifuge.png | Bin 0 -> 2255 bytes .../textures/gui/electricalengine.png | Bin 0 -> 1847 bytes .../forestry/textures/gui/escritoire.png | Bin 0 -> 3240 bytes .../forestry/textures/gui/fabricator.png | Bin 0 -> 2529 bytes .../forestry/textures/gui/fermenter.png | Bin 0 -> 1935 bytes .../forestry/textures/gui/generator.png | Bin 0 -> 2199 bytes .../forestry/textures/gui/hygroregulator.png | Bin 0 -> 1992 bytes .../forestry/textures/gui/imprinter.png | Bin 0 -> 1299 bytes .../assets/forestry/textures/gui/infuser.png | Bin 0 -> 1193 bytes .../assets/forestry/textures/gui/ledger.png | Bin 0 -> 840 bytes .../assets/forestry/textures/gui/letter.png | Bin 0 -> 2081 bytes .../forestry/textures/gui/mailalert.png | Bin 0 -> 893 bytes .../assets/forestry/textures/gui/mailbox.png | Bin 0 -> 1293 bytes .../forestry/textures/gui/mailtrader.png | Bin 0 -> 1842 bytes .../assets/forestry/textures/gui/mfarm.png | Bin 0 -> 2346 bytes .../forestry/textures/gui/moistener.png | Bin 0 -> 2581 bytes .../forestry/textures/gui/peatengine.png | Bin 0 -> 1912 bytes .../forestry/textures/gui/philatelist.png | Bin 0 -> 2421 bytes .../assets/forestry/textures/gui/raintank.png | Bin 0 -> 2068 bytes .../assets/forestry/textures/gui/sieve.png | Bin 0 -> 2256 bytes .../assets/forestry/textures/gui/solder.png | Bin 0 -> 1397 bytes .../assets/forestry/textures/gui/squeezer.png | Bin 0 -> 4238 bytes .../assets/forestry/textures/gui/still.png | Bin 0 -> 2169 bytes .../assets/forestry/textures/gui/swarmer.png | Bin 0 -> 2157 bytes .../forestry/textures/gui/tradername.png | Bin 0 -> 1980 bytes .../forestry/textures/gui/worktable.png | Bin 0 -> 2120 bytes .../forestry/textures/items/ambrosia.png | Bin 0 -> 423 bytes .../textures/items/analyzer/anything.png | Bin 0 -> 469 bytes .../forestry/textures/items/analyzer/bee.png | Bin 0 -> 454 bytes .../forestry/textures/items/analyzer/cave.png | Bin 0 -> 381 bytes .../textures/items/analyzer/closed.png | Bin 0 -> 455 bytes .../textures/items/analyzer/drone.png | Bin 0 -> 453 bytes .../textures/items/analyzer/flyer.png | Bin 0 -> 366 bytes .../forestry/textures/items/analyzer/item.png | Bin 0 -> 434 bytes .../textures/items/analyzer/nocturnal.png | Bin 0 -> 515 bytes .../textures/items/analyzer/princess.png | Bin 0 -> 469 bytes .../textures/items/analyzer/pure_breed.png | Bin 0 -> 454 bytes .../textures/items/analyzer/pure_cave.png | Bin 0 -> 392 bytes .../textures/items/analyzer/pure_flyer.png | Bin 0 -> 377 bytes .../items/analyzer/pure_nocturnal.png | Bin 0 -> 512 bytes .../textures/items/analyzer/queen.png | Bin 0 -> 473 bytes .../forestry/textures/items/apatite.png | Bin 0 -> 3394 bytes .../forestry/textures/items/apiaristBoots.png | Bin 0 -> 3019 bytes .../forestry/textures/items/apiaristChest.png | Bin 0 -> 3008 bytes .../textures/items/apiaristHelmet.png | Bin 0 -> 3014 bytes .../forestry/textures/items/apiaristLegs.png | Bin 0 -> 3002 bytes .../textures/items/apiarist_armor_1.png | Bin 0 -> 798 bytes .../textures/items/apiarist_armor_2.png | Bin 0 -> 830 bytes .../assets/forestry/textures/items/ash.png | Bin 0 -> 3033 bytes .../textures/items/backpacks/locked.png | Bin 0 -> 2816 bytes .../textures/items/backpacks/neutral.png | Bin 0 -> 2773 bytes .../textures/items/backpacks/receive.png | Bin 0 -> 2792 bytes .../textures/items/backpacks/resupply.png | Bin 0 -> 2787 bytes .../textures/items/backpacks/t1.cloth.png | Bin 0 -> 3048 bytes .../textures/items/backpacks/t1.outline.png | Bin 0 -> 2809 bytes .../textures/items/backpacks/t2.cloth.png | Bin 0 -> 3048 bytes .../textures/items/backpacks/t2.outline.png | Bin 0 -> 2805 bytes .../forestry/textures/items/beeCombs.0.png | Bin 0 -> 3045 bytes .../forestry/textures/items/beeCombs.1.png | Bin 0 -> 3053 bytes .../forestry/textures/items/beealyzer.png | Bin 0 -> 3048 bytes .../textures/items/bees/default/body1.png | Bin 0 -> 419 bytes .../items/bees/default/drone.body2.png | Bin 0 -> 308 bytes .../items/bees/default/drone.body2.png.mcmeta | 1 + .../items/bees/default/drone.body2.txt | 8 + .../items/bees/default/drone.outline.png | Bin 0 -> 366 bytes .../bees/default/drone.outline.png.mcmeta | 1 + .../items/bees/default/drone.outline.txt | 8 + .../items/bees/default/larvae.body.png | Bin 0 -> 412 bytes .../items/bees/default/larvae.body.png.mcmeta | 1 + .../items/bees/default/larvae.body.txt | 5 + .../items/bees/default/larvae.body2.png | Bin 0 -> 425 bytes .../bees/default/larvae.body2.png.mcmeta | 1 + .../items/bees/default/larvae.body2.txt | 5 + .../items/bees/default/larvae.outline.png | Bin 0 -> 403 bytes .../bees/default/larvae.outline.png.mcmeta | 1 + .../items/bees/default/larvae.outline.txt | 5 + .../items/bees/default/princess.body2.png | Bin 0 -> 252 bytes .../bees/default/princess.body2.png.mcmeta | 1 + .../items/bees/default/princess.body2.txt | 8 + .../items/bees/default/princess.outline.png | Bin 0 -> 366 bytes .../bees/default/princess.outline.png.mcmeta | 1 + .../items/bees/default/princess.outline.txt | 8 + .../items/bees/default/queen.body2.png | Bin 0 -> 259 bytes .../items/bees/default/queen.body2.png.mcmeta | 1 + .../items/bees/default/queen.body2.txt | 8 + .../items/bees/default/queen.outline.png | Bin 0 -> 366 bytes .../bees/default/queen.outline.png.mcmeta | 1 + .../items/bees/default/queen.outline.txt | 8 + .../forestry/textures/items/beeswax.png | Bin 0 -> 3043 bytes .../forestry/textures/items/bioMass.png | Bin 0 -> 2938 bytes .../textures/items/biomefinder.mcmeta | 1 + .../forestry/textures/items/biomefinder.png | Bin 0 -> 1239 bytes .../textures/items/biomefinder.png.mcmeta | 1 + .../forestry/textures/items/biomefinder.txt | 0 .../textures/items/biomefinder.txt.mcmeta | 1 + .../textures/items/bituminousPeat.png | Bin 0 -> 3079 bytes .../textures/items/brokenBronzePickaxe.png | Bin 0 -> 3022 bytes .../textures/items/brokenBronzeShovel.png | Bin 0 -> 3015 bytes .../forestry/textures/items/bronzePickaxe.png | Bin 0 -> 3036 bytes .../forestry/textures/items/bronzeShovel.png | Bin 0 -> 3024 bytes .../forestry/textures/items/bucketBiofuel.png | Bin 0 -> 3073 bytes .../forestry/textures/items/bucketBiomass.png | Bin 0 -> 3073 bytes .../assets/forestry/textures/items/carton.png | Bin 0 -> 3002 bytes .../forestry/textures/items/catalogue.png | Bin 0 -> 408 bytes .../textures/items/caterpillar.body.mcmeta | 1 + .../textures/items/caterpillar.body.png | Bin 0 -> 3154 bytes .../items/caterpillar.body.png.mcmeta | 1 + .../textures/items/caterpillar.body.txt | 6 + .../items/caterpillar.body.txt.mcmeta | 1 + .../textures/items/caterpillar.body2.mcmeta | 1 + .../textures/items/caterpillar.body2.png | Bin 0 -> 2893 bytes .../items/caterpillar.body2.png.mcmeta | 1 + .../textures/items/caterpillar.body2.txt | 6 + .../items/caterpillar.body2.txt.mcmeta | 1 + .../forestry/textures/items/chipsets.0.png | Bin 0 -> 3134 bytes .../forestry/textures/items/chipsets.1.png | Bin 0 -> 2978 bytes .../assets/forestry/textures/items/crate.png | Bin 0 -> 3059 bytes .../textures/items/crates/apatite.png | Bin 0 -> 503 bytes .../forestry/textures/items/crates/apples.png | Bin 0 -> 483 bytes .../forestry/textures/items/crates/ash.png | Bin 0 -> 484 bytes .../textures/items/crates/beeswax.png | Bin 0 -> 483 bytes .../textures/items/crates/bogearth.png | Bin 0 -> 487 bytes .../forestry/textures/items/crates/brass.png | Bin 0 -> 494 bytes .../forestry/textures/items/crates/brick.png | Bin 0 -> 549 bytes .../forestry/textures/items/crates/bronze.png | Bin 0 -> 499 bytes .../forestry/textures/items/crates/cacti.png | Bin 0 -> 509 bytes .../textures/items/crates/charcoal.png | Bin 0 -> 522 bytes .../forestry/textures/items/crates/clay.png | Bin 0 -> 483 bytes .../forestry/textures/items/crates/coal.png | Bin 0 -> 522 bytes .../textures/items/crates/cobblestone.png | Bin 0 -> 632 bytes .../textures/items/crates/cocoacomb.png | Bin 0 -> 480 bytes .../textures/items/crates/cookies.png | Bin 0 -> 486 bytes .../forestry/textures/items/crates/copper.png | Bin 0 -> 499 bytes .../forestry/textures/items/crates/dirt.png | Bin 0 -> 504 bytes .../textures/items/crates/drippingcombs.png | Bin 0 -> 478 bytes .../textures/items/crates/fertilizer.png | Bin 0 -> 484 bytes .../textures/items/crates/frozencombs.png | Bin 0 -> 477 bytes .../textures/items/crates/glowstone.png | Bin 0 -> 486 bytes .../forestry/textures/items/crates/gravel.png | Bin 0 -> 483 bytes .../textures/items/crates/honeycombs.png | Bin 0 -> 480 bytes .../textures/items/crates/honeydew.png | Bin 0 -> 480 bytes .../textures/items/crates/honeydrop.png | Bin 0 -> 480 bytes .../forestry/textures/items/crates/humus.png | Bin 0 -> 487 bytes .../forestry/textures/items/crates/iron.png | Bin 0 -> 486 bytes .../forestry/textures/items/crates/lapis.png | Bin 0 -> 491 bytes .../forestry/textures/items/crates/mulch.png | Bin 0 -> 487 bytes .../textures/items/crates/mycelium.png | Bin 0 -> 579 bytes .../textures/items/crates/netherbrick.png | Bin 0 -> 514 bytes .../textures/items/crates/netherrack.png | Bin 0 -> 647 bytes .../textures/items/crates/netherwart.png | Bin 0 -> 479 bytes .../textures/items/crates/nikolite.png | Bin 0 -> 486 bytes .../textures/items/crates/obsidian.png | Bin 0 -> 599 bytes .../forestry/textures/items/crates/peat.png | Bin 0 -> 482 bytes .../textures/items/crates/phosphor.png | Bin 0 -> 484 bytes .../forestry/textures/items/crates/pollen.png | Bin 0 -> 479 bytes .../textures/items/crates/propolis.png | Bin 0 -> 515 bytes .../textures/items/crates/redstone.png | Bin 0 -> 486 bytes .../forestry/textures/items/crates/reeds.png | Bin 0 -> 486 bytes .../textures/items/crates/refractorywax.png | Bin 0 -> 483 bytes .../forestry/textures/items/crates/resin.png | Bin 0 -> 664 bytes .../forestry/textures/items/crates/rubber.png | Bin 0 -> 493 bytes .../forestry/textures/items/crates/sand.png | Bin 0 -> 653 bytes .../textures/items/crates/sandstone.png | Bin 0 -> 683 bytes .../textures/items/crates/saplings.png | Bin 0 -> 478 bytes .../forestry/textures/items/crates/scrap.png | Bin 0 -> 497 bytes .../forestry/textures/items/crates/seeds.png | Bin 0 -> 480 bytes .../textures/items/crates/simmeringcombs.png | Bin 0 -> 480 bytes .../textures/items/crates/soulsand.png | Bin 0 -> 623 bytes .../forestry/textures/items/crates/stone.png | Bin 0 -> 659 bytes .../textures/items/crates/stringycombs.png | Bin 0 -> 480 bytes .../textures/items/crates/tile]-16.png | Bin 0 -> 478 bytes .../forestry/textures/items/crates/tin.png | Bin 0 -> 499 bytes .../forestry/textures/items/crates/uum.png | Bin 0 -> 509 bytes .../forestry/textures/items/crates/wheat.png | Bin 0 -> 508 bytes .../forestry/textures/items/crates/wood.png | Bin 0 -> 529 bytes .../forestry/textures/items/decayingWheat.png | Bin 0 -> 3100 bytes .../textures/items/dissipationCharge.png | Bin 0 -> 3035 bytes .../textures/items/errors/circuitMismatch.png | Bin 0 -> 417 bytes .../textures/items/errors/errored.png | Bin 0 -> 373 bytes .../textures/items/errors/forcedCooldown.png | Bin 0 -> 446 bytes .../textures/items/errors/invalidBiome.png | Bin 0 -> 1043 bytes .../textures/items/errors/isRaining.png | Bin 0 -> 366 bytes .../textures/items/errors/noCircuitBoard.png | Bin 0 -> 524 bytes .../textures/items/errors/noDisposal.png | Bin 0 -> 562 bytes .../textures/items/errors/noDrone.png | Bin 0 -> 434 bytes .../textures/items/errors/noEnergyNet.png | Bin 0 -> 380 bytes .../textures/items/errors/noFarmland.png | Bin 0 -> 418 bytes .../textures/items/errors/noFertilizer.png | Bin 0 -> 421 bytes .../textures/items/errors/noFlower.png | Bin 0 -> 413 bytes .../forestry/textures/items/errors/noFuel.png | Bin 0 -> 421 bytes .../forestry/textures/items/errors/noHeat.png | Bin 0 -> 454 bytes .../textures/items/errors/noHoney.png | Bin 0 -> 405 bytes .../textures/items/errors/noLiquid.png | Bin 0 -> 473 bytes .../textures/items/errors/noQueen.png | Bin 0 -> 452 bytes .../textures/items/errors/noRecipe.png | Bin 0 -> 425 bytes .../textures/items/errors/noRecipient.png | Bin 0 -> 419 bytes .../textures/items/errors/noResource.png | Bin 0 -> 457 bytes .../forestry/textures/items/errors/noSky.png | Bin 0 -> 398 bytes .../textures/items/errors/noSpace.png | Bin 0 -> 489 bytes .../textures/items/errors/noSpecimen.png | Bin 0 -> 434 bytes .../textures/items/errors/noStamps.png | Bin 0 -> 458 bytes .../textures/items/errors/notAlphaNumeric.png | Bin 0 -> 402 bytes .../forestry/textures/items/errors/notDay.png | Bin 0 -> 515 bytes .../textures/items/errors/notGloomy.png | Bin 0 -> 381 bytes .../textures/items/errors/notLucid.png | Bin 0 -> 398 bytes .../textures/items/errors/notNight.png | Bin 0 -> 514 bytes .../textures/items/errors/notPostpaid.png | Bin 0 -> 458 bytes .../textures/items/errors/notRaining.png | Bin 0 -> 393 bytes .../textures/items/errors/notUnique.png | Bin 0 -> 417 bytes .../forestry/textures/items/errors/ok.png | Bin 0 -> 365 bytes .../textures/items/errors/unknown.png | Bin 0 -> 366 bytes .../textures/items/errors/wrongStacksize.png | Bin 0 -> 417 bytes .../forestry/textures/items/fertilizerBio.png | Bin 0 -> 3042 bytes .../textures/items/fertilizerCompound.png | Bin 0 -> 3025 bytes .../forestry/textures/items/flutterlyzer.png | Bin 0 -> 2914 bytes .../textures/items/frameImpregnated.png | Bin 0 -> 3079 bytes .../forestry/textures/items/frameProven.png | Bin 0 -> 3026 bytes .../textures/items/frameUntreated.png | Bin 0 -> 3194 bytes .../forestry/textures/items/fruits/cherry.png | Bin 0 -> 3146 bytes .../textures/items/fruits/chestnut.png | Bin 0 -> 3175 bytes .../forestry/textures/items/fruits/dates.png | Bin 0 -> 694 bytes .../forestry/textures/items/fruits/lemon.png | Bin 0 -> 453 bytes .../forestry/textures/items/fruits/papaya.png | Bin 0 -> 603 bytes .../forestry/textures/items/fruits/plum.png | Bin 0 -> 648 bytes .../forestry/textures/items/fruits/walnut.png | Bin 0 -> 3197 bytes .../forestry/textures/items/gearBronze.png | Bin 0 -> 3084 bytes .../forestry/textures/items/gearCopper.png | Bin 0 -> 3084 bytes .../forestry/textures/items/gearTin.png | Bin 0 -> 3084 bytes .../forestry/textures/items/grafter.png | Bin 0 -> 3060 bytes .../forestry/textures/items/grafterProven.png | Bin 0 -> 2864 bytes .../textures/items/habitats/desert.png | Bin 0 -> 651 bytes .../forestry/textures/items/habitats/end.png | Bin 0 -> 473 bytes .../textures/items/habitats/forest.png | Bin 0 -> 567 bytes .../textures/items/habitats/hills.png | Bin 0 -> 510 bytes .../textures/items/habitats/jungle.png | Bin 0 -> 607 bytes .../textures/items/habitats/mushroom.png | Bin 0 -> 572 bytes .../textures/items/habitats/nether.png | Bin 0 -> 981 bytes .../textures/items/habitats/ocean.png | Bin 0 -> 400 bytes .../textures/items/habitats/plains.png | Bin 0 -> 529 bytes .../forestry/textures/items/habitats/snow.png | Bin 0 -> 434 bytes .../textures/items/habitats/swamp.png | Bin 0 -> 591 bytes .../textures/items/habitats/taiga.png | Bin 0 -> 476 bytes .../textures/items/hardenedMachine.png | Bin 0 -> 3055 bytes .../forestry/textures/items/honeyDrop.0.png | Bin 0 -> 3005 bytes .../forestry/textures/items/honeyDrop.1.png | Bin 0 -> 3005 bytes .../forestry/textures/items/honeyPot.png | Bin 0 -> 3031 bytes .../forestry/textures/items/honeydew.png | Bin 0 -> 2991 bytes .../forestry/textures/items/honeyedSlice.png | Bin 0 -> 3107 bytes .../forestry/textures/items/iceShard.png | Bin 0 -> 3063 bytes .../textures/items/impregnatedCasing.png | Bin 0 -> 3089 bytes .../forestry/textures/items/imprinter.png | Bin 0 -> 3043 bytes .../forestry/textures/items/infuser.png | Bin 0 -> 3133 bytes .../forestry/textures/items/ingotBronze.png | Bin 0 -> 3071 bytes .../forestry/textures/items/ingotCopper.png | Bin 0 -> 3063 bytes .../forestry/textures/items/ingotTin.png | Bin 0 -> 3063 bytes .../forestry/textures/items/iodineCapsule.png | Bin 0 -> 3053 bytes .../forestry/textures/items/kitPickaxe.png | Bin 0 -> 3065 bytes .../forestry/textures/items/kitShovel.png | Bin 0 -> 3063 bytes .../textures/items/liquids/bucket.bottle.png | Bin 0 -> 2862 bytes .../items/liquids/bucket.contents.png | Bin 0 -> 2827 bytes .../textures/items/liquids/can.bottle.png | Bin 0 -> 410 bytes .../textures/items/liquids/can.contents.png | Bin 0 -> 207 bytes .../textures/items/liquids/capsule.bottle.png | Bin 0 -> 410 bytes .../items/liquids/capsule.contents.png | Bin 0 -> 207 bytes .../textures/items/liquids/glass.bottle.png | Bin 0 -> 466 bytes .../textures/items/liquids/glass.contents.png | Bin 0 -> 395 bytes .../textures/items/liquids/jar.bottle.png | Bin 0 -> 417 bytes .../textures/items/liquids/jar.contents.png | Bin 0 -> 204 bytes .../items/liquids/refractory.bottle.png | Bin 0 -> 410 bytes .../items/liquids/refractory.contents.png | Bin 0 -> 207 bytes .../textures/items/mail/carrier.player.png | Bin 0 -> 330 bytes .../textures/items/mail/carrier.trader.png | Bin 0 -> 300 bytes .../textures/items/mail/letter.0.emptied.png | Bin 0 -> 3108 bytes .../textures/items/mail/letter.0.fresh.png | Bin 0 -> 3051 bytes .../textures/items/mail/letter.0.opened.png | Bin 0 -> 3076 bytes .../textures/items/mail/letter.0.stamped.png | Bin 0 -> 3043 bytes .../textures/items/mail/letter.1.emptied.png | Bin 0 -> 3021 bytes .../textures/items/mail/letter.1.fresh.png | Bin 0 -> 3076 bytes .../textures/items/mail/letter.1.opened.png | Bin 0 -> 3019 bytes .../textures/items/mail/letter.1.stamped.png | Bin 0 -> 3078 bytes .../textures/items/mail/letter.2.emptied.png | Bin 0 -> 3077 bytes .../textures/items/mail/letter.2.fresh.png | Bin 0 -> 3032 bytes .../textures/items/mail/letter.2.opened.png | Bin 0 -> 3079 bytes .../textures/items/mail/letter.2.stamped.png | Bin 0 -> 3059 bytes .../textures/items/misc/access.private.png | Bin 0 -> 565 bytes .../textures/items/misc/access.shared.png | Bin 0 -> 574 bytes .../textures/items/misc/access.viewable.png | Bin 0 -> 559 bytes .../forestry/textures/items/misc/energy.png | Bin 0 -> 380 bytes .../forestry/textures/items/misc/hint.png | Bin 0 -> 388 bytes .../forestry/textures/items/mouldyWheat.png | Bin 0 -> 3100 bytes .../assets/forestry/textures/items/mulch.png | Bin 0 -> 3049 bytes .../textures/items/naturalistHelmet.png | Bin 0 -> 488 bytes .../textures/items/naturalist_armor_1.png | Bin 0 -> 838 bytes .../forestry/textures/items/oakStick.png | Bin 0 -> 2991 bytes .../textures/items/particles/ember.png | Bin 0 -> 217 bytes .../textures/items/particles/flame.png | Bin 0 -> 231 bytes .../textures/items/particles/placeholder.png | Bin 0 -> 183 bytes .../textures/items/particles/poison.png | Bin 0 -> 226 bytes .../textures/items/particles/snow.1.png | Bin 0 -> 275 bytes .../textures/items/particles/snow.2.png | Bin 0 -> 299 bytes .../textures/items/particles/snow.3.png | Bin 0 -> 300 bytes .../textures/items/particles/swarm_bee.png | Bin 0 -> 264 bytes .../assets/forestry/textures/items/peat.png | Bin 0 -> 3048 bytes .../forestry/textures/items/phosphor.png | Bin 0 -> 3044 bytes .../forestry/textures/items/pipette.0.png | Bin 0 -> 3047 bytes .../forestry/textures/items/pipette.1.png | Bin 0 -> 3033 bytes .../forestry/textures/items/pollen.0.png | Bin 0 -> 3014 bytes .../forestry/textures/items/pollen.1.png | Bin 0 -> 3062 bytes .../forestry/textures/items/propolis.0.png | Bin 0 -> 3067 bytes .../forestry/textures/items/pulsatingDust.png | Bin 0 -> 3048 bytes .../forestry/textures/items/pulsatingMesh.png | Bin 0 -> 3096 bytes .../forestry/textures/items/refractoryWax.png | Bin 0 -> 3025 bytes .../forestry/textures/items/royalJelly.png | Bin 0 -> 318 bytes .../textures/items/scentedPaneling.png | Bin 0 -> 3038 bytes .../assets/forestry/textures/items/scoop.png | Bin 0 -> 3066 bytes .../forestry/textures/items/silkWisp.png | Bin 0 -> 3021 bytes .../forestry/textures/items/slots/blocked.png | Bin 0 -> 189 bytes .../textures/items/slots/blocked_2.png | Bin 0 -> 193 bytes .../textures/items/slots/container.png | Bin 0 -> 383 bytes .../forestry/textures/items/slots/liquid.png | Bin 0 -> 362 bytes .../forestry/textures/items/slots/locked.png | Bin 0 -> 2816 bytes .../forestry/textures/items/solderingIron.png | Bin 0 -> 3032 bytes .../forestry/textures/items/spectacles.png | Bin 0 -> 488 bytes .../forestry/textures/items/stamps.0.png | Bin 0 -> 3043 bytes .../forestry/textures/items/stamps.1.png | Bin 0 -> 3064 bytes .../forestry/textures/items/sturdyMachine.png | Bin 0 -> 3055 bytes .../textures/items/thermionicTubes.0.png | Bin 0 -> 3029 bytes .../textures/items/thermionicTubes.1.png | Bin 0 -> 3031 bytes .../forestry/textures/items/treealyzer.png | Bin 0 -> 3055 bytes .../textures/items/triggers/hasMail.png | Bin 0 -> 401 bytes .../textures/items/triggers/hasWork.png | Bin 0 -> 408 bytes .../textures/items/triggers/lowFertilizer.png | Bin 0 -> 421 bytes .../textures/items/triggers/lowFuel.png | Bin 0 -> 421 bytes .../textures/items/triggers/lowGermlings.png | Bin 0 -> 437 bytes .../textures/items/triggers/lowInput.png | Bin 0 -> 448 bytes .../textures/items/triggers/lowLiquid.png | Bin 0 -> 472 bytes .../textures/items/triggers/lowPaper.png | Bin 0 -> 433 bytes .../textures/items/triggers/lowResources.png | Bin 0 -> 467 bytes .../textures/items/triggers/lowSoil.png | Bin 0 -> 811 bytes .../textures/items/triggers/lowStamps.png | Bin 0 -> 470 bytes .../textures/items/triggers/mailBuffer.png | Bin 0 -> 478 bytes .../textures/items/triggers/missingDrone.png | Bin 0 -> 434 bytes .../textures/items/triggers/missingQueen.png | Bin 0 -> 452 bytes .../textures/items/triggers/noFrames.png | Bin 0 -> 461 bytes .../forestry/textures/items/vialCatalyst.png | Bin 0 -> 3035 bytes .../forestry/textures/items/waxCast.png | Bin 0 -> 3103 bytes .../forestry/textures/items/woodPulp.png | Bin 0 -> 3049 bytes .../forestry/textures/items/wovenSilk.png | Bin 0 -> 3021 bytes .../assets/forestry/textures/items/wrench.png | Bin 0 -> 3013 bytes .../forestry/textures/unsorted/tile]-10.png | Bin 0 -> 3078 bytes .../forestry/textures/unsorted/tile]-105.png | Bin 0 -> 3058 bytes .../forestry/textures/unsorted/tile]-37.png | Bin 0 -> 3035 bytes .../forestry/textures/unsorted/tile]-88.png | Bin 0 -> 3074 bytes .../forestry/textures/unsorted/tile]-89.png | Bin 0 -> 3058 bytes .../forestry/textures/unsorted/tile]-90.png | Bin 0 -> 3058 bytes forestry_resources/changelog/2.0.0.0 | 31 + forestry_resources/changelog/2.0.0.1 | 16 + forestry_resources/changelog/2.0.0.10 | 11 + forestry_resources/changelog/2.0.0.11 | 9 + forestry_resources/changelog/2.0.0.2 | 12 + forestry_resources/changelog/2.0.0.3 | 15 + forestry_resources/changelog/2.0.0.4 | 24 + forestry_resources/changelog/2.0.0.5 | 4 + forestry_resources/changelog/2.0.0.6 | 10 + forestry_resources/changelog/2.0.0.7 | 4 + forestry_resources/changelog/2.0.0.8 | 14 + forestry_resources/changelog/2.0.0.9 | 7 + forestry_resources/changelog/2.1.0.0 | 5 + forestry_resources/changelog/2.2.0.0 | 25 + forestry_resources/changelog/2.2.0.1 | 11 + forestry_resources/changelog/2.2.0.2 | 10 + forestry_resources/changelog/2.2.2.0 | 9 + forestry_resources/changelog/2.2.2.1 | 11 + forestry_resources/changelog/2.2.2.2 | 8 + forestry_resources/changelog/2.2.4.0 | 11 + forestry_resources/changelog/2.2.4.1 | 8 + forestry_resources/changelog/2.2.4.2 | 7 + forestry_resources/changelog/2.2.4.3 | 9 + forestry_resources/changelog/2.2.6.0 | 11 + forestry_resources/changelog/2.2.6.1 | 8 + forestry_resources/changelog/2.2.6.2 | 7 + forestry_resources/changelog/2.2.6.3 | 10 + forestry_resources/changelog/2.2.8.2 | 14 + forestry_resources/changelog/2.2.8.3 | 17 + forestry_resources/changelog/2.2.8.4 | 9 + forestry_resources/changelog/2.3.0.0 | 6 + forestry_resources/changelog/2.3.0.1 | 10 + forestry_resources/changelog/2.3.0.2 | 3 + forestry_resources/changelog/2.3.0.3 | 5 + forestry_resources/changelog/2.3.0.4 | 14 + forestry_resources/changelog/2.3.0.5 | 9 + forestry_resources/changelog/2.3.0.6 | 9 + forestry_resources/changelog/2.3.0.7 | 13 + forestry_resources/changelog/2.3.1.0 | 11 + forestry_resources/changelog/2.3.1.1 | 14 + forestry_resources/changelog/2.4.0.0 | 4 + .../config/forestry/colour.properties | 46 + .../config/forestry/gamemodes/HARD.conf | 95 ++ .../config/forestry/gamemodes/NORMAL.conf | 96 ++ .../config/forestry/gamemodes/OP.conf | 99 ++ .../config/forestry/hints.properties | 21 + .../lang/forestry/apiculture/en_US.properties | 163 +++ .../forestry/arboriculture/en_US.properties | 69 + .../lang/forestry/core/en_US.properties | 540 ++++++++ .../lang/forestry/farming/en_US.properties | 55 + .../forestry/lepidopterology/en_US.properties | 8 + .../lang/forestry/mail/en_US.properties | 23 + .../lang/forestry/pipes/en_US.properties | 2 + forestry_resources/mcmod.info | 18 + forestry_techne/Bee.java | 131 ++ forestry_techne/Bee1.tcn | Bin 0 -> 885 bytes forestry_techne/Bee2.tcn | Bin 0 -> 1444 bytes forestry_techne/BeeQueen.java | 131 ++ forestry_techne/BeeQueen.png | Bin 0 -> 381 bytes forestry_techne/BeeQueen.tcn | Bin 0 -> 1453 bytes forestry_techne/Butterfly1.tcn | Bin 0 -> 709 bytes forestry_techne/Butterfly2-2.tcn | Bin 0 -> 1332 bytes forestry_techne/Butterfly2.png | Bin 0 -> 396 bytes forestry_techne/Escritoire.java | 123 ++ forestry_techne/Escritoire.png | Bin 0 -> 506 bytes forestry_techne/escritoire.tcn | Bin 0 -> 801 bytes forestry_techne/escritoire2.tcn | Bin 0 -> 796 bytes .../forestry/pipes/EnumFilterType.java | 38 + .../forestry/pipes/GuiHandlerPipes.java | 65 + .../forestry/pipes/PipeIconProvider.java | 40 + .../forestry/pipes/PipeItemsPropolis.java | 160 +++ .../forestry/pipes/PipeLogicPropolis.java | 206 +++ .../pipes/gui/ContainerPropolisPipe.java | 44 + .../forestry/pipes/gui/GuiPropolisPipe.java | 237 ++++ .../pipes/network/PacketHandlerPipes.java | 122 ++ .../pipes/proxy/ClientProxyPipes.java | 34 + .../forestry/pipes/proxy/ProxyPipes.java | 45 + .../forestry/plugins/PluginPropolisPipe.java | 102 ++ 1787 files changed, 97372 insertions(+) create mode 100755 CLA.txt create mode 100755 CONTRIBUTING.md.txt create mode 100755 LICENSE.txt create mode 100755 README.md.txt create mode 100755 build.gradle create mode 100755 build.number create mode 100755 build.xml create mode 100755 forestry_common/apiculture/forestry/apiculture/BeekeepingLogic.java create mode 100755 forestry_common/apiculture/forestry/apiculture/CommandBeekeepingMode.java create mode 100755 forestry_common/apiculture/forestry/apiculture/CommandGiveBee.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderCacti.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderEnd.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderGourd.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderJungle.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderMushroom.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderNetherwart.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderVanilla.java create mode 100755 forestry_common/apiculture/forestry/apiculture/FlowerProviderWheat.java create mode 100755 forestry_common/apiculture/forestry/apiculture/GuiHandlerApiculture.java create mode 100755 forestry_common/apiculture/forestry/apiculture/MaterialBeehive.java create mode 100755 forestry_common/apiculture/forestry/apiculture/PacketHandlerApiculture.java create mode 100755 forestry_common/apiculture/forestry/apiculture/SaveEventHandlerApiculture.java create mode 100755 forestry_common/apiculture/forestry/apiculture/SpeciesNotFoundException.java create mode 100755 forestry_common/apiculture/forestry/apiculture/TemplateNotFoundException.java create mode 100755 forestry_common/apiculture/forestry/apiculture/VillageHandlerApiculture.java create mode 100755 forestry_common/apiculture/forestry/apiculture/entities/EntityBee.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/BlockAlveary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/BlockBeehives.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/BlockCandle.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/BlockStump.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/StructureLogicAlveary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlveary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyClimatiser.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyFan.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHeater.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyPlain.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySieve.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyStabiliser.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySwarmer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileApiaristChest.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileApiary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileBeehouse.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileCandle.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gadgets/TileSwarm.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AIAvoidPlayers.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleBeeSpecies.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectAggressive.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectCreeper.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectExploration.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectGlacial.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectHeroic.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectIgnition.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMiasmic.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMisanthrope.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectNone.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectPotion.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRadioactive.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRepulsion.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectResurrection.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectSnowing.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectThrottled.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/AlleleFlowers.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/ApiaristTracker.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/Bee.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/BeeGenome.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/BeeHelper.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/BeeMutation.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/BeeTemplates.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/BeekeepingMode.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/BranchBees.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/HiveDrop.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/IJubilanceProvider.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/JubilanceDefault.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/JubilanceNone.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/JubilanceProviderHermit.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/JubilanceReqRes.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/MutationEMC.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/MutationReqRes.java create mode 100755 forestry_common/apiculture/forestry/apiculture/genetics/MutationTimeLimited.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerAlveary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearyHygroregulator.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySieve.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySwarmer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerApiary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerBeealyzer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerHabitatLocator.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/ContainerImprinter.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiAlveary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearyHygroregulator.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySieve.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySwarmer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiApiary.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiBeealyzer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiHabitatLocator.java create mode 100755 forestry_common/apiculture/forestry/apiculture/gui/GuiImprinter.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemAlvearyBlock.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemArmorApiarist.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemBeeGE.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemBeealyzer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemBiomefinder.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemCandleBlock.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemHiveFrame.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemHoneycomb.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemImprinter.java create mode 100755 forestry_common/apiculture/forestry/apiculture/items/ItemWaxCast.java create mode 100755 forestry_common/apiculture/forestry/apiculture/proxy/ClientProxyApiculture.java create mode 100755 forestry_common/apiculture/forestry/apiculture/proxy/ProxyApiculture.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/BeeItemRenderer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/BlockCandleRenderer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/EntityBeeFX.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/ModelAnalyzer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/ModelBee.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/ParticleRenderer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/RenderBee.java create mode 100755 forestry_common/apiculture/forestry/apiculture/render/TextureBiomefinder.java create mode 100755 forestry_common/apiculture/forestry/apiculture/trigger/TriggerNoFrames.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/ComponentVillageBeeHouse.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/HiveDecorator.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHive.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveEnd.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveForest.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveJungle.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveMeadows.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveParched.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSnow.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamer.java create mode 100755 forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamp.java create mode 100755 forestry_common/apiculture/forestry/plugins/PluginApiculture.java create mode 100755 forestry_common/apiculture/forestry/plugins/PluginEE.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/CommandSpawnForest.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/CommandSpawnTree.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/CommandTreekeepingMode.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/EventHandlerArboriculture.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/FruitProviderNone.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/FruitProviderPod.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/FruitProviderRandom.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/FruitProviderRipening.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/GuiHandlerArboriculture.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/IWoodTyped.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/PacketHandlerArboriculture.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/VillageHandlerArboriculture.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/WoodType.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/WorldGenHelper.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbFence.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbStairs.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockFruitPod.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLeaves.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLog.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockPlanks.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSapling.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSlab.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockTreeContainer.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/TileArboristChest.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/TileFruitPod.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/TileLeaves.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/TileSapling.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/TileStairs.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gadgets/TileTreeContainer.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleFruit.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleGrowth.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleLeafEffectNone.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleTreeSpecies.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/ArboristTracker.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/BranchTrees.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProvider.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProviderTropical.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/Tree.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/TreeGenome.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/TreeHelper.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/TreeMutation.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/TreeTemplates.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/genetics/TreekeepingMode.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gui/ContainerTreealyzer.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/gui/GuiTreealyzer.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/items/ItemGermlingGE.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/items/ItemGrafter.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/items/ItemStairs.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/items/ItemTreealyzer.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/items/ItemWoodBlock.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/network/PacketLeafUpdate.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/proxy/ClientProxyArboriculture.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/proxy/ProxyArboriculture.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/render/FenceRenderingHandler.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/render/FruitPodRenderingHandler.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/render/LeavesRenderingHandler.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/render/SaplingRenderHandler.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/render/StairItemRenderer.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeLeaf.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeVoid.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenAcacia.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenArboriculture.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBalsa.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBaobab.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBirch.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenCherry.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenChestnut.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenDate.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenEbony.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGiganteum.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGreenheart.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenJungle.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenKapok.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLarch.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLemon.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLime.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahoe.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahogany.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMaple.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenOak.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPapaya.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPine.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPlum.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPoplar.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSequoia.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSpruce.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTeak.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTree.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWalnut.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWenge.java create mode 100755 forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWillow.java create mode 100755 forestry_common/arboriculture/forestry/plugins/PluginArboriculture.java create mode 100755 forestry_common/core/forestry/Forestry.java create mode 100755 forestry_common/core/forestry/api/apiculture/BeeManager.java create mode 100755 forestry_common/core/forestry/api/apiculture/EnumBeeChromosome.java create mode 100755 forestry_common/core/forestry/api/apiculture/EnumBeeType.java create mode 100755 forestry_common/core/forestry/api/apiculture/FlowerManager.java create mode 100755 forestry_common/core/forestry/api/apiculture/IAlleleBeeEffect.java create mode 100755 forestry_common/core/forestry/api/apiculture/IAlleleBeeSpecies.java create mode 100755 forestry_common/core/forestry/api/apiculture/IAlvearyComponent.java create mode 100755 forestry_common/core/forestry/api/apiculture/IApiaristTracker.java create mode 100755 forestry_common/core/forestry/api/apiculture/IArmorApiarist.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBee.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeeGenome.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeeHousing.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeeListener.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeeModifier.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeeMutation.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeeRoot.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeekeepingLogic.java create mode 100755 forestry_common/core/forestry/api/apiculture/IBeekeepingMode.java create mode 100755 forestry_common/core/forestry/api/apiculture/IHiveDrop.java create mode 100755 forestry_common/core/forestry/api/apiculture/IHiveFrame.java create mode 100755 forestry_common/core/forestry/api/apiculture/package-info.java create mode 100755 forestry_common/core/forestry/api/arboriculture/EnumGermlingType.java create mode 100755 forestry_common/core/forestry/api/arboriculture/EnumGrowthConditions.java create mode 100755 forestry_common/core/forestry/api/arboriculture/EnumTreeChromosome.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IAlleleFruit.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IAlleleGrowth.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IAlleleLeafEffect.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IAlleleTreeSpecies.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IArboristTracker.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IFruitProvider.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IGrowthProvider.java create mode 100755 forestry_common/core/forestry/api/arboriculture/ILeafTickHandler.java create mode 100755 forestry_common/core/forestry/api/arboriculture/IToolGrafter.java create mode 100755 forestry_common/core/forestry/api/arboriculture/ITree.java create mode 100755 forestry_common/core/forestry/api/arboriculture/ITreeGenome.java create mode 100755 forestry_common/core/forestry/api/arboriculture/ITreeModifier.java create mode 100755 forestry_common/core/forestry/api/arboriculture/ITreeMutation.java create mode 100755 forestry_common/core/forestry/api/arboriculture/ITreeRoot.java create mode 100755 forestry_common/core/forestry/api/arboriculture/ITreekeepingMode.java create mode 100755 forestry_common/core/forestry/api/arboriculture/TreeManager.java create mode 100755 forestry_common/core/forestry/api/arboriculture/package-info.java create mode 100755 forestry_common/core/forestry/api/circuits/ChipsetManager.java create mode 100755 forestry_common/core/forestry/api/circuits/ICircuit.java create mode 100755 forestry_common/core/forestry/api/circuits/ICircuitBoard.java create mode 100755 forestry_common/core/forestry/api/circuits/ICircuitLayout.java create mode 100755 forestry_common/core/forestry/api/circuits/ICircuitLibrary.java create mode 100755 forestry_common/core/forestry/api/circuits/ICircuitRegistry.java create mode 100755 forestry_common/core/forestry/api/circuits/ISolderManager.java create mode 100755 forestry_common/core/forestry/api/circuits/package-info.java create mode 100755 forestry_common/core/forestry/api/core/BlockInterface.java create mode 100755 forestry_common/core/forestry/api/core/EnumHumidity.java create mode 100755 forestry_common/core/forestry/api/core/EnumTemperature.java create mode 100755 forestry_common/core/forestry/api/core/ForestryAPI.java create mode 100755 forestry_common/core/forestry/api/core/ForestryEvent.java create mode 100755 forestry_common/core/forestry/api/core/IArmorNaturalist.java create mode 100755 forestry_common/core/forestry/api/core/IForestryConstants.java create mode 100755 forestry_common/core/forestry/api/core/IGameMode.java create mode 100755 forestry_common/core/forestry/api/core/IIconProvider.java create mode 100755 forestry_common/core/forestry/api/core/INBTTagable.java create mode 100755 forestry_common/core/forestry/api/core/IPlugin.java create mode 100755 forestry_common/core/forestry/api/core/IStructureLogic.java create mode 100755 forestry_common/core/forestry/api/core/ITextureManager.java create mode 100755 forestry_common/core/forestry/api/core/ITileStructure.java create mode 100755 forestry_common/core/forestry/api/core/IToolScoop.java create mode 100755 forestry_common/core/forestry/api/core/ItemInterface.java create mode 100755 forestry_common/core/forestry/api/core/PluginInfo.java create mode 100755 forestry_common/core/forestry/api/core/Tabs.java create mode 100755 forestry_common/core/forestry/api/core/package-info.java create mode 100755 forestry_common/core/forestry/api/farming/Farmables.java create mode 100755 forestry_common/core/forestry/api/farming/ICrop.java create mode 100755 forestry_common/core/forestry/api/farming/IFarmComponent.java create mode 100755 forestry_common/core/forestry/api/farming/IFarmHousing.java create mode 100755 forestry_common/core/forestry/api/farming/IFarmInterface.java create mode 100755 forestry_common/core/forestry/api/farming/IFarmListener.java create mode 100755 forestry_common/core/forestry/api/farming/IFarmLogic.java create mode 100755 forestry_common/core/forestry/api/farming/IFarmable.java create mode 100755 forestry_common/core/forestry/api/farming/package-info.java create mode 100755 forestry_common/core/forestry/api/food/BeverageManager.java create mode 100755 forestry_common/core/forestry/api/food/IBeverageEffect.java create mode 100755 forestry_common/core/forestry/api/food/IInfuserManager.java create mode 100755 forestry_common/core/forestry/api/food/IIngredientManager.java create mode 100755 forestry_common/core/forestry/api/food/package-info.java create mode 100755 forestry_common/core/forestry/api/fuels/EngineBronzeFuel.java create mode 100755 forestry_common/core/forestry/api/fuels/EngineCopperFuel.java create mode 100755 forestry_common/core/forestry/api/fuels/FermenterFuel.java create mode 100755 forestry_common/core/forestry/api/fuels/FuelManager.java create mode 100755 forestry_common/core/forestry/api/fuels/GeneratorFuel.java create mode 100755 forestry_common/core/forestry/api/fuels/MoistenerFuel.java create mode 100755 forestry_common/core/forestry/api/fuels/RainSubstrate.java create mode 100755 forestry_common/core/forestry/api/fuels/package-info.java create mode 100755 forestry_common/core/forestry/api/genetics/AlleleManager.java create mode 100755 forestry_common/core/forestry/api/genetics/EnumTolerance.java create mode 100755 forestry_common/core/forestry/api/genetics/IAllele.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleArea.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleBoolean.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleEffect.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleFloat.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleFlowers.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleHandler.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleInteger.java create mode 100755 forestry_common/core/forestry/api/genetics/IAllelePlantType.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleRegistry.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleSpecies.java create mode 100755 forestry_common/core/forestry/api/genetics/IAlleleTolerance.java create mode 100755 forestry_common/core/forestry/api/genetics/IBreedingTracker.java create mode 100755 forestry_common/core/forestry/api/genetics/IChromosome.java create mode 100755 forestry_common/core/forestry/api/genetics/IChromosomeType.java create mode 100755 forestry_common/core/forestry/api/genetics/IClassification.java create mode 100755 forestry_common/core/forestry/api/genetics/IEffectData.java create mode 100755 forestry_common/core/forestry/api/genetics/IFlowerProvider.java create mode 100755 forestry_common/core/forestry/api/genetics/IFruitBearer.java create mode 100755 forestry_common/core/forestry/api/genetics/IFruitFamily.java create mode 100755 forestry_common/core/forestry/api/genetics/IGenome.java create mode 100755 forestry_common/core/forestry/api/genetics/IHousing.java create mode 100755 forestry_common/core/forestry/api/genetics/IIndividual.java create mode 100755 forestry_common/core/forestry/api/genetics/IIndividualLiving.java create mode 100755 forestry_common/core/forestry/api/genetics/ILegacyHandler.java create mode 100755 forestry_common/core/forestry/api/genetics/IMutation.java create mode 100755 forestry_common/core/forestry/api/genetics/IPollinatable.java create mode 100755 forestry_common/core/forestry/api/genetics/ISpeciesRoot.java create mode 100755 forestry_common/core/forestry/api/genetics/package-info.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/EnumButterflyChromosome.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/EnumFlutterType.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IAlleleButterflyEffect.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IAlleleButterflySpecies.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IButterfly.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IButterflyGenome.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IButterflyMutation.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IButterflyNursery.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IButterflyRoot.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/IEntityButterfly.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/ILepidopteristTracker.java create mode 100755 forestry_common/core/forestry/api/lepidopterology/package-info.java create mode 100755 forestry_common/core/forestry/api/mail/EnumPostage.java create mode 100755 forestry_common/core/forestry/api/mail/ILetter.java create mode 100755 forestry_common/core/forestry/api/mail/ILetterHandler.java create mode 100755 forestry_common/core/forestry/api/mail/IPostOffice.java create mode 100755 forestry_common/core/forestry/api/mail/IPostRegistry.java create mode 100755 forestry_common/core/forestry/api/mail/IPostalCarrier.java create mode 100755 forestry_common/core/forestry/api/mail/IPostalState.java create mode 100755 forestry_common/core/forestry/api/mail/IStamps.java create mode 100755 forestry_common/core/forestry/api/mail/ITradeStation.java create mode 100755 forestry_common/core/forestry/api/mail/MailAddress.java create mode 100755 forestry_common/core/forestry/api/mail/PostManager.java create mode 100755 forestry_common/core/forestry/api/mail/TradeStationInfo.java create mode 100755 forestry_common/core/forestry/api/mail/package-info.java create mode 100755 forestry_common/core/forestry/api/package-info.java create mode 100755 forestry_common/core/forestry/api/recipes/IBottlerManager.java create mode 100755 forestry_common/core/forestry/api/recipes/ICarpenterManager.java create mode 100755 forestry_common/core/forestry/api/recipes/ICentrifugeManager.java create mode 100755 forestry_common/core/forestry/api/recipes/ICraftingProvider.java create mode 100755 forestry_common/core/forestry/api/recipes/IFabricatorManager.java create mode 100755 forestry_common/core/forestry/api/recipes/IFermenterManager.java create mode 100755 forestry_common/core/forestry/api/recipes/IGenericCrate.java create mode 100755 forestry_common/core/forestry/api/recipes/IMoistenerManager.java create mode 100755 forestry_common/core/forestry/api/recipes/ISqueezerManager.java create mode 100755 forestry_common/core/forestry/api/recipes/IStillManager.java create mode 100755 forestry_common/core/forestry/api/recipes/IVariableFermentable.java create mode 100755 forestry_common/core/forestry/api/recipes/RecipeManagers.java create mode 100755 forestry_common/core/forestry/api/recipes/package-info.java create mode 100755 forestry_common/core/forestry/api/storage/BackpackEvent.java create mode 100755 forestry_common/core/forestry/api/storage/BackpackManager.java create mode 100755 forestry_common/core/forestry/api/storage/BackpackResupplyEvent.java create mode 100755 forestry_common/core/forestry/api/storage/BackpackStowEvent.java create mode 100755 forestry_common/core/forestry/api/storage/EnumBackpackType.java create mode 100755 forestry_common/core/forestry/api/storage/IBackpackDefinition.java create mode 100755 forestry_common/core/forestry/api/storage/IBackpackInterface.java create mode 100755 forestry_common/core/forestry/api/storage/package-info.java create mode 100755 forestry_common/core/forestry/api/world/ITreeGenData.java create mode 100755 forestry_common/core/forestry/api/world/IWorldGenInterface.java create mode 100755 forestry_common/core/forestry/api/world/WorldGenManager.java create mode 100755 forestry_common/core/forestry/api/world/package-info.java create mode 100755 forestry_common/core/forestry/core/CommandForestry.java create mode 100755 forestry_common/core/forestry/core/CreativeTabForestry.java create mode 100755 forestry_common/core/forestry/core/EnumErrorCode.java create mode 100755 forestry_common/core/forestry/core/EventHandlerCore.java create mode 100755 forestry_common/core/forestry/core/ForestryClient.java create mode 100755 forestry_common/core/forestry/core/ForestryConstants.java create mode 100755 forestry_common/core/forestry/core/ForestryCore.java create mode 100755 forestry_common/core/forestry/core/GameMode.java create mode 100755 forestry_common/core/forestry/core/GuiHandler.java create mode 100755 forestry_common/core/forestry/core/GuiHandlerBase.java create mode 100755 forestry_common/core/forestry/core/PickupHandlerCore.java create mode 100755 forestry_common/core/forestry/core/SaveEventHandlerCore.java create mode 100755 forestry_common/core/forestry/core/TemperatureState.java create mode 100755 forestry_common/core/forestry/core/TickHandlerCoreClient.java create mode 100755 forestry_common/core/forestry/core/TickHandlerCoreServer.java create mode 100755 forestry_common/core/forestry/core/WorldGenerator.java create mode 100755 forestry_common/core/forestry/core/circuits/Circuit.java create mode 100755 forestry_common/core/forestry/core/circuits/CircuitBoard.java create mode 100755 forestry_common/core/forestry/core/circuits/CircuitBoardManager.java create mode 100755 forestry_common/core/forestry/core/circuits/CircuitId.java create mode 100755 forestry_common/core/forestry/core/circuits/CircuitLayout.java create mode 100755 forestry_common/core/forestry/core/circuits/CircuitLibrary.java create mode 100755 forestry_common/core/forestry/core/circuits/CircuitRegistry.java create mode 100755 forestry_common/core/forestry/core/circuits/ContainerSolderingIron.java create mode 100755 forestry_common/core/forestry/core/circuits/EnumCircuitBoardType.java create mode 100755 forestry_common/core/forestry/core/circuits/GuiSolderingIron.java create mode 100755 forestry_common/core/forestry/core/circuits/ISolderingIron.java create mode 100755 forestry_common/core/forestry/core/circuits/ItemCircuitBoard.java create mode 100755 forestry_common/core/forestry/core/circuits/ItemSolderingIron.java create mode 100755 forestry_common/core/forestry/core/config/Config.java create mode 100755 forestry_common/core/forestry/core/config/Configuration.java create mode 100755 forestry_common/core/forestry/core/config/Defaults.java create mode 100755 forestry_common/core/forestry/core/config/ForestryBlock.java create mode 100755 forestry_common/core/forestry/core/config/ForestryItem.java create mode 100755 forestry_common/core/forestry/core/config/Property.java create mode 100755 forestry_common/core/forestry/core/config/SessionVars.java create mode 100755 forestry_common/core/forestry/core/config/Version.java create mode 100755 forestry_common/core/forestry/core/gadgets/BlockBase.java create mode 100755 forestry_common/core/forestry/core/gadgets/BlockForestry.java create mode 100755 forestry_common/core/forestry/core/gadgets/BlockResource.java create mode 100755 forestry_common/core/forestry/core/gadgets/BlockSoil.java create mode 100755 forestry_common/core/forestry/core/gadgets/BlockStainedGlass.java create mode 100755 forestry_common/core/forestry/core/gadgets/BlockStructure.java create mode 100755 forestry_common/core/forestry/core/gadgets/Engine.java create mode 100755 forestry_common/core/forestry/core/gadgets/IStructureBlockItem.java create mode 100755 forestry_common/core/forestry/core/gadgets/MachineDefinition.java create mode 100755 forestry_common/core/forestry/core/gadgets/MachineNBTDefinition.java create mode 100755 forestry_common/core/forestry/core/gadgets/Mill.java create mode 100755 forestry_common/core/forestry/core/gadgets/NaturalistGame.java create mode 100755 forestry_common/core/forestry/core/gadgets/StructureLogic.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileAnalyzer.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileBase.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileEngine.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileEscritoire.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileForestry.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileMachine.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileMill.java create mode 100755 forestry_common/core/forestry/core/gadgets/TileNaturalistChest.java create mode 100755 forestry_common/core/forestry/core/gadgets/TilePowered.java create mode 100755 forestry_common/core/forestry/core/genetics/Allele.java create mode 100755 forestry_common/core/forestry/core/genetics/AlleleArea.java create mode 100755 forestry_common/core/forestry/core/genetics/AlleleBoolean.java create mode 100755 forestry_common/core/forestry/core/genetics/AlleleFloat.java create mode 100755 forestry_common/core/forestry/core/genetics/AlleleInteger.java create mode 100755 forestry_common/core/forestry/core/genetics/AllelePlantType.java create mode 100755 forestry_common/core/forestry/core/genetics/AlleleRegistry.java create mode 100755 forestry_common/core/forestry/core/genetics/AlleleSpecies.java create mode 100755 forestry_common/core/forestry/core/genetics/AlleleTolerance.java create mode 100755 forestry_common/core/forestry/core/genetics/Branch.java create mode 100755 forestry_common/core/forestry/core/genetics/BreedingTracker.java create mode 100755 forestry_common/core/forestry/core/genetics/Chromosome.java create mode 100755 forestry_common/core/forestry/core/genetics/Classification.java create mode 100755 forestry_common/core/forestry/core/genetics/ClimateHelper.java create mode 100755 forestry_common/core/forestry/core/genetics/EffectData.java create mode 100755 forestry_common/core/forestry/core/genetics/EnumMutateChance.java create mode 100755 forestry_common/core/forestry/core/genetics/FruitFamily.java create mode 100755 forestry_common/core/forestry/core/genetics/GenericRatings.java create mode 100755 forestry_common/core/forestry/core/genetics/Genome.java create mode 100755 forestry_common/core/forestry/core/genetics/Individual.java create mode 100755 forestry_common/core/forestry/core/genetics/IndividualLiving.java create mode 100755 forestry_common/core/forestry/core/genetics/ItemGE.java create mode 100755 forestry_common/core/forestry/core/genetics/ItemResearchNote.java create mode 100755 forestry_common/core/forestry/core/genetics/Mutation.java create mode 100755 forestry_common/core/forestry/core/genetics/SpeciesRoot.java create mode 100755 forestry_common/core/forestry/core/gui/ClimateLedger.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerAnalyzer.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerDummy.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerEscritoire.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerForestry.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerItemInventory.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerLiquidTanks.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerNaturalistInventory.java create mode 100755 forestry_common/core/forestry/core/gui/ContainerSocketed.java create mode 100755 forestry_common/core/forestry/core/gui/ErrorLedger.java create mode 100755 forestry_common/core/forestry/core/gui/GuiAlyzer.java create mode 100755 forestry_common/core/forestry/core/gui/GuiAnalyzer.java create mode 100755 forestry_common/core/forestry/core/gui/GuiEscritoire.java create mode 100755 forestry_common/core/forestry/core/gui/GuiForestry.java create mode 100755 forestry_common/core/forestry/core/gui/GuiNaturalistInventory.java create mode 100755 forestry_common/core/forestry/core/gui/GuiTextBox.java create mode 100755 forestry_common/core/forestry/core/gui/HintLedger.java create mode 100755 forestry_common/core/forestry/core/gui/IGuiSelectable.java create mode 100755 forestry_common/core/forestry/core/gui/IPagedInventory.java create mode 100755 forestry_common/core/forestry/core/gui/Ledger.java create mode 100755 forestry_common/core/forestry/core/gui/LedgerManager.java create mode 100755 forestry_common/core/forestry/core/gui/OwnerLedger.java create mode 100755 forestry_common/core/forestry/core/gui/PlainLedger.java create mode 100755 forestry_common/core/forestry/core/gui/PowerLedger.java create mode 100755 forestry_common/core/forestry/core/gui/WidgetManager.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/ButtonTextureSet.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/GuiBetterButton.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/GuiButtonSmall.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/GuiMultiButton.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/GuiToggleButton.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/GuiToggleButtonSmall.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/IButtonTextureSet.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/IMultiButtonState.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/LockButtonState.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/MultiButtonController.java create mode 100755 forestry_common/core/forestry/core/gui/buttons/StandardButtonTextureSets.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotClosed.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotCraftAuto.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotCrafter.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotCustom.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotForestry.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotItemInventory.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotLiquidContainer.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotLocked.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotOutput.java create mode 100755 forestry_common/core/forestry/core/gui/slots/SlotWorking.java create mode 100755 forestry_common/core/forestry/core/gui/tooltips/IToolTipProvider.java create mode 100755 forestry_common/core/forestry/core/gui/tooltips/ToolTip.java create mode 100755 forestry_common/core/forestry/core/gui/tooltips/ToolTipLine.java create mode 100755 forestry_common/core/forestry/core/gui/widgets/ReservoirWidget.java create mode 100755 forestry_common/core/forestry/core/gui/widgets/SocketWidget.java create mode 100755 forestry_common/core/forestry/core/gui/widgets/TankWidget.java create mode 100755 forestry_common/core/forestry/core/gui/widgets/Widget.java create mode 100755 forestry_common/core/forestry/core/interfaces/IBlockRenderer.java create mode 100755 forestry_common/core/forestry/core/interfaces/IClimatised.java create mode 100755 forestry_common/core/forestry/core/interfaces/IContainerCrafting.java create mode 100755 forestry_common/core/forestry/core/interfaces/ICrafter.java create mode 100755 forestry_common/core/forestry/core/interfaces/ICraftingPlan.java create mode 100755 forestry_common/core/forestry/core/interfaces/IDescriptiveRecipe.java create mode 100755 forestry_common/core/forestry/core/interfaces/IErrorSource.java create mode 100755 forestry_common/core/forestry/core/interfaces/IHintSource.java create mode 100755 forestry_common/core/forestry/core/interfaces/IInventoriedItem.java create mode 100755 forestry_common/core/forestry/core/interfaces/ILiquidTankContainer.java create mode 100755 forestry_common/core/forestry/core/interfaces/IOreDictionaryHandler.java create mode 100755 forestry_common/core/forestry/core/interfaces/IOwnable.java create mode 100755 forestry_common/core/forestry/core/interfaces/IPacketHandler.java create mode 100755 forestry_common/core/forestry/core/interfaces/IPickupHandler.java create mode 100755 forestry_common/core/forestry/core/interfaces/IPowerHandler.java create mode 100755 forestry_common/core/forestry/core/interfaces/IRenderableMachine.java create mode 100755 forestry_common/core/forestry/core/interfaces/IResupplyHandler.java create mode 100755 forestry_common/core/forestry/core/interfaces/ISaveEventHandler.java create mode 100755 forestry_common/core/forestry/core/interfaces/ISocketable.java create mode 100755 forestry_common/core/forestry/core/inventory/ITileFilter.java create mode 100755 forestry_common/core/forestry/core/inventory/InvTools.java create mode 100755 forestry_common/core/forestry/core/inventory/InventoryConcatenator.java create mode 100755 forestry_common/core/forestry/core/inventory/InventorySorter.java create mode 100755 forestry_common/core/forestry/core/inventory/ItemStackMap.java create mode 100755 forestry_common/core/forestry/core/inventory/ItemStackSet.java create mode 100755 forestry_common/core/forestry/core/inventory/ItemStackSizeSorter.java create mode 100755 forestry_common/core/forestry/core/inventory/filters/ArrayStackFilter.java create mode 100755 forestry_common/core/forestry/core/inventory/filters/IStackFilter.java create mode 100755 forestry_common/core/forestry/core/inventory/filters/InvertedStackFilter.java create mode 100755 forestry_common/core/forestry/core/inventory/filters/StackFilter.java create mode 100755 forestry_common/core/forestry/core/inventory/manipulators/InventoryManipulator.java create mode 100755 forestry_common/core/forestry/core/inventory/manipulators/SpecialManipulator.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/ChestWrapper.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/IInvSlot.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/InventoryCopy.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/InventoryIterator.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/InventoryMapper.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryIterator.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryMapper.java create mode 100755 forestry_common/core/forestry/core/inventory/wrappers/SpecialInventoryMapper.java create mode 100755 forestry_common/core/forestry/core/items/ItemArmorNaturalist.java create mode 100755 forestry_common/core/forestry/core/items/ItemAssemblyKit.java create mode 100755 forestry_common/core/forestry/core/items/ItemCrated.java create mode 100755 forestry_common/core/forestry/core/items/ItemForestry.java create mode 100755 forestry_common/core/forestry/core/items/ItemForestryBlock.java create mode 100755 forestry_common/core/forestry/core/items/ItemForestryFood.java create mode 100755 forestry_common/core/forestry/core/items/ItemForestryPickaxe.java create mode 100755 forestry_common/core/forestry/core/items/ItemForestryShovel.java create mode 100755 forestry_common/core/forestry/core/items/ItemForestryTool.java create mode 100755 forestry_common/core/forestry/core/items/ItemFruit.java create mode 100755 forestry_common/core/forestry/core/items/ItemInventoried.java create mode 100755 forestry_common/core/forestry/core/items/ItemLiquidContainer.java create mode 100755 forestry_common/core/forestry/core/items/ItemLiquids.java create mode 100755 forestry_common/core/forestry/core/items/ItemMisc.java create mode 100755 forestry_common/core/forestry/core/items/ItemNBTTile.java create mode 100755 forestry_common/core/forestry/core/items/ItemOverlay.java create mode 100755 forestry_common/core/forestry/core/items/ItemPipette.java create mode 100755 forestry_common/core/forestry/core/items/ItemScoop.java create mode 100755 forestry_common/core/forestry/core/items/ItemWrench.java create mode 100755 forestry_common/core/forestry/core/network/ClassMap.java create mode 100755 forestry_common/core/forestry/core/network/EntityNetData.java create mode 100755 forestry_common/core/forestry/core/network/ForestryPacket.java create mode 100755 forestry_common/core/forestry/core/network/GuiId.java create mode 100755 forestry_common/core/forestry/core/network/ILocatedPacket.java create mode 100755 forestry_common/core/forestry/core/network/INetworkedEntity.java create mode 100755 forestry_common/core/forestry/core/network/IndexInPayload.java create mode 100755 forestry_common/core/forestry/core/network/PacketCoordinates.java create mode 100755 forestry_common/core/forestry/core/network/PacketFXSignal.java create mode 100755 forestry_common/core/forestry/core/network/PacketHandler.java create mode 100755 forestry_common/core/forestry/core/network/PacketIds.java create mode 100755 forestry_common/core/forestry/core/network/PacketInventoryStack.java create mode 100755 forestry_common/core/forestry/core/network/PacketNBT.java create mode 100755 forestry_common/core/forestry/core/network/PacketPayload.java create mode 100755 forestry_common/core/forestry/core/network/PacketSocketUpdate.java create mode 100755 forestry_common/core/forestry/core/network/PacketTankUpdate.java create mode 100755 forestry_common/core/forestry/core/network/PacketTileNBT.java create mode 100755 forestry_common/core/forestry/core/network/PacketTileUpdate.java create mode 100755 forestry_common/core/forestry/core/network/PacketUpdate.java create mode 100755 forestry_common/core/forestry/core/proxy/ClientProxyCommon.java create mode 100755 forestry_common/core/forestry/core/proxy/ClientProxyNetwork.java create mode 100755 forestry_common/core/forestry/core/proxy/ClientProxyRender.java create mode 100755 forestry_common/core/forestry/core/proxy/Proxies.java create mode 100755 forestry_common/core/forestry/core/proxy/ProxyCommon.java create mode 100755 forestry_common/core/forestry/core/proxy/ProxyLog.java create mode 100755 forestry_common/core/forestry/core/proxy/ProxyNetwork.java create mode 100755 forestry_common/core/forestry/core/proxy/ProxyRender.java create mode 100755 forestry_common/core/forestry/core/render/BlockRenderingHandler.java create mode 100755 forestry_common/core/forestry/core/render/EntityBiodustFX.java create mode 100755 forestry_common/core/forestry/core/render/EntityHoneydustFX.java create mode 100755 forestry_common/core/forestry/core/render/EntitySnowFX.java create mode 100755 forestry_common/core/forestry/core/render/ModelEscritoire.java create mode 100755 forestry_common/core/forestry/core/render/OverlayRenderingHandler.java create mode 100755 forestry_common/core/forestry/core/render/RenderAnalyzer.java create mode 100755 forestry_common/core/forestry/core/render/RenderEscritoire.java create mode 100755 forestry_common/core/forestry/core/render/RenderMachine.java create mode 100755 forestry_common/core/forestry/core/render/RenderMill.java create mode 100755 forestry_common/core/forestry/core/render/SpriteSheet.java create mode 100755 forestry_common/core/forestry/core/render/TextureManager.java create mode 100755 forestry_common/core/forestry/core/render/TileRendererIndex.java create mode 100755 forestry_common/core/forestry/core/triggers/ForestryTrigger.java create mode 100755 forestry_common/core/forestry/core/triggers/Trigger.java create mode 100755 forestry_common/core/forestry/core/triggers/TriggerHasWork.java create mode 100755 forestry_common/core/forestry/core/triggers/TriggerLowFuel.java create mode 100755 forestry_common/core/forestry/core/triggers/TriggerLowGermlings.java create mode 100755 forestry_common/core/forestry/core/triggers/TriggerLowResource.java create mode 100755 forestry_common/core/forestry/core/triggers/TriggerLowSoil.java create mode 100755 forestry_common/core/forestry/core/triggers/TriggerMissingDrone.java create mode 100755 forestry_common/core/forestry/core/triggers/TriggerMissingQueen.java create mode 100755 forestry_common/core/forestry/core/utils/BlockUtil.java create mode 100755 forestry_common/core/forestry/core/utils/CommandMC.java create mode 100755 forestry_common/core/forestry/core/utils/DamageSourceForestry.java create mode 100755 forestry_common/core/forestry/core/utils/DelayTimer.java create mode 100755 forestry_common/core/forestry/core/utils/EnumAccess.java create mode 100755 forestry_common/core/forestry/core/utils/EnumTankLevel.java create mode 100755 forestry_common/core/forestry/core/utils/FluidMap.java create mode 100755 forestry_common/core/forestry/core/utils/FluidStackMap.java create mode 100755 forestry_common/core/forestry/core/utils/Fluids.java create mode 100755 forestry_common/core/forestry/core/utils/FontColour.java create mode 100755 forestry_common/core/forestry/core/utils/ForestryModEnvWarningCallable.java create mode 100755 forestry_common/core/forestry/core/utils/ForestryResource.java create mode 100755 forestry_common/core/forestry/core/utils/ForestryTank.java create mode 100755 forestry_common/core/forestry/core/utils/IDAllocator.java create mode 100755 forestry_common/core/forestry/core/utils/InventoryAdapter.java create mode 100755 forestry_common/core/forestry/core/utils/ItemInventory.java create mode 100755 forestry_common/core/forestry/core/utils/ItemStackMap.java create mode 100755 forestry_common/core/forestry/core/utils/LiquidHelper.java create mode 100755 forestry_common/core/forestry/core/utils/Localization.java create mode 100755 forestry_common/core/forestry/core/utils/PlainInventory.java create mode 100755 forestry_common/core/forestry/core/utils/RecipeUtil.java create mode 100755 forestry_common/core/forestry/core/utils/Schemata.java create mode 100755 forestry_common/core/forestry/core/utils/ShapedRecipeCustom.java create mode 100755 forestry_common/core/forestry/core/utils/StackMap.java create mode 100755 forestry_common/core/forestry/core/utils/StackUtils.java create mode 100755 forestry_common/core/forestry/core/utils/StringUtil.java create mode 100755 forestry_common/core/forestry/core/utils/TileInventoryAdapter.java create mode 100755 forestry_common/core/forestry/core/utils/Utils.java create mode 100755 forestry_common/core/forestry/core/utils/Vect.java create mode 100755 forestry_common/core/forestry/core/worldgen/BlockType.java create mode 100755 forestry_common/core/forestry/core/worldgen/WorldGenBase.java create mode 100755 forestry_common/core/forestry/core/worldgen/WorldGenMinableMeta.java create mode 100755 forestry_common/core/forestry/plugins/NativePlugin.java create mode 100755 forestry_common/core/forestry/plugins/PluginBuildCraft.java create mode 100755 forestry_common/core/forestry/plugins/PluginCore.java create mode 100755 forestry_common/core/forestry/plugins/PluginIC2.java create mode 100755 forestry_common/core/forestry/plugins/PluginManager.java create mode 100755 forestry_common/energy/forestry/energy/GuiHandlerEnergy.java create mode 100755 forestry_common/energy/forestry/energy/circuits/CircuitElectricBoost.java create mode 100755 forestry_common/energy/forestry/energy/circuits/CircuitElectricChange.java create mode 100755 forestry_common/energy/forestry/energy/circuits/CircuitElectricChoke.java create mode 100755 forestry_common/energy/forestry/energy/circuits/CircuitElectricEfficiency.java create mode 100755 forestry_common/energy/forestry/energy/circuits/CircuitFireDampener.java create mode 100755 forestry_common/energy/forestry/energy/gadgets/EngineBronze.java create mode 100755 forestry_common/energy/forestry/energy/gadgets/EngineClockwork.java create mode 100755 forestry_common/energy/forestry/energy/gadgets/EngineCopper.java create mode 100755 forestry_common/energy/forestry/energy/gadgets/EngineDefinition.java create mode 100755 forestry_common/energy/forestry/energy/gadgets/EngineTin.java create mode 100755 forestry_common/energy/forestry/energy/gadgets/MachineGenerator.java create mode 100755 forestry_common/energy/forestry/energy/gui/ContainerEngineBronze.java create mode 100755 forestry_common/energy/forestry/energy/gui/ContainerEngineCopper.java create mode 100755 forestry_common/energy/forestry/energy/gui/ContainerEngineTin.java create mode 100755 forestry_common/energy/forestry/energy/gui/ContainerGenerator.java create mode 100755 forestry_common/energy/forestry/energy/gui/GuiEngine.java create mode 100755 forestry_common/energy/forestry/energy/gui/GuiEngineBronze.java create mode 100755 forestry_common/energy/forestry/energy/gui/GuiEngineCopper.java create mode 100755 forestry_common/energy/forestry/energy/gui/GuiEngineTin.java create mode 100755 forestry_common/energy/forestry/energy/gui/GuiGenerator.java create mode 100755 forestry_common/energy/forestry/energy/proxy/ClientProxyEnergy.java create mode 100755 forestry_common/energy/forestry/energy/proxy/ProxyEnergy.java create mode 100755 forestry_common/energy/forestry/energy/render/RenderEngine.java create mode 100755 forestry_common/energy/forestry/plugins/PluginEnergy.java create mode 100755 forestry_common/factory/forestry/factory/GuiHandlerFactory.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineBottler.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineCarpenter.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineCentrifuge.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineFabricator.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineFermenter.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineMoistener.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineRaintank.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineSqueezer.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MachineStill.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/MillRainmaker.java create mode 100755 forestry_common/factory/forestry/factory/gadgets/TileWorktable.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerBottler.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerCarpenter.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerCentrifuge.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerFabricator.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerFermenter.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerMoistener.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerRaintank.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerSqueezer.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerStill.java create mode 100755 forestry_common/factory/forestry/factory/gui/ContainerWorktable.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiBottler.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiCarpenter.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiCentrifuge.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiFabricator.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiFermenter.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiMoistener.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiRaintank.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiSqueezer.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiStill.java create mode 100755 forestry_common/factory/forestry/factory/gui/GuiWorktable.java create mode 100755 forestry_common/factory/forestry/factory/gui/InventoryCraftingAuto.java create mode 100755 forestry_common/factory/forestry/factory/gui/SlotCraftMatrix.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideBottler.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideCarpenter.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideCentrifuge.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideCustomRecipes.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideFabricator.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideFermenter.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideIntegration.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideSqueezer.java create mode 100755 forestry_common/factory/forestry/factory/recipes/CraftGuideStill.java create mode 100755 forestry_common/factory/forestry/plugins/PluginFactory.java create mode 100755 forestry_common/farming/forestry/farming/EventHandlerFarming.java create mode 100755 forestry_common/farming/forestry/farming/FarmHelper.java create mode 100755 forestry_common/farming/forestry/farming/FarmTarget.java create mode 100755 forestry_common/farming/forestry/farming/GuiHandlerFarming.java create mode 100755 forestry_common/farming/forestry/farming/circuits/CircuitFarmLogic.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/BlockFarm.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/BlockMushroom.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/StructureLogicFarm.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/TileControl.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/TileFarm.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/TileFarmPlain.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/TileGearbox.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/TileHatch.java create mode 100755 forestry_common/farming/forestry/farming/gadgets/TileValve.java create mode 100755 forestry_common/farming/forestry/farming/gui/ContainerFarm.java create mode 100755 forestry_common/farming/forestry/farming/gui/GuiFarm.java create mode 100755 forestry_common/farming/forestry/farming/items/ItemFarmBlock.java create mode 100755 forestry_common/farming/forestry/farming/logic/Crop.java create mode 100755 forestry_common/farming/forestry/farming/logic/CropBlock.java create mode 100755 forestry_common/farming/forestry/farming/logic/CropFruit.java create mode 100755 forestry_common/farming/forestry/farming/logic/CropPeat.java create mode 100755 forestry_common/farming/forestry/farming/logic/CropRubber.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogic.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicArboreal.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicCereal.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicCocoa.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicCrops.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicGourd.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicHomogenous.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicInfernal.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicOrchard.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicPeat.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicPoale.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicRubber.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicShroom.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicSucculent.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicVegetable.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmLogicWatered.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableCocoa.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableFarmCraftory.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableGE.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableGenericCrop.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableGenericSapling.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableGourd.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableStacked.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableVanillaSapling.java create mode 100755 forestry_common/farming/forestry/farming/logic/FarmableVanillaShroom.java create mode 100755 forestry_common/farming/forestry/farming/proxy/ClientProxyFarming.java create mode 100755 forestry_common/farming/forestry/farming/proxy/ProxyFarming.java create mode 100755 forestry_common/farming/forestry/farming/render/FarmItemRenderer.java create mode 100755 forestry_common/farming/forestry/farming/render/FarmRenderingHandler.java create mode 100755 forestry_common/farming/forestry/farming/triggers/TriggerLowFertilizer.java create mode 100755 forestry_common/farming/forestry/farming/triggers/TriggerLowLiquid.java create mode 100755 forestry_common/farming/forestry/farming/triggers/TriggerLowSoil.java create mode 100755 forestry_common/farming/forestry/farming/worldgen/WorldGenBigMushroom.java create mode 100755 forestry_common/farming/forestry/plugins/PluginFarmCraftory.java create mode 100755 forestry_common/farming/forestry/plugins/PluginFarming.java create mode 100755 forestry_common/farming/forestry/plugins/PluginNatura.java create mode 100755 forestry_common/food/forestry/food/BeverageEffect.java create mode 100755 forestry_common/food/forestry/food/BeverageEffectAntidote.java create mode 100755 forestry_common/food/forestry/food/BeverageEffectDrunk.java create mode 100755 forestry_common/food/forestry/food/GuiHandlerFood.java create mode 100755 forestry_common/food/forestry/food/gui/ContainerInfuser.java create mode 100755 forestry_common/food/forestry/food/gui/GuiInfuser.java create mode 100755 forestry_common/food/forestry/food/items/ItemAmbrosia.java create mode 100755 forestry_common/food/forestry/food/items/ItemBeverage.java create mode 100755 forestry_common/food/forestry/food/items/ItemInfuser.java create mode 100755 forestry_common/food/forestry/plugins/PluginFood.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/ButterflySpawner.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/GuiHandlerLepidopterology.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/MatingRecipe.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyBase.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyFlee.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyInteract.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyRest.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyWander.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/entities/EntityButterfly.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/gadgets/TileLepidopteristChest.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleButterflySpecies.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleEffectNone.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/genetics/Butterfly.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyGenome.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyHelper.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyTemplates.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/genetics/LepidopteristTracker.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/gui/ContainerFlutterlyzer.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/gui/GuiFlutterlyzer.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/items/ItemButterflyGE.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/items/ItemFlutterlyzer.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/proxy/ClientProxyLepidopterology.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/proxy/ProxyLepidopterology.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/render/ButterflyItemRenderer.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/render/ModelButterfly.java create mode 100755 forestry_common/lepidopterology/forestry/lepidopterology/render/RenderButterfly.java create mode 100755 forestry_common/lepidopterology/forestry/plugins/PluginLepidopterology.java create mode 100755 forestry_common/mail/forestry/mail/CommandMail.java create mode 100755 forestry_common/mail/forestry/mail/EnumAddressee.java create mode 100755 forestry_common/mail/forestry/mail/EnumDeliveryState.java create mode 100755 forestry_common/mail/forestry/mail/EnumStationState.java create mode 100755 forestry_common/mail/forestry/mail/GuiHandlerMail.java create mode 100755 forestry_common/mail/forestry/mail/IMailContainer.java create mode 100755 forestry_common/mail/forestry/mail/Letter.java create mode 100755 forestry_common/mail/forestry/mail/POBox.java create mode 100755 forestry_common/mail/forestry/mail/POBoxInfo.java create mode 100755 forestry_common/mail/forestry/mail/PacketHandlerMail.java create mode 100755 forestry_common/mail/forestry/mail/PostOffice.java create mode 100755 forestry_common/mail/forestry/mail/PostRegistry.java create mode 100755 forestry_common/mail/forestry/mail/PostalCarrier.java create mode 100755 forestry_common/mail/forestry/mail/SaveEventHandlerMail.java create mode 100755 forestry_common/mail/forestry/mail/TickHandlerMailClient.java create mode 100755 forestry_common/mail/forestry/mail/TradeStation.java create mode 100755 forestry_common/mail/forestry/mail/gadgets/MachineMailbox.java create mode 100755 forestry_common/mail/forestry/mail/gadgets/MachinePhilatelist.java create mode 100755 forestry_common/mail/forestry/mail/gadgets/MachineTrader.java create mode 100755 forestry_common/mail/forestry/mail/gui/ContainerCatalogue.java create mode 100755 forestry_common/mail/forestry/mail/gui/ContainerLetter.java create mode 100755 forestry_common/mail/forestry/mail/gui/ContainerMailbox.java create mode 100755 forestry_common/mail/forestry/mail/gui/ContainerPhilatelist.java create mode 100755 forestry_common/mail/forestry/mail/gui/ContainerTradeName.java create mode 100755 forestry_common/mail/forestry/mail/gui/ContainerTrader.java create mode 100755 forestry_common/mail/forestry/mail/gui/GuiCatalogue.java create mode 100755 forestry_common/mail/forestry/mail/gui/GuiLetter.java create mode 100755 forestry_common/mail/forestry/mail/gui/GuiMailbox.java create mode 100755 forestry_common/mail/forestry/mail/gui/GuiMailboxInfo.java create mode 100755 forestry_common/mail/forestry/mail/gui/GuiPhilatelist.java create mode 100755 forestry_common/mail/forestry/mail/gui/GuiTradeName.java create mode 100755 forestry_common/mail/forestry/mail/gui/GuiTrader.java create mode 100755 forestry_common/mail/forestry/mail/items/ItemCatalogue.java create mode 100755 forestry_common/mail/forestry/mail/items/ItemLetter.java create mode 100755 forestry_common/mail/forestry/mail/items/ItemStamps.java create mode 100755 forestry_common/mail/forestry/mail/network/PacketPOBoxInfo.java create mode 100755 forestry_common/mail/forestry/mail/network/PacketTradeInfo.java create mode 100755 forestry_common/mail/forestry/mail/proxy/ClientProxyMail.java create mode 100755 forestry_common/mail/forestry/mail/proxy/ProxyMail.java create mode 100755 forestry_common/mail/forestry/mail/triggers/TriggerBuffer.java create mode 100755 forestry_common/mail/forestry/mail/triggers/TriggerHasMail.java create mode 100755 forestry_common/mail/forestry/mail/triggers/TriggerLowInput.java create mode 100755 forestry_common/mail/forestry/mail/triggers/TriggerLowPaper.java create mode 100755 forestry_common/mail/forestry/mail/triggers/TriggerLowStamps.java create mode 100755 forestry_common/mail/forestry/plugins/PluginMail.java create mode 100755 forestry_common/storage/forestry/plugins/PluginStorage.java create mode 100755 forestry_common/storage/forestry/storage/BackpackDefinition.java create mode 100755 forestry_common/storage/forestry/storage/BackpackHelper.java create mode 100755 forestry_common/storage/forestry/storage/BackpackMode.java create mode 100755 forestry_common/storage/forestry/storage/GuiHandlerStorage.java create mode 100755 forestry_common/storage/forestry/storage/PickupHandlerStorage.java create mode 100755 forestry_common/storage/forestry/storage/ResupplyHandler.java create mode 100755 forestry_common/storage/forestry/storage/gui/ContainerBackpack.java create mode 100755 forestry_common/storage/forestry/storage/gui/ContainerNaturalistBackpack.java create mode 100755 forestry_common/storage/forestry/storage/gui/GuiBackpack.java create mode 100755 forestry_common/storage/forestry/storage/gui/GuiBackpackT2.java create mode 100755 forestry_common/storage/forestry/storage/items/ItemBackpack.java create mode 100755 forestry_common/storage/forestry/storage/items/ItemNaturalistBackpack.java create mode 100755 forestry_resources/CREDITS.txt create mode 100755 forestry_resources/README.txt create mode 100755 forestry_resources/assets/forestry/logo.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/analyzer.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/analyzer_pedestal.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/analyzer_tower1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/analyzer_tower2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiaristchest.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiaristchest.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiaristchest.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiaristchest.3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiaristchest.4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiary.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiary.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiary.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiary.4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiary.7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.bottom.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.entrance.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.fan.off.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.fan.on.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.heater.off.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.heater.on.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.left.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.right.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.sieve.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.stabiliser.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.swarmer.off.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.swarmer.on.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.valve.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/arbchest.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/arbchest.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/arbchest.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/arbchest.3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/arbchest.4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/arbchest.7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.1.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.1.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.2.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.2.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.3.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.3.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.4.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.4.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.5.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.5.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.6.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.6.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.7.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.7.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.8.side.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehives/beehive.8.top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehouse.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehouse.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehouse.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehouse.4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/beehouse.7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/block_0_14.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/block_12_13.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/block_12_14.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/block_12_15.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/block_13_14.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/block_13_15.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/candle.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/candleStumpLit.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/candleStumpUnlit.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/candleTipLit.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/candleTipUnlit.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter_tank_resource_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter_tank_resource_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter_tank_resource_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/carpenter_tank_resource_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/centrifuge.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/centrifuge_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/centrifuge_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/centrifuge_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_bronze_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_bronze_extension.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_bronze_piston.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_clock_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_clock_extension.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_clock_piston.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_copper_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_copper_extension.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_copper_piston.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_tin_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_tin_extension.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_tin_piston.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_trunk_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_trunk_higher.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_trunk_highest.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_trunk_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engine_trunk_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/enginebronze.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/engineclockwork.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/enginecopper.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/enginetin.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/escritoire.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/escritoire.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fabricator.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fabricator.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fabricator.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fabricator.3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fabricator.4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/band.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/control.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/gears.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/hatch.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/reverse.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/top.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/farm/valve.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_product_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_product_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_product_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_product_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeAcacia.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeBalsa.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeBaobab.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeCherry.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeChestnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeDate.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeEbony.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeGigant.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeKapok.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLarch.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLemon.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLime.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeMahoe.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeMahogony.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeMaple.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePapaya.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePine.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePlum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePoplar.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeRubber.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeSequioa.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeSipiri.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeTeak.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeWalnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeWenge.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeWillow.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/conifers.changed.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/conifers.fancy.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/conifers.plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/deciduous.changed.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/deciduous.fancy.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/deciduous.plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/fruits.berries.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/fruits.citrus.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/fruits.nuts.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/fruits.plums.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/fruits.pomes.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/jungle.changed.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/jungle.fancy.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/jungle.plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/maple.changed.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/maple.fancy.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/maple.plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/palm.changed.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/palm.fancy.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/palm.plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/tile]-103.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/tile]-52.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/tile]-68.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/tile]-98.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/willow.changed.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/willow.fancy.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/leaves/willow.plain.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/lepichest.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/lepichest.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/lepichest.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/lepichest.3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/lepichest.4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/lepichest.7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/bioethanol.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/bioethanol.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/biomass.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/biomass.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/glass.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/glass.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/honey.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/honey.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/ice.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/ice.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/juice.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/juice.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/milk.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/seedoil.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/seedoil.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/short.mead.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/liquid/short.mead.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/blocks/mailbox.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/mailbox.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/mailbox.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/mailbox.7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/ores/apatite.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/ores/copper.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/ores/tin.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/philatelist.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/philatelist.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/philatelist.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/philatelist.3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/philatelist.7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.black.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.blue.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.green.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.red.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.white.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.yellow.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pods/dates.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pods/dates.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pods/dates.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pods/papaya.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pods/papaya.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/pods/papaya.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_blade1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_blade2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_5.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_6.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_column_7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_extension.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/rainmaker_pedestal.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/raintank.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/raintank.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/soil/bog.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/soil/humus.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/soil/peat.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/squeezer_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/10.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/11.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/12.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/13.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/14.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/15.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/5.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/6.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/8.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stained/9.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_base.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_product_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_product_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_product_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_product_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_product_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_resource_empty.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_resource_high.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_resource_low.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_resource_maximum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/still_tank_resource_medium.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/stump.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/tradestation.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/tradestation.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/tradestation.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/tradestation.3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/tradestation.4.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/tradestation.7.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.acacia.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.balsa.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.baobab.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.cherry.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.chestnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.citrus.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.ebony.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.giganteum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.greenheart.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.kapok.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.larch.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.lime.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.mahoe.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.mahogany.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.maple.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.palm.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.papaya.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.pine.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.plum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.poplar.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.sequoia.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.teak.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.walnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.wenge.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/bark.willow.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.acacia.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.balsa.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.baobab.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.cherry.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.chestnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.citrus.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.ebony.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.giganteum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.greenheart.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.kapok.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.larch.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.lime.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.mahoe.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.mahogany.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.maple.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.palm.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.papaya.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.pine.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.plum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.poplar.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.sequoia.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.teak.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.walnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.wenge.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/heart.willow.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.acacia.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.balsa.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.baobab.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.cherry.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.chestnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.citrus.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.ebony.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.greenheart.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.kapok.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.larch.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.lime.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.mahoe.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.mahogany.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.maple.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.palm.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.papaya.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.pine.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.plum.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.poplar.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.sequoia.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.teak.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.walnut.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.wenge.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/planks.willow.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/tile]-120.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/tile]-127.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/tile]-142.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/tile]-143.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/tile]-158.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/wood/tile]-159.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/worktable.0.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/worktable.1.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/worktable.2.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/worktable.3.png create mode 100755 forestry_resources/assets/forestry/textures/blocks/worktable.4.png create mode 100755 forestry_resources/assets/forestry/textures/entity/beekeeper.png create mode 100755 forestry_resources/assets/forestry/textures/entity/bees/endBee.png create mode 100755 forestry_resources/assets/forestry/textures/entity/bees/honeyBee.png create mode 100755 forestry_resources/assets/forestry/textures/entity/bees/icyBee.png create mode 100755 forestry_resources/assets/forestry/textures/entity/bees/sinisterBee.png create mode 100755 forestry_resources/assets/forestry/textures/entity/bees/tropicalBee.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiAurora.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiBatesia.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiBlackSwallow.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiBlueDuke.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiBlueWing.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiBrimstone.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiCSpeckledWood.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiCabbageWhite.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiCitrusSwallow.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiComma.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiDianaFrit.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiEmeraldPeacock.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiGlasswing.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiGlassyTiger.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiGozoraAzure.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiLLacewing.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiMBlueMorpho.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiMSpeckledWood.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiMalachite.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiMonarch.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiPBlueMorpho.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiPalaenoSulphur.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiPostillion.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiPostman.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiRBlueMorpho.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiReseda.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiSpeckledWood.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiSpicebush.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiSpringAzure.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiThoasSwallow.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/lepiZebraSwallow.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/mothAtlas.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/mothBrimstone.png create mode 100755 forestry_resources/assets/forestry/textures/entity/butterflies/mothLatticedHeath.png create mode 100755 forestry_resources/assets/forestry/textures/entity/lumberjack.png create mode 100755 forestry_resources/assets/forestry/textures/gui/alveary.png create mode 100755 forestry_resources/assets/forestry/textures/gui/alyzer.png create mode 100755 forestry_resources/assets/forestry/textures/gui/analyzer.png create mode 100755 forestry_resources/assets/forestry/textures/gui/apiaristinventory.png create mode 100755 forestry_resources/assets/forestry/textures/gui/apiary.png create mode 100755 forestry_resources/assets/forestry/textures/gui/atlas.png create mode 100755 forestry_resources/assets/forestry/textures/gui/backpack.png create mode 100755 forestry_resources/assets/forestry/textures/gui/backpackT2.png create mode 100755 forestry_resources/assets/forestry/textures/gui/beealyzer.png create mode 100755 forestry_resources/assets/forestry/textures/gui/bioengine.png create mode 100755 forestry_resources/assets/forestry/textures/gui/biomefinder.png create mode 100755 forestry_resources/assets/forestry/textures/gui/bottler.png create mode 100755 forestry_resources/assets/forestry/textures/gui/buttons.png create mode 100755 forestry_resources/assets/forestry/textures/gui/carpenter.png create mode 100755 forestry_resources/assets/forestry/textures/gui/centrifuge.png create mode 100755 forestry_resources/assets/forestry/textures/gui/electricalengine.png create mode 100755 forestry_resources/assets/forestry/textures/gui/escritoire.png create mode 100755 forestry_resources/assets/forestry/textures/gui/fabricator.png create mode 100755 forestry_resources/assets/forestry/textures/gui/fermenter.png create mode 100755 forestry_resources/assets/forestry/textures/gui/generator.png create mode 100755 forestry_resources/assets/forestry/textures/gui/hygroregulator.png create mode 100755 forestry_resources/assets/forestry/textures/gui/imprinter.png create mode 100755 forestry_resources/assets/forestry/textures/gui/infuser.png create mode 100755 forestry_resources/assets/forestry/textures/gui/ledger.png create mode 100755 forestry_resources/assets/forestry/textures/gui/letter.png create mode 100755 forestry_resources/assets/forestry/textures/gui/mailalert.png create mode 100755 forestry_resources/assets/forestry/textures/gui/mailbox.png create mode 100755 forestry_resources/assets/forestry/textures/gui/mailtrader.png create mode 100755 forestry_resources/assets/forestry/textures/gui/mfarm.png create mode 100755 forestry_resources/assets/forestry/textures/gui/moistener.png create mode 100755 forestry_resources/assets/forestry/textures/gui/peatengine.png create mode 100755 forestry_resources/assets/forestry/textures/gui/philatelist.png create mode 100755 forestry_resources/assets/forestry/textures/gui/raintank.png create mode 100755 forestry_resources/assets/forestry/textures/gui/sieve.png create mode 100755 forestry_resources/assets/forestry/textures/gui/solder.png create mode 100755 forestry_resources/assets/forestry/textures/gui/squeezer.png create mode 100755 forestry_resources/assets/forestry/textures/gui/still.png create mode 100755 forestry_resources/assets/forestry/textures/gui/swarmer.png create mode 100755 forestry_resources/assets/forestry/textures/gui/tradername.png create mode 100755 forestry_resources/assets/forestry/textures/gui/worktable.png create mode 100755 forestry_resources/assets/forestry/textures/items/ambrosia.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/anything.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/bee.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/cave.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/closed.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/drone.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/flyer.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/item.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/nocturnal.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/princess.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/pure_breed.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/pure_cave.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/pure_flyer.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/pure_nocturnal.png create mode 100755 forestry_resources/assets/forestry/textures/items/analyzer/queen.png create mode 100755 forestry_resources/assets/forestry/textures/items/apatite.png create mode 100755 forestry_resources/assets/forestry/textures/items/apiaristBoots.png create mode 100755 forestry_resources/assets/forestry/textures/items/apiaristChest.png create mode 100755 forestry_resources/assets/forestry/textures/items/apiaristHelmet.png create mode 100755 forestry_resources/assets/forestry/textures/items/apiaristLegs.png create mode 100755 forestry_resources/assets/forestry/textures/items/apiarist_armor_1.png create mode 100755 forestry_resources/assets/forestry/textures/items/apiarist_armor_2.png create mode 100755 forestry_resources/assets/forestry/textures/items/ash.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/locked.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/neutral.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/receive.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/resupply.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/t1.cloth.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/t1.outline.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/t2.cloth.png create mode 100755 forestry_resources/assets/forestry/textures/items/backpacks/t2.outline.png create mode 100755 forestry_resources/assets/forestry/textures/items/beeCombs.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/beeCombs.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/beealyzer.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/body1.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/princess.body2.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/princess.body2.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/princess.body2.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.txt create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.png create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.txt create mode 100755 forestry_resources/assets/forestry/textures/items/beeswax.png create mode 100755 forestry_resources/assets/forestry/textures/items/bioMass.png create mode 100755 forestry_resources/assets/forestry/textures/items/biomefinder.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/biomefinder.png create mode 100755 forestry_resources/assets/forestry/textures/items/biomefinder.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/biomefinder.txt create mode 100755 forestry_resources/assets/forestry/textures/items/biomefinder.txt.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/bituminousPeat.png create mode 100755 forestry_resources/assets/forestry/textures/items/brokenBronzePickaxe.png create mode 100755 forestry_resources/assets/forestry/textures/items/brokenBronzeShovel.png create mode 100755 forestry_resources/assets/forestry/textures/items/bronzePickaxe.png create mode 100755 forestry_resources/assets/forestry/textures/items/bronzeShovel.png create mode 100755 forestry_resources/assets/forestry/textures/items/bucketBiofuel.png create mode 100755 forestry_resources/assets/forestry/textures/items/bucketBiomass.png create mode 100755 forestry_resources/assets/forestry/textures/items/carton.png create mode 100755 forestry_resources/assets/forestry/textures/items/catalogue.png create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body.png create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body.txt create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body.txt.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body2.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body2.png create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body2.png.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt create mode 100755 forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt.mcmeta create mode 100755 forestry_resources/assets/forestry/textures/items/chipsets.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/chipsets.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/crate.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/apatite.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/apples.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/ash.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/beeswax.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/bogearth.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/brass.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/brick.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/bronze.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/cacti.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/charcoal.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/clay.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/coal.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/cobblestone.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/cocoacomb.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/cookies.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/copper.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/dirt.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/drippingcombs.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/fertilizer.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/frozencombs.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/glowstone.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/gravel.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/honeycombs.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/honeydew.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/honeydrop.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/humus.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/iron.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/lapis.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/mulch.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/mycelium.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/netherbrick.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/netherrack.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/netherwart.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/nikolite.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/obsidian.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/peat.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/phosphor.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/pollen.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/propolis.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/redstone.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/reeds.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/refractorywax.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/resin.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/rubber.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/sand.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/sandstone.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/saplings.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/scrap.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/seeds.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/simmeringcombs.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/soulsand.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/stone.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/stringycombs.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/tile]-16.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/tin.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/uum.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/wheat.png create mode 100755 forestry_resources/assets/forestry/textures/items/crates/wood.png create mode 100755 forestry_resources/assets/forestry/textures/items/decayingWheat.png create mode 100755 forestry_resources/assets/forestry/textures/items/dissipationCharge.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/circuitMismatch.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/errored.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/forcedCooldown.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/invalidBiome.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/isRaining.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noCircuitBoard.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noDisposal.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noDrone.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noEnergyNet.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noFarmland.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noFertilizer.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noFlower.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noFuel.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noHeat.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noHoney.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noLiquid.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noQueen.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noRecipe.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noRecipient.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noResource.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noSky.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noSpace.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noSpecimen.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/noStamps.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notAlphaNumeric.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notDay.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notGloomy.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notLucid.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notNight.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notPostpaid.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notRaining.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/notUnique.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/ok.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/unknown.png create mode 100755 forestry_resources/assets/forestry/textures/items/errors/wrongStacksize.png create mode 100755 forestry_resources/assets/forestry/textures/items/fertilizerBio.png create mode 100755 forestry_resources/assets/forestry/textures/items/fertilizerCompound.png create mode 100755 forestry_resources/assets/forestry/textures/items/flutterlyzer.png create mode 100755 forestry_resources/assets/forestry/textures/items/frameImpregnated.png create mode 100755 forestry_resources/assets/forestry/textures/items/frameProven.png create mode 100755 forestry_resources/assets/forestry/textures/items/frameUntreated.png create mode 100755 forestry_resources/assets/forestry/textures/items/fruits/cherry.png create mode 100755 forestry_resources/assets/forestry/textures/items/fruits/chestnut.png create mode 100755 forestry_resources/assets/forestry/textures/items/fruits/dates.png create mode 100755 forestry_resources/assets/forestry/textures/items/fruits/lemon.png create mode 100755 forestry_resources/assets/forestry/textures/items/fruits/papaya.png create mode 100755 forestry_resources/assets/forestry/textures/items/fruits/plum.png create mode 100755 forestry_resources/assets/forestry/textures/items/fruits/walnut.png create mode 100755 forestry_resources/assets/forestry/textures/items/gearBronze.png create mode 100755 forestry_resources/assets/forestry/textures/items/gearCopper.png create mode 100755 forestry_resources/assets/forestry/textures/items/gearTin.png create mode 100755 forestry_resources/assets/forestry/textures/items/grafter.png create mode 100755 forestry_resources/assets/forestry/textures/items/grafterProven.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/desert.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/end.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/forest.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/hills.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/jungle.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/mushroom.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/nether.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/ocean.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/plains.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/snow.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/swamp.png create mode 100755 forestry_resources/assets/forestry/textures/items/habitats/taiga.png create mode 100755 forestry_resources/assets/forestry/textures/items/hardenedMachine.png create mode 100755 forestry_resources/assets/forestry/textures/items/honeyDrop.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/honeyDrop.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/honeyPot.png create mode 100755 forestry_resources/assets/forestry/textures/items/honeydew.png create mode 100755 forestry_resources/assets/forestry/textures/items/honeyedSlice.png create mode 100755 forestry_resources/assets/forestry/textures/items/iceShard.png create mode 100755 forestry_resources/assets/forestry/textures/items/impregnatedCasing.png create mode 100755 forestry_resources/assets/forestry/textures/items/imprinter.png create mode 100755 forestry_resources/assets/forestry/textures/items/infuser.png create mode 100755 forestry_resources/assets/forestry/textures/items/ingotBronze.png create mode 100755 forestry_resources/assets/forestry/textures/items/ingotCopper.png create mode 100755 forestry_resources/assets/forestry/textures/items/ingotTin.png create mode 100755 forestry_resources/assets/forestry/textures/items/iodineCapsule.png create mode 100755 forestry_resources/assets/forestry/textures/items/kitPickaxe.png create mode 100755 forestry_resources/assets/forestry/textures/items/kitShovel.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/bucket.bottle.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/bucket.contents.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/can.bottle.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/can.contents.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/capsule.bottle.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/capsule.contents.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/glass.bottle.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/glass.contents.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/jar.bottle.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/jar.contents.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/refractory.bottle.png create mode 100755 forestry_resources/assets/forestry/textures/items/liquids/refractory.contents.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/carrier.player.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/carrier.trader.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.0.emptied.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.0.fresh.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.0.opened.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.0.stamped.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.1.emptied.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.1.fresh.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.1.opened.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.1.stamped.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.2.emptied.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.2.fresh.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.2.opened.png create mode 100755 forestry_resources/assets/forestry/textures/items/mail/letter.2.stamped.png create mode 100755 forestry_resources/assets/forestry/textures/items/misc/access.private.png create mode 100755 forestry_resources/assets/forestry/textures/items/misc/access.shared.png create mode 100755 forestry_resources/assets/forestry/textures/items/misc/access.viewable.png create mode 100755 forestry_resources/assets/forestry/textures/items/misc/energy.png create mode 100755 forestry_resources/assets/forestry/textures/items/misc/hint.png create mode 100755 forestry_resources/assets/forestry/textures/items/mouldyWheat.png create mode 100755 forestry_resources/assets/forestry/textures/items/mulch.png create mode 100755 forestry_resources/assets/forestry/textures/items/naturalistHelmet.png create mode 100755 forestry_resources/assets/forestry/textures/items/naturalist_armor_1.png create mode 100755 forestry_resources/assets/forestry/textures/items/oakStick.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/ember.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/flame.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/placeholder.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/poison.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/snow.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/snow.2.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/snow.3.png create mode 100755 forestry_resources/assets/forestry/textures/items/particles/swarm_bee.png create mode 100755 forestry_resources/assets/forestry/textures/items/peat.png create mode 100755 forestry_resources/assets/forestry/textures/items/phosphor.png create mode 100755 forestry_resources/assets/forestry/textures/items/pipette.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/pipette.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/pollen.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/pollen.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/propolis.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/pulsatingDust.png create mode 100755 forestry_resources/assets/forestry/textures/items/pulsatingMesh.png create mode 100755 forestry_resources/assets/forestry/textures/items/refractoryWax.png create mode 100755 forestry_resources/assets/forestry/textures/items/royalJelly.png create mode 100755 forestry_resources/assets/forestry/textures/items/scentedPaneling.png create mode 100755 forestry_resources/assets/forestry/textures/items/scoop.png create mode 100755 forestry_resources/assets/forestry/textures/items/silkWisp.png create mode 100755 forestry_resources/assets/forestry/textures/items/slots/blocked.png create mode 100755 forestry_resources/assets/forestry/textures/items/slots/blocked_2.png create mode 100755 forestry_resources/assets/forestry/textures/items/slots/container.png create mode 100755 forestry_resources/assets/forestry/textures/items/slots/liquid.png create mode 100755 forestry_resources/assets/forestry/textures/items/slots/locked.png create mode 100755 forestry_resources/assets/forestry/textures/items/solderingIron.png create mode 100755 forestry_resources/assets/forestry/textures/items/spectacles.png create mode 100755 forestry_resources/assets/forestry/textures/items/stamps.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/stamps.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/sturdyMachine.png create mode 100755 forestry_resources/assets/forestry/textures/items/thermionicTubes.0.png create mode 100755 forestry_resources/assets/forestry/textures/items/thermionicTubes.1.png create mode 100755 forestry_resources/assets/forestry/textures/items/treealyzer.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/hasMail.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/hasWork.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowFertilizer.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowFuel.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowGermlings.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowInput.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowLiquid.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowPaper.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowResources.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowSoil.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/lowStamps.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/mailBuffer.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/missingDrone.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/missingQueen.png create mode 100755 forestry_resources/assets/forestry/textures/items/triggers/noFrames.png create mode 100755 forestry_resources/assets/forestry/textures/items/vialCatalyst.png create mode 100755 forestry_resources/assets/forestry/textures/items/waxCast.png create mode 100755 forestry_resources/assets/forestry/textures/items/woodPulp.png create mode 100755 forestry_resources/assets/forestry/textures/items/wovenSilk.png create mode 100755 forestry_resources/assets/forestry/textures/items/wrench.png create mode 100755 forestry_resources/assets/forestry/textures/unsorted/tile]-10.png create mode 100755 forestry_resources/assets/forestry/textures/unsorted/tile]-105.png create mode 100755 forestry_resources/assets/forestry/textures/unsorted/tile]-37.png create mode 100755 forestry_resources/assets/forestry/textures/unsorted/tile]-88.png create mode 100755 forestry_resources/assets/forestry/textures/unsorted/tile]-89.png create mode 100755 forestry_resources/assets/forestry/textures/unsorted/tile]-90.png create mode 100755 forestry_resources/changelog/2.0.0.0 create mode 100755 forestry_resources/changelog/2.0.0.1 create mode 100755 forestry_resources/changelog/2.0.0.10 create mode 100755 forestry_resources/changelog/2.0.0.11 create mode 100755 forestry_resources/changelog/2.0.0.2 create mode 100755 forestry_resources/changelog/2.0.0.3 create mode 100755 forestry_resources/changelog/2.0.0.4 create mode 100755 forestry_resources/changelog/2.0.0.5 create mode 100755 forestry_resources/changelog/2.0.0.6 create mode 100755 forestry_resources/changelog/2.0.0.7 create mode 100755 forestry_resources/changelog/2.0.0.8 create mode 100755 forestry_resources/changelog/2.0.0.9 create mode 100755 forestry_resources/changelog/2.1.0.0 create mode 100755 forestry_resources/changelog/2.2.0.0 create mode 100755 forestry_resources/changelog/2.2.0.1 create mode 100755 forestry_resources/changelog/2.2.0.2 create mode 100755 forestry_resources/changelog/2.2.2.0 create mode 100755 forestry_resources/changelog/2.2.2.1 create mode 100755 forestry_resources/changelog/2.2.2.2 create mode 100755 forestry_resources/changelog/2.2.4.0 create mode 100755 forestry_resources/changelog/2.2.4.1 create mode 100755 forestry_resources/changelog/2.2.4.2 create mode 100755 forestry_resources/changelog/2.2.4.3 create mode 100755 forestry_resources/changelog/2.2.6.0 create mode 100755 forestry_resources/changelog/2.2.6.1 create mode 100755 forestry_resources/changelog/2.2.6.2 create mode 100755 forestry_resources/changelog/2.2.6.3 create mode 100755 forestry_resources/changelog/2.2.8.2 create mode 100755 forestry_resources/changelog/2.2.8.3 create mode 100755 forestry_resources/changelog/2.2.8.4 create mode 100755 forestry_resources/changelog/2.3.0.0 create mode 100755 forestry_resources/changelog/2.3.0.1 create mode 100755 forestry_resources/changelog/2.3.0.2 create mode 100755 forestry_resources/changelog/2.3.0.3 create mode 100755 forestry_resources/changelog/2.3.0.4 create mode 100755 forestry_resources/changelog/2.3.0.5 create mode 100755 forestry_resources/changelog/2.3.0.6 create mode 100755 forestry_resources/changelog/2.3.0.7 create mode 100755 forestry_resources/changelog/2.3.1.0 create mode 100755 forestry_resources/changelog/2.3.1.1 create mode 100755 forestry_resources/changelog/2.4.0.0 create mode 100755 forestry_resources/config/forestry/colour.properties create mode 100755 forestry_resources/config/forestry/gamemodes/HARD.conf create mode 100755 forestry_resources/config/forestry/gamemodes/NORMAL.conf create mode 100755 forestry_resources/config/forestry/gamemodes/OP.conf create mode 100755 forestry_resources/config/forestry/hints.properties create mode 100755 forestry_resources/lang/forestry/apiculture/en_US.properties create mode 100755 forestry_resources/lang/forestry/arboriculture/en_US.properties create mode 100755 forestry_resources/lang/forestry/core/en_US.properties create mode 100755 forestry_resources/lang/forestry/farming/en_US.properties create mode 100755 forestry_resources/lang/forestry/lepidopterology/en_US.properties create mode 100755 forestry_resources/lang/forestry/mail/en_US.properties create mode 100755 forestry_resources/lang/forestry/pipes/en_US.properties create mode 100755 forestry_resources/mcmod.info create mode 100755 forestry_techne/Bee.java create mode 100755 forestry_techne/Bee1.tcn create mode 100755 forestry_techne/Bee2.tcn create mode 100755 forestry_techne/BeeQueen.java create mode 100755 forestry_techne/BeeQueen.png create mode 100755 forestry_techne/BeeQueen.tcn create mode 100755 forestry_techne/Butterfly1.tcn create mode 100755 forestry_techne/Butterfly2-2.tcn create mode 100755 forestry_techne/Butterfly2.png create mode 100755 forestry_techne/Escritoire.java create mode 100755 forestry_techne/Escritoire.png create mode 100755 forestry_techne/escritoire.tcn create mode 100755 forestry_techne/escritoire2.tcn create mode 100755 pipes_common/forestry/pipes/EnumFilterType.java create mode 100755 pipes_common/forestry/pipes/GuiHandlerPipes.java create mode 100755 pipes_common/forestry/pipes/PipeIconProvider.java create mode 100755 pipes_common/forestry/pipes/PipeItemsPropolis.java create mode 100755 pipes_common/forestry/pipes/PipeLogicPropolis.java create mode 100755 pipes_common/forestry/pipes/gui/ContainerPropolisPipe.java create mode 100755 pipes_common/forestry/pipes/gui/GuiPropolisPipe.java create mode 100755 pipes_common/forestry/pipes/network/PacketHandlerPipes.java create mode 100755 pipes_common/forestry/pipes/proxy/ClientProxyPipes.java create mode 100755 pipes_common/forestry/pipes/proxy/ProxyPipes.java create mode 100755 pipes_common/forestry/plugins/PluginPropolisPipe.java diff --git a/CLA.txt b/CLA.txt new file mode 100755 index 000000000..bb165405b --- /dev/null +++ b/CLA.txt @@ -0,0 +1,11 @@ +FORESTRY INDIVIDUAL CONTRIBUTOR LICENSE AGREEMENT + Thank you for your interest in contributing to Forestry ("We" or "Us"). + This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please sign it and send it to Us by electronic submission using CLAHub (http://www.clahub.com/). This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us. 1. Definitions "You" means the individual who Submits a Contribution to Us. "Contribution" means any work of authorship that is Submitted by You to Us in which You own or assert ownership of the Copyright. "Copyright" means all rights protecting works of authorship owned or controlled by You, including copyright, moral and neighboring rights, as appropriate, for the full term of their existence including any extensions by You. "Material" means the work of authorship which is made available by Us to third parties. When this Agreement covers more than one software project, the Material means the work of authorship to which the Contribution was Submitted. After You Submit the Contribution, it may be included in the Material. "Submit" means any form of electronic, verbal, or written communication sent to Us or our representatives, including but not limited to electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Us for the purpose of discussing and improving the Material, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." "Submission Date" means the date on which You Submit a Contribution to Us. "Effective Date" means the date You execute this Agreement or the date You first Submit a Contribution to Us, whichever is earlier. "Media" means any portion of a Contribution which is not software. 2. Grant of Rights 2.1 Copyright License (a) You retain ownership of the Copyright in Your Contribution and have the same rights to use or license the Contribution which You would have had without entering into the Agreement. (b) To the maximum extent permitted by the relevant law, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable license under the Copyright covering the Contribution, with the right to sublicense such rights through multiple tiers of sublicensees, to reproduce, modify, display, perform and distribute the Contribution as part of the Material; provided that this license is conditioned upon compliance with Section 2.3. 2.2 Patent License For patent claims including, without limitation, method, process, and apparatus claims which You own, control or have the right to grant, now or in the future, You grant to Us a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable patent license, with the right to sublicense these rights to multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, import and otherwise transfer the Contribution and the Contribution in combination with the Material (and portions of such combination). This license is granted only to the extent that the exercise of the licensed rights infringes such patent claims; and provided that this license is conditioned upon compliance with Section 2.3. 2.3 Outbound License Based on the grant of rights in Sections 2.1 and 2.2, if We include Your Contribution in a Material, We may license the Contribution under any license, including copyleft, permissive, commercial, or proprietary licenses. + 2.4 Moral Rights. + +If moral rights apply to the Contribution, to the maximum extent permitted by law, You waive and agree not to assert such moral rights against Us or our successors in interest, or any of our licensees, either direct or indirect. 2.5 Our Rights. + +You acknowledge that We are not obligated to use Your Contribution as part of the Material and may decide to include any Contribution We consider appropriate. 2.6 Reservation of Rights. + +Any rights not expressly assigned or licensed under this section are expressly reserved by You. 3. Agreement You confirm that: (a) You have the legal authority to enter into this Agreement. (b) You own the Copyright and patent claims covering the Contribution which are required to grant the rights under Section 2. (c) The grant of rights under Section 2 does not violate any grant of rights which You have made to third parties, including Your employer. If You are an employee, You have had Your employer approve this Agreement. If You are less than eighteen years old, please have Your parents or guardian sign the Agreement. 4. Disclaimer EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO US AND BY US TO YOU. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW. + 5. Consequential Damage Waiver TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU OR US BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. 6. Miscellaneous 6.1 This Agreement will be governed by and construed in accordance with the laws of Germany excluding its conflicts of law provisions. Under certain circumstances, the governing law in this section might be superseded by the United Nations Convention on Contracts for the International Sale of Goods ("UN Convention") and the parties intend to avoid the application of the UN Convention to this Agreement and, thus, exclude the application of the UN Convention in its entirety to this Agreement. 6.2 This Agreement sets out the entire agreement between You and Us for Your Contributions to Us and overrides all other agreements or understandings. 6.3 If You or We assign the rights or obligations received through this Agreement to a third party, as a condition of the assignment, that third party must agree in writing to abide by all the rights and obligations in the Agreement. 6.4 The failure of either party to require performance by the other party of any provision of this Agreement in one situation shall not affect the right of a party to require such performance at any time in the future. A waiver of performance under a provision in one situation shall not be considered a waiver of the performance of the provision in the future or a waiver of the provision in its entirety. 6.5 If any provision of this Agreement is found void and unenforceable, such provision will be replaced to the extent possible with a provision that comes closest to the meaning of the original provision and which is enforceable. The terms and conditions set forth in this Agreement shall apply notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the maximum extent possible under law. \ No newline at end of file diff --git a/CONTRIBUTING.md.txt b/CONTRIBUTING.md.txt new file mode 100755 index 000000000..a0ba3a665 --- /dev/null +++ b/CONTRIBUTING.md.txt @@ -0,0 +1,16 @@ +How to contribute to Forestry +==================================== + +### Contributor License Agreement + +Before pull requests can be accepted, the contributor needs to sign a contributor license agreement. (Essentially giving a license for using his code and/or media and for re-licensing it, for details read the agreement linked below.) + +### How do I sign? + +To keep the hassle for everyone involved to a minimum, Forestry uses CLAHub to manage the agreements. To get started, sign the Contributor License Agreement. + +### Why is this needed? + +Without CLAs it at some point becomes essentially impossible to change the license of a project which accepts contributions from third parties. Without an explicit agreement every contributor would still own the copyright to his code. So as long as it (or parts of it) remain in the code base, he would have to agree to every license change. If enough time has passed, there may be dozens, perhaps even hundreds of contributors involved and it will be very hard to track down each and every one of them and get them to agree on a new license. + +This would make it impossible to change the license to a more permissive one at a later date, so the code would be locked into CC BY-NC-ND 3.0 until it passes into the public domain about a hundred years from now. This situation is to be avoided and that’s why you are being bothered with this CLA. \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100755 index 000000000..f0bea231f --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,64 @@ +License (CC BY-NC-ND 3.0) + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + +1. Definitions + +"Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. +"Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +"Distribute" means to make available to the public the original and copies of the Work through sale or other transfer of ownership. +"Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. +"Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +"Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. +"Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. +"Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. + +2. Fair Dealing Rights. + +Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. + +3. License Grant. + +Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: + +to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; and, +to Distribute and Publicly Perform the Work including as incorporated in Collections. +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Adaptations. Subject to 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d). + +4. Restrictions. + +The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + +You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. +You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. +If You Distribute, or Publicly Perform the Work or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Collection, at a minimum such credit will appear, if a credit for all contributing authors of Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. +For the avoidance of doubt: + +Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; +Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, +Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b). +Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. + +EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + +This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. +Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. + +8. Miscellaneous + +Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. +If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. +No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. +This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. +The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. \ No newline at end of file diff --git a/README.md.txt b/README.md.txt new file mode 100755 index 000000000..4d818692f --- /dev/null +++ b/README.md.txt @@ -0,0 +1,28 @@ +Forestry +==================================== + +### What is it? + +Forestry is a modification for the game Minecraft and known primarily for its farms and bees. + +### Homepage + +[Wiki](http://forestry.sengir.net/) + +[Forums](http://forestry.sengir.net/forum/) + +[IRC #forestry on esper.net](http://webchat.esper.net/?nick=ForestryWiki...&channels=forestry&prompt=1) + +### Notes + +Beware of ugly code. + +The API resides in its own repository. You will need it to compile this code. + +Bugfixes are generally welcome. If you want to contribute something which changes game mechanics, please talk to someone with commit privileges first. Nothing is more frustrating than putting a lot of work and effort into a new game mechanic and then having the PR rejected because it doesn’t fit gameplay-wise. + +If you submit a PR you must accept the Contributor License Agreement. There is no way around that, since otherwise changing the license later - even to something more permissive! - , becomes close to impossible. + +### License & Copyright + +Forestry is (c) 2011 - 2014 SirSengir and licensed under CC BY-NC-ND 3.0. See the LICENSE.txt for all the gory details or go to http://creativecommons.org/licenses/by-nc-nd/3.0/ for more information. Forestry also contains code contributed by CovertJaguar, Player, MysteriousAges, Binnie, RichardG, cpw and others. \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100755 index 000000000..f503efbf7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,123 @@ +buildscript { + repositories { + mavenCentral() + maven { + name = "forge" + url = "http://files.minecraftforge.net/maven" + } + maven { + name = "sonatype" + url = "https://oss.sonatype.org/content/repositories/snapshots/" + } + } + dependencies { + classpath 'net.minecraftforge.gradle:ForgeGradle:1.1-SNAPSHOT' + } +} + +apply plugin: 'forge' + +ext.buildnumber = createBuildNumber() +version = "2.4.0.0-" + buildnumber +group= "net.sengir.forestry" // http://maven.apache.org/guides/mini/guide-naming-conventions.html +archivesBaseName = "forestry" + +ext.langDir = "../Forestry-Localization" +ext.srcbcDir = "../BuildCraft/common" +ext.srcIc2Dir = "../IC2/src" +ext.srcCraftguideDir = "../CraftGuide/src" + +minecraft { + version = "1.7.2-10.12.0.1032" + assetDir = "eclipse/assets" + + replace '@VERSION@', project.version + replace '@BUILD_NUMBER@', project.buildnumber + replace '$___$', rndString() + replace '$____$', rndString() + replace '$_____$', rndString() + replace '$______$', rndString() + replace '$_______$', rndString() + replace '$________$', rndString() + replace '$_________$', rndString() + replace '$__________$', rndString() +} + +sourceSets { + api { + java { + srcDir project.srcCraftguideDir + include '**/CraftGuide/api/**' + } + } + + main { + java { + srcDirs file('forestry_common').listFiles() + include 'forestry/**' + + srcDir project.srcbcDir + include 'buildcraft/api/**' + + srcDir project.srcIc2Dir + include 'api/**' + } + resources { + srcDir 'forestry_resources' + srcDir project.langDir + } + } +} + +processResources { + // replace stuff in mcmod.info, nothing else + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace version and mcversion + expand 'version':project.version, 'mcversion':project.minecraft.version + } + + // copy everything else, thats not the mcmod.info + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + exclude '**/*.md' + } +} + +task apiZip(type: Jar) { + from sourceSets.main.allSource + include 'forestry/api/**' + classifier = 'api' + extension = 'zip' +} + +task deobfJar(type: Jar) { + from sourceSets.main.output + classifier = 'dev' +} + +build.dependsOn apiZip, deobfJar + +def rndString() { + String AB = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + Random rnd = new Random() + String ret = "" + int max = rnd.nextInt(18) + 3 + + for (int i = 0; i < max; i++) { + ret += AB.charAt(rnd.nextInt(AB.length())) + } + + int rndStart = rnd.nextInt(6) + 2 + rndStart = rndStart >= ret.length() - 4 ? 3 : rndStart; + + return ret.substring(0, rndStart).toLowerCase(Locale.ENGLISH) + ret.substring(rndStart) +} + +def createBuildNumber() { + ant.buildnumber() + + return ant.antProject.properties['build.number'] +} + diff --git a/build.number b/build.number new file mode 100755 index 000000000..7103f44b6 --- /dev/null +++ b/build.number @@ -0,0 +1,3 @@ +#Build Number for ANT. Do not edit! +#Mon Mar 31 06:46:14 CEST 2014 +build.number=712 diff --git a/build.xml b/build.xml new file mode 100755 index 000000000..eda558604 --- /dev/null +++ b/build.xml @@ -0,0 +1,352 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forestry_common/apiculture/forestry/apiculture/BeekeepingLogic.java b/forestry_common/apiculture/forestry/apiculture/BeekeepingLogic.java new file mode 100755 index 000000000..98f9bca69 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/BeekeepingLogic.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.Stack; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeekeepingLogic; +import forestry.api.genetics.IEffectData; +import forestry.api.genetics.IIndividual; +import forestry.core.EnumErrorCode; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.proxy.Proxies; +import forestry.plugins.PluginApiculture; + +public class BeekeepingLogic implements IBeekeepingLogic { + + private static final int MAX_POLLINATION_ATTEMPTS = 20; + IBeeHousing housing; + // Breeding + private int breedingTime; + private final int totalBreedingTime = Defaults.APIARY_BREEDING_TIME; + private int throttle; + private IEffectData effectData[] = new IEffectData[2]; + private IBee queen; + private IIndividual pollen; + private int attemptedPollinations = 0; + private final Stack spawn = new Stack(); + + public BeekeepingLogic(IBeeHousing housing) { + this.housing = housing; + } + + // / SAVING & LOADING + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + breedingTime = nbttagcompound.getInteger("BreedingTime"); + throttle = nbttagcompound.getInteger("Throttle"); + + NBTTagList nbttaglist = new NBTTagList(); + while (!spawn.isEmpty()) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + spawn.pop().writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("Offspring", nbttaglist); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + nbttagcompound.setInteger("BreedingTime", breedingTime); + nbttagcompound.setInteger("Throttle", throttle); + + NBTTagList nbttaglist = nbttagcompound.getTagList("Offspring", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + spawn.add(ItemStack.loadItemStackFromNBT(nbttaglist.getCompoundTagAt(i))); + } + + } + + // / STATE INFORMATION + @Override + public int getBreedingTime() { + return this.breedingTime; + } + + @Override + public int getTotalBreedingTime() { + return this.totalBreedingTime; + } + + @Override + public IBee getQueen() { + return this.queen; + } + + @Override + public IBeeHousing getHousing() { + return this.housing; + } + + @Override + public IEffectData[] getEffectData() { + return this.effectData; + } + + /* UPDATING */ + @Override + public void update() { + + resetQueen(null); + + // Still something to spawn, try it + while (!spawn.isEmpty()) { + ItemStack next = spawn.peek(); + if (housing.addProduct(next, true)) { + spawn.pop(); + housing.setErrorState(EnumErrorCode.OK.ordinal()); + } else + housing.setErrorState(EnumErrorCode.NOSPACE.ordinal()); + return; + } + + // No queen? And no princess? + if (housing.getQueen() == null) { + housing.setErrorState(EnumErrorCode.NOQUEEN.ordinal()); + return; + } + + // Princess available? Try to breed! + if (ForestryItem.beePrincessGE.isItemEqual(housing.getQueen())) { + if (ForestryItem.beeDroneGE.isItemEqual(housing.getDrone())) + housing.setErrorState(EnumErrorCode.NODRONE.ordinal()); + else + housing.setErrorState(EnumErrorCode.OK.ordinal()); + tickBreed(); + return; + } + + // Can't continue if an item of the wrong type is in the queen slot. + if (!ForestryItem.beeQueenGE.isItemEqual(housing.getQueen())) { + housing.setErrorState(EnumErrorCode.NOQUEEN.ordinal()); + return; + } + + IBee queen = PluginApiculture.beeInterface.getMember(housing.getQueen()); + // Kill dying queens + if (!queen.isAlive()) { + killQueen(queen); + housing.setErrorState(EnumErrorCode.OK.ordinal()); + return; + } + + resetQueen(queen); + + // Not while raining, at night or without light + EnumErrorCode state = EnumErrorCode.values()[queen.isWorking(housing)]; + if (state != EnumErrorCode.OK) { + housing.setErrorState(state.ordinal()); + return; + } else if (housing.getErrorOrdinal() != EnumErrorCode.NOFLOWER.ordinal()) + housing.setErrorState(EnumErrorCode.OK.ordinal()); + + // Effects only fire when queen can work. + effectData = queen.doEffect(effectData, housing); + + // We have a queen, work! + throttle++; + + if (throttle >= PluginApiculture.beeCycleTicks) + throttle = 0; + else + return; + + // Need a flower + if (!queen.hasFlower(housing)) { + housing.setErrorState(EnumErrorCode.NOFLOWER.ordinal()); + return; + } else + housing.setErrorState(EnumErrorCode.OK.ordinal()); + + // Produce and add stacks + ItemStack[] products = queen.produceStacks(housing); + housing.wearOutEquipment(1); + for (ItemStack stack : products) { + housing.addProduct(stack, false); + } + + // Plant a flower + queen.plantFlowerRandom(housing); + // Get pollen if none available yet + if (pollen == null) { + pollen = queen.retrievePollen(housing); + attemptedPollinations = 0; + if (pollen != null) { + if (housing.onPollenRetrieved(queen, pollen, false)) + pollen = null; + } + } + if (pollen != null) { + attemptedPollinations++; + if (queen.pollinateRandom(housing, pollen) + || attemptedPollinations >= MAX_POLLINATION_ATTEMPTS) { + pollen = null; + } + } + + // Age the queen + queen.age(housing.getWorld(), housing.getLifespanModifier(queen.getGenome(), queen.getMate(), 0f)); + + // Write the changed queen back into the item stack. + NBTTagCompound nbttagcompound = new NBTTagCompound(); + queen.writeToNBT(nbttagcompound); + housing.getQueen().setTagCompound(nbttagcompound); + + return; + } + + private void resetQueen(IBee bee) { + this.queen = bee; + } + + // / BREEDING + private void tickBreed() { + if (!tryBreed()) { + breedingTime = 0; + return; + } + + if (breedingTime < totalBreedingTime) + breedingTime++; + if (breedingTime < totalBreedingTime) + return; + + // Breeding done, create new queen if slot available + if (!ForestryItem.beePrincessGE.isItemEqual(housing.getQueen())) + return; + + // Replace + IBee princess = PluginApiculture.beeInterface.getMember(housing.getQueen()); + IBee drone = PluginApiculture.beeInterface.getMember(housing.getDrone()); + princess.mate(drone); + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + princess.writeToNBT(nbttagcompound); + ItemStack queen = ForestryItem.beeQueenGE.getItemStack(); + queen.setTagCompound(nbttagcompound); + + housing.setQueen(queen); + housing.onQueenChange(housing.getQueen()); + + // Register the new queen with the breeding tracker + PluginApiculture.beeInterface.getBreedingTracker(housing.getWorld(), housing.getOwnerName()).registerQueen(princess); + + // Remove drone + housing.getDrone().stackSize--; + if (housing.getDrone().stackSize <= 0) + housing.setDrone(null); + + // Reset breeding time + breedingTime = 0; + } + + private boolean tryBreed() { + if (housing.getDrone() == null || housing.getQueen() == null) + return false; + + if (!ForestryItem.beeDroneGE.isItemEqual(housing.getDrone()) || !ForestryItem.beePrincessGE.isItemEqual(housing.getQueen())) + return false; + + if (!housing.canBreed()) + return false; + + return true; + } + + private void killQueen(IBee queen) { + if (queen.canSpawn()) { + spawnOffspring(queen); + housing.getQueen().stackSize = 0; + housing.setQueen(null); + } else { + Proxies.log.warning("Tried to spawn offspring off an unmated queen. Devolving her to a princess."); + + ItemStack convert = ForestryItem.beePrincessGE.getItemStack(); + NBTTagCompound nbttagcompound = new NBTTagCompound(); + queen.writeToNBT(nbttagcompound); + convert.setTagCompound(nbttagcompound); + + spawn.add(convert); + housing.setQueen(null); + } + housing.onQueenChange(housing.getQueen()); + } + + /** + * Creates the succeeding princess and between one and three drones. + */ + private void spawnOffspring(IBee queen) { + + Stack offspring = new Stack(); + IApiaristTracker breedingTracker = PluginApiculture.beeInterface.getBreedingTracker(housing.getWorld(), housing.getOwnerName()); + + housing.onQueenDeath(getQueen()); + + // Princess + IBee heiress = queen.spawnPrincess(housing); + if (heiress != null) { + ItemStack princess = PluginApiculture.beeInterface.getMemberStack(heiress, EnumBeeType.PRINCESS.ordinal()); + breedingTracker.registerPrincess(heiress); + offspring.push(princess); + } + + // Drones + IBee[] larvae = queen.spawnDrones(housing); + for (IBee larva : larvae) { + ItemStack drone = PluginApiculture.beeInterface.getMemberStack(larva, EnumBeeType.DRONE.ordinal()); + breedingTracker.registerDrone(larva); + offspring.push(drone); + } + + while (!offspring.isEmpty()) { + ItemStack spawned = offspring.pop(); + if (!housing.addProduct(spawned, true)) + spawn.add(spawned); + } + + housing.onPostQueenDeath(getQueen()); + + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/CommandBeekeepingMode.java b/forestry_common/apiculture/forestry/apiculture/CommandBeekeepingMode.java new file mode 100755 index 000000000..755efb32e --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/CommandBeekeepingMode.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommand; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.apiculture.IBeekeepingMode; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.core.config.Defaults; +import forestry.core.config.Version; +import forestry.core.proxy.Proxies; +import forestry.core.utils.CommandMC; +import forestry.core.utils.StringUtil; +import forestry.plugins.PluginApiculture; + +public class CommandBeekeepingMode extends CommandMC { + + String[] modeStrings; + + public CommandBeekeepingMode() { + modeStrings = new String[PluginApiculture.beeInterface.getBeekeepingModes().size()]; + for (int i = 0; i < PluginApiculture.beeInterface.getBeekeepingModes().size(); i++) + modeStrings[i] = PluginApiculture.beeInterface.getBeekeepingModes().get(i).getName(); + } + + @Override + public int compareTo(Object arg0) { + return this.getCommandName().compareTo(((ICommand) arg0).getCommandName()); + } + + @Override + public String getCommandName() { + return "beekeeping"; + } + + @Override + public String getCommandUsage(ICommandSender var1) { + return "/" + this.getCommandName() + " help"; + } + + @SuppressWarnings("rawtypes") + @Override + public List getCommandAliases() { + return null; + } + + @Override + public void processCommand(ICommandSender sender, String[] arguments) { + + if (arguments.length <= 0) + throw new WrongUsageException("Type '" + this.getCommandUsage(sender) + "' for help."); + + if (arguments[0].matches("list")) + listModes(sender, arguments); + else if (arguments[0].matches("info")) + listModeInfo(sender, arguments); + else if (arguments[0].matches("set")) { + if (arguments.length <= 1) + throw new WrongUsageException("/" + this.getCommandName() + " set [] "); + + World world = getWorld(sender, arguments); + String desired = arguments[arguments.length - 1]; + + IBeekeepingMode mode = PluginApiculture.beeInterface.getBeekeepingMode(desired); + if (mode == null) + throw new CommandException("A bekeeping mode called '%s' is not available.", desired); + + PluginApiculture.beeInterface.setBeekeepingMode(world, mode.getName()); + notifyAdmins(sender, "Beekeeping mode set to %s.", mode.getName()); + + } else if (arguments[0].matches("save")) { + if (arguments.length <= 1) + throw new WrongUsageException("/" + this.getCommandName() + " save "); + + saveStatistics(sender, arguments); + } else if (arguments[0].matches("help")) { + sendChatMessage(sender, "Format: '/" + this.getCommandName() + " '"); + sendChatMessage(sender, "Available commands:"); + sendChatMessage(sender, "- list []: lists current and available beekeeping modes."); + sendChatMessage(sender, "- info : information on beekeeping mode."); + sendChatMessage(sender, "- set [] : set beekeeping mode for world."); + sendChatMessage(sender, "- save [] : save beekeeping statistics for the given player."); + } + } + + private void saveStatistics(ICommandSender sender, String[] arguments) { + + String newLine = System.getProperty("line.separator"); + World world = getWorld(sender, arguments); + + String player = arguments[1]; + Collection statistics = new ArrayList(); + + statistics.add(String.format("Beekeeping statistics for %s on %s:", player, DateFormat.getInstance().format(new Date()))); + statistics.add(""); + statistics.add("MODE: " + PluginApiculture.beeInterface.getBeekeepingMode(world).getName()); + statistics.add(""); + + IApiaristTracker tracker = PluginApiculture.beeInterface.getBreedingTracker(world, player); + if (tracker == null) + statistics.add("No statistics found."); + else { + statistics.add("BRED:"); + statistics.add("-----"); + statistics.add(""); + + statistics.add("Queens:\t\t" + tracker.getQueenCount()); + statistics.add("Princesses:\t" + tracker.getPrincessCount()); + statistics.add("Drones:\t\t" + tracker.getDroneCount()); + statistics.add(""); + + Collection species = new ArrayList(); + for (IAllele allele : AlleleManager.alleleRegistry.getRegisteredAlleles().values()) + if (allele instanceof IAlleleBeeSpecies) + species.add((IAlleleBeeSpecies) allele); + + statistics.add(String.format("SPECIES (%s):", species.size())); + statistics.add("-------------"); + statistics.add(""); + + for (IAlleleBeeSpecies allele : species) + statistics.add(generateSpeciesListEntry(allele, tracker)); + } + + File file = new File(Proxies.common.getForestryRoot(), "config/" + Defaults.MOD.toLowerCase(Locale.ENGLISH) + "/stats/" + player + ".log"); + try { + + if (file.getParentFile() != null) + file.getParentFile().mkdirs(); + + if (!file.exists() && !file.createNewFile()) { + sendChatMessage(sender, "Log file could not be created. Failed to save statistics."); + return; + } + + if (!file.canWrite()) { + sendChatMessage(sender, "Cannot write to log file. Failed to save statistics."); + return; + } + + FileOutputStream fileout = new FileOutputStream(file); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fileout, "UTF-8")); + + writer.write("# " + Defaults.MOD + newLine + "# " + Version.getVersion() + newLine); + + for (String line : statistics) + writer.write(line + newLine); + + writer.close(); + + } catch (Exception ex) { + sendChatMessage(sender, "Write operation threw an exception. Failed to save statistics."); + ex.printStackTrace(); + } + + sendChatMessage(sender, "Saved statistics for player " + player); + } + + private String generateSpeciesListEntry(IAlleleBeeSpecies species, IApiaristTracker tracker) { + String discovered = "[ ]"; + if (tracker.isDiscovered(species)) + discovered = "[ X ]"; + String blacklisted = "[ ]"; + if (AlleleManager.alleleRegistry.isBlacklisted(species.getUID())) + blacklisted = "[ BL ]"; + String notcounted = "[ ]"; + if (!species.isCounted()) + notcounted = "[ NC ]"; + + return String.format("%s %s %s\t%-40s %-20s %-20s", discovered, blacklisted, notcounted, species.getUID(), species.getName(), species.getAuthority()); + } + + private void listModes(ICommandSender sender, String[] arguments) { + World world = getWorld(sender, arguments); + + sendChatMessage(sender, "Current: " + PluginApiculture.beeInterface.getBeekeepingMode(world).getName() + " (#" + world.getWorldInfo().getSaveVersion() + ")"); + + String help = ""; + for (IBeekeepingMode mode : PluginApiculture.beeInterface.getBeekeepingModes()) { + if (!help.isEmpty()) + help += ", "; + help += mode.getName(); + } + sendChatMessage(sender, "Available modes: " + help); + return; + } + + private void listModeInfo(ICommandSender sender, String[] arguments) { + if (arguments.length <= 1) + throw new WrongUsageException("/" + this.getCommandName() + " info "); + + IBeekeepingMode found = null; + for (IBeekeepingMode mode : PluginApiculture.beeInterface.getBeekeepingModes()) + if (mode.getName().equalsIgnoreCase(arguments[1])) { + found = mode; + break; + } + + if (found == null) + throw new CommandException("No beekeeping mode called '%s' is available.", arguments[1]); + + sendChatMessage(sender, "\u00A7aMode: " + found.getName()); + for (String desc : found.getDescription()) + sendChatMessage(sender, StringUtil.localize(desc)); + } + + @Override + public boolean canCommandSenderUseCommand(ICommandSender sender) { + if (sender instanceof EntityPlayer) + return Proxies.common.isOp((EntityPlayer) sender); + else + return sender.canCommandSenderUseCommand(4, getCommandName()); + } + + @SuppressWarnings("rawtypes") + @Override + public List addTabCompletionOptions(ICommandSender sender, String[] incomplete) { + return getListOfStringsMatchingLastWord(incomplete, modeStrings); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/CommandGiveBee.java b/forestry_common/apiculture/forestry/apiculture/CommandGiveBee.java new file mode 100755 index 000000000..4f32808c2 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/CommandGiveBee.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleSpecies; +import forestry.core.utils.CommandMC; +import forestry.plugins.PluginApiculture; + +public class CommandGiveBee extends CommandMC { + + EnumBeeType type; + + public CommandGiveBee(EnumBeeType type) { + this.type = type; + } + + @Override + public String getCommandName() { + return "give" + type.toString().toLowerCase(); + } + + @Override + public String getCommandUsage(ICommandSender par1ICommandSender) { + return "/" + getCommandName() + " "; + } + + @Override + public void processCommand(ICommandSender sender, String[] arguments) { + if (arguments.length >= 2) { + + EntityPlayer player = getPlayerFromName(arguments[0]); + + String parameter = arguments[1]; + + IAlleleBeeSpecies species = null; + + search: for (String uid : AlleleManager.alleleRegistry.getRegisteredAlleles().keySet()) { + + if (!uid.equals(parameter)) + continue; + + if (AlleleManager.alleleRegistry.getAllele(uid) instanceof IAlleleBeeSpecies) { + species = (IAlleleBeeSpecies) AlleleManager.alleleRegistry.getAllele(uid); + break search; + } + } + + search: if (species == null) + for (IAllele allele : AlleleManager.alleleRegistry.getRegisteredAlleles().values()) + if (allele instanceof IAlleleBeeSpecies) + if (((IAlleleBeeSpecies) allele).getName().equals(parameter)) { + species = (IAlleleBeeSpecies) allele; + break search; + } + + if (species == null) + throw new SpeciesNotFoundException(parameter); + + IAllele[] template = PluginApiculture.beeInterface.getTemplate(species.getUID()); + + if (template == null) + throw new TemplateNotFoundException(species); + + IBeeGenome genome = PluginApiculture.beeInterface.templateAsGenome(template); + + IBee bee = PluginApiculture.beeInterface.getBee(player.worldObj, genome); + + ItemStack beestack = PluginApiculture.beeInterface.getMemberStack(bee, type.ordinal()); + player.dropPlayerItemWithRandomChoice(beestack, true); + notifyAdmins(sender, "Player %s was given a %s bee.", player.getCommandSenderName(), ((IAlleleSpecies) template[0]).getName()); + } else + throw new WrongUsageException("/" + getCommandName() + " "); + } + + /** + * Adds the strings available in this command to the given list of tab completion options. + */ + @SuppressWarnings("rawtypes") + @Override + public List addTabCompletionOptions(ICommandSender sender, String[] parameters) { + if (parameters.length == 1) + return getListOfStringsMatchingLastWord(parameters, this.getPlayers()); + else if (parameters.length == 2) + return getListOfStringsMatchingLastWord(parameters, this.getSpecies()); + else + return null; + } + + protected String[] getSpecies() { + List species = new ArrayList(); + + for (IAllele allele : AlleleManager.alleleRegistry.getRegisteredAlleles().values()) + if (allele instanceof IAlleleBeeSpecies) + species.add(((IAlleleSpecies) allele).getName()); + + return species.toArray(new String[] {}); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderCacti.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderCacti.java new file mode 100755 index 000000000..16cf11943 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderCacti.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class FlowerProviderCacti implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + // Specific check for flower pots. + if (block == Blocks.flower_pot) + return checkFlowerPot(world.getBlockMetadata(x, y, z)); + + return block == Blocks.cactus; + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + return pollinatable.getPlantType().contains(EnumPlantType.Desert); + } + + private boolean checkFlowerPot(int meta) { + if (meta == 9) + return true; + else + return false; + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + if (block == Blocks.flower_pot && world.getBlockMetadata(x, y, z) == 0) + return growInPot(world, x, y, z); + + return false; + } + + private boolean growInPot(World world, int x, int y, int z) { + if (world.rand.nextBoolean()) + world.setBlock(x, y, z, Blocks.flower_pot, 9, Defaults.FLAG_BLOCK_SYNCH); + else + world.setBlock(x, y, z, Blocks.flower_pot, 10, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.cacti"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return new ItemStack[] { new ItemStack(Blocks.cactus) }; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderEnd.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderEnd.java new file mode 100755 index 000000000..41646aa09 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderEnd.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.EnumSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.utils.StringUtil; + +public class FlowerProviderEnd implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + return block == Blocks.dragon_egg; + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + EnumSet types = pollinatable.getPlantType(); + return types.size() > 1 || !types.contains(EnumPlantType.Nether); + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.end"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return new ItemStack[] { new ItemStack(Blocks.dragon_egg) }; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderGourd.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderGourd.java new file mode 100755 index 000000000..fe8e68201 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderGourd.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.EnumSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class FlowerProviderGourd implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + return block == Blocks.pumpkin_stem || block == Blocks.melon_stem; + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + EnumSet types = pollinatable.getPlantType(); + return types.size() > 1 || !types.contains(EnumPlantType.Nether); + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + + Block block = world.getBlock(x, y, z); + + // We only grow wheat, we don't plant it + if (block != Blocks.pumpkin_stem && block != Blocks.melon_stem) + return false; + + int meta = world.getBlockMetadata(x, y, z); + if (meta > 6) + return false; + + if (meta < 6) + meta += 2; + else + meta = 7; + + world.setBlockMetadataWithNotify(x, y, z, meta, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.gourd"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return new ItemStack[] { new ItemStack(Blocks.wheat, 1, 8) }; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderJungle.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderJungle.java new file mode 100755 index 000000000..1161fb1dd --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderJungle.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.EnumSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class FlowerProviderJungle implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + int meta = world.getBlockMetadata(x, y, z); + + // Specific check for flower pots. + if (block == Blocks.flower_pot) + return checkFlowerPot(meta); + + return block == Blocks.vine || (block == Blocks.tallgrass && meta == 2); + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + EnumSet types = pollinatable.getPlantType(); + return types.size() > 1 || !types.contains(EnumPlantType.Nether); + } + + private boolean checkFlowerPot(int meta) { + if (meta == 11) + return true; + else + return false; + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + if (block == Blocks.flower_pot) + return growInPot(world, x, y, z); + + return false; + } + + private boolean growInPot(World world, int x, int y, int z) { + world.setBlock(x, y, z, Blocks.flower_pot, 11, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.jungle"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return new ItemStack[] { new ItemStack(Blocks.vine), new ItemStack(Blocks.tallgrass, 1, 2) }; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderMushroom.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderMushroom.java new file mode 100755 index 000000000..221dc72b9 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderMushroom.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.EnumSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class FlowerProviderMushroom implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + // Specific check for flower pots. + if (block == Blocks.flower_pot) + return checkFlowerPot(world.getBlockMetadata(x, y, z)); + + return block == Blocks.brown_mushroom || block == Blocks.red_mushroom; + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + EnumSet types = pollinatable.getPlantType(); + return types.size() > 1 || !types.contains(EnumPlantType.Nether); + } + + private boolean checkFlowerPot(int meta) { + if (meta == 7 || meta == 8) + return true; + else + return false; + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + if (!block.isAir(world, x, y, z)) + if (block == Blocks.flower_pot) + return growInPot(world, x, y, z); + else + return false; + + // Check ground + Block ground = world.getBlock(x, y - 1, z); + + if (ground != Blocks.mycelium) + return false; + + Block mushroom; + if (world.rand.nextBoolean()) + mushroom = Blocks.brown_mushroom; + else + mushroom = Blocks.red_mushroom; + + world.setBlock(x, y, z, mushroom, 0, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + private boolean growInPot(World world, int x, int y, int z) { + if (world.rand.nextBoolean()) + world.setBlock(x, y, z, Blocks.flower_pot, 7, Defaults.FLAG_BLOCK_SYNCH); + else + world.setBlock(x, y, z, Blocks.flower_pot, 8, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.mushroom"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return new ItemStack[] { new ItemStack(Blocks.brown_mushroom), new ItemStack(Blocks.red_mushroom) }; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderNetherwart.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderNetherwart.java new file mode 100755 index 000000000..50771fcd7 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderNetherwart.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class FlowerProviderNetherwart implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + return block == Blocks.nether_wart; + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + return pollinatable.getPlantType().contains(EnumPlantType.Nether); + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + + Block block = world.getBlock(x, y, z); + + // We only grow netherwart, we don't plant it + if (block != Blocks.nether_wart) + return false; + + int meta = world.getBlockMetadata(x, y, z); + if (meta >= 3) + return false; + + if (meta == 2) + meta = 3; + else + meta = 2; + + world.setBlockMetadataWithNotify(x, y, z, meta, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.nether"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return new ItemStack[] { new ItemStack(Blocks.nether_wart) }; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderVanilla.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderVanilla.java new file mode 100755 index 000000000..52d7a66f6 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderVanilla.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.Collections; +import java.util.EnumSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.apiculture.FlowerManager; +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Defaults; +import forestry.core.utils.StackUtils; +import forestry.core.utils.StringUtil; + +public class FlowerProviderVanilla implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + + Block block = world.getBlock(x, y, z); + int meta = world.getBlockMetadata(x, y, z); + + // Specific check for flower pots. + if (block == Blocks.flower_pot) + return checkFlowerPot(meta); + + ItemStack flower = new ItemStack(block, 1, meta); + + for (ItemStack stack : FlowerManager.plainFlowers) + if (flower.isItemEqual(stack)) + return true; + + return false; + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + EnumSet types = pollinatable.getPlantType(); + return types.size() > 1 || !types.contains(EnumPlantType.Nether); + } + + private boolean checkFlowerPot(int meta) { + if (meta == 1 || meta == 2) + return true; + else + return false; + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + + Block block = world.getBlock(x, y, z); + + if (!block.isAir(world, x, y, z)) + if (block == Blocks.flower_pot && world.getBlockMetadata(x, y, z) == 0) + return growInPot(world, x, y, z); + else + return false; + + // Check ground + Block ground = world.getBlock(x, y - 1, z); + + if (ground != Blocks.dirt && ground != Blocks.grass) + return false; + + // Determine flower to plant + Collections.shuffle(FlowerManager.plainFlowers); + ItemStack flower = FlowerManager.plainFlowers.get(world.rand.nextInt(FlowerManager.plainFlowers.size() - 1)); + world.setBlock(x, y, z, StackUtils.getBlock(flower), flower.getItemDamage(), Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + private boolean growInPot(World world, int x, int y, int z) { + if (world.rand.nextBoolean()) + world.setBlock(x, y, z, Blocks.flower_pot, 1, Defaults.FLAG_BLOCK_SYNCH); + else + world.setBlock(x, y, z, Blocks.flower_pot, 2, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.vanilla"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return FlowerManager.plainFlowers.toArray(new ItemStack[0]); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/FlowerProviderWheat.java b/forestry_common/apiculture/forestry/apiculture/FlowerProviderWheat.java new file mode 100755 index 000000000..95d4d2bce --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/FlowerProviderWheat.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.EnumSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class FlowerProviderWheat implements IFlowerProvider { + + @Override + public boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + return block == Blocks.wheat; + } + + @Override + public boolean isAcceptedPollinatable(World world, IPollinatable pollinatable) { + EnumSet types = pollinatable.getPlantType(); + return types.size() > 1 || !types.contains(EnumPlantType.Nether); + } + + @Override + public boolean growFlower(World world, IIndividual individual, int x, int y, int z) { + + Block block = world.getBlock(x, y, z); + + // We only grow wheat, we don't plant it + if (block != Blocks.wheat) + return false; + + int meta = world.getBlockMetadata(x, y, z); + if (meta > 6) + return false; + + if (meta < 6) + meta += 2; + else + meta = 7; + + world.setBlockMetadataWithNotify(x, y, z, meta, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + @Override + public String getDescription() { + return StringUtil.localize("flowers.wheat"); + } + + @Override + public ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products) { + return products; + } + + @Override + public ItemStack[] getItemStacks() { + return new ItemStack[] { new ItemStack(Blocks.wheat, 1, 8) }; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/GuiHandlerApiculture.java b/forestry_common/apiculture/forestry/apiculture/GuiHandlerApiculture.java new file mode 100755 index 000000000..d2ba46b9f --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/GuiHandlerApiculture.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.apiculture.gadgets.TileAlvearyHygroregulator; +import forestry.apiculture.gadgets.TileAlvearyPlain; +import forestry.apiculture.gadgets.TileAlvearySieve; +import forestry.apiculture.gadgets.TileAlvearySwarmer; +import forestry.apiculture.gadgets.TileApiary; +import forestry.apiculture.gadgets.TileBeehouse; +import forestry.apiculture.genetics.BeeHelper; +import forestry.apiculture.gui.ContainerAlveary; +import forestry.apiculture.gui.ContainerAlvearyHygroregulator; +import forestry.apiculture.gui.ContainerAlvearySieve; +import forestry.apiculture.gui.ContainerAlvearySwarmer; +import forestry.apiculture.gui.ContainerApiary; +import forestry.apiculture.gui.ContainerBeealyzer; +import forestry.apiculture.gui.ContainerHabitatLocator; +import forestry.apiculture.gui.ContainerImprinter; +import forestry.apiculture.gui.GuiAlveary; +import forestry.apiculture.gui.GuiAlvearyHygroregulator; +import forestry.apiculture.gui.GuiAlvearySieve; +import forestry.apiculture.gui.GuiAlvearySwarmer; +import forestry.apiculture.gui.GuiApiary; +import forestry.apiculture.gui.GuiBeealyzer; +import forestry.apiculture.gui.GuiHabitatLocator; +import forestry.apiculture.gui.GuiImprinter; +import forestry.apiculture.items.ItemBeealyzer.BeealyzerInventory; +import forestry.apiculture.items.ItemBiomefinder.BiomefinderInventory; +import forestry.apiculture.items.ItemImprinter.ImprinterInventory; +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; +import forestry.plugins.PluginApiculture; + +public class GuiHandlerApiculture extends GuiHandlerBase { + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + int guiData = decodeGuiData(id); + + if (cleanId >= GuiId.values().length) + return null; + + ItemStack equipped; + switch (GuiId.values()[cleanId]) { + + case AlvearyGUI: + return new GuiAlveary(player.inventory, (TileAlvearyPlain) getTileForestry(world, x, y, z)); + + case AlvearySieveGUI: + return new GuiAlvearySieve(player.inventory, (TileAlvearySieve) getTileForestry(world, x, y, z)); + + case AlvearySwarmerGUI: + return new GuiAlvearySwarmer(player.inventory, (TileAlvearySwarmer) getTileForestry(world, x, y, z)); + + case ApiaristChestGUI: + return getNaturalistChestGui(BeeHelper.UID, player, world, x, y, z, guiData); + + case ApiaryGUI: + return new GuiApiary(player.inventory, (TileApiary) getTileForestry(world, x, y, z)); + + case BeealyzerGUI: + equipped = getEquippedItem(player); + if (equipped == null) + return null; + + return new GuiBeealyzer(player, new BeealyzerInventory(player, equipped)); + + case BeehouseGUI: + return new GuiApiary(player.inventory, (TileBeehouse) getTileForestry(world, x, y, z)); + + case HabitatLocatorGUI: + equipped = getEquippedItem(player); + if (equipped == null) + return null; + + return new GuiHabitatLocator(player.inventory, new BiomefinderInventory(equipped)); + + case HygroregulatorGUI: + return new GuiAlvearyHygroregulator(player.inventory, (TileAlvearyHygroregulator) getTileForestry(world, x, y, z)); + + case ImprinterGUI: + return new GuiImprinter(player.inventory, new ImprinterInventory(player)); + + default: + return null; + + } + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + int guiData = decodeGuiData(id); + + if (cleanId >= GuiId.values().length) + return null; + + ItemStack equipped; + switch (GuiId.values()[cleanId]) { + + case AlvearyGUI: + synchApiaristTracker(world, player); + return new ContainerAlveary(player.inventory, (TileAlvearyPlain) getTileForestry(world, x, y, z)); + + case AlvearySieveGUI: + return new ContainerAlvearySieve(player.inventory, (TileAlvearySieve) getTileForestry(world, x, y, z)); + + case AlvearySwarmerGUI: + return new ContainerAlvearySwarmer(player.inventory, (TileAlvearySwarmer) getTileForestry(world, x, y, z)); + + case ApiaristChestGUI: + return getNaturalistChestContainer(BeeHelper.UID, player, world, x, y, z, guiData); + + case ApiaryGUI: + synchApiaristTracker(world, player); + return new ContainerApiary(player.inventory, (TileApiary) getTileForestry(world, x, y, z), true); + + case BeealyzerGUI: + equipped = getEquippedItem(player); + if (equipped == null) + return null; + + synchApiaristTracker(world, player); + return new ContainerBeealyzer(player.inventory, new BeealyzerInventory(player, equipped)); + + case BeehouseGUI: + synchApiaristTracker(world, player); + return new ContainerApiary(player.inventory, (TileBeehouse) getTileForestry(world, x, y, z), false); + + case HabitatLocatorGUI: + equipped = getEquippedItem(player); + if (equipped == null) + return null; + + return new ContainerHabitatLocator(player.inventory, new BiomefinderInventory(equipped)); + + case HygroregulatorGUI: + return new ContainerAlvearyHygroregulator(player.inventory, (TileAlvearyHygroregulator) getTileForestry(world, x, y, z)); + + case ImprinterGUI: + synchApiaristTracker(world, player); + return new ContainerImprinter(player.inventory, new ImprinterInventory(player)); + + default: + return null; + + } + } + + private void synchApiaristTracker(World world, EntityPlayer player) { + PluginApiculture.beeInterface.getBreedingTracker(world, player.getGameProfile().getId()).synchToPlayer(player); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/MaterialBeehive.java b/forestry_common/apiculture/forestry/apiculture/MaterialBeehive.java new file mode 100755 index 000000000..2f2e911aa --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/MaterialBeehive.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; + +public class MaterialBeehive extends Material { + + public MaterialBeehive(boolean noHarvest) { + super(MapColor.stoneColor); + if (noHarvest) + this.setRequiresTool(); + setImmovableMobility(); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/PacketHandlerApiculture.java b/forestry_common/apiculture/forestry/apiculture/PacketHandlerApiculture.java new file mode 100755 index 000000000..8b3ea1cac --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/PacketHandlerApiculture.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.io.DataInputStream; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.apiculture.gui.ContainerImprinter; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.network.PacketCoordinates; +import forestry.core.network.PacketIds; +import forestry.core.proxy.Proxies; + +public class PacketHandlerApiculture implements IPacketHandler { + + @Override + public void onPacketData(int packetID, DataInputStream data, EntityPlayer player) { + + try { + + switch (packetID) { + case PacketIds.HABITAT_BIOME_POINTER: + PacketCoordinates packetC = new PacketCoordinates(); + packetC.readData(data); + Proxies.common.setBiomefinderCoordinates(player, packetC.getCoordinates()); + break; + case PacketIds.IMPRINT_SELECTION_GET: + onImprintSelectionGet(player); + break; + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + private void onImprintSelectionGet(EntityPlayer playerEntity) { + + if (!(playerEntity.openContainer instanceof ContainerImprinter)) + return; + + ((ContainerImprinter) playerEntity.openContainer).sendSelection(playerEntity); + + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/SaveEventHandlerApiculture.java b/forestry_common/apiculture/forestry/apiculture/SaveEventHandlerApiculture.java new file mode 100755 index 000000000..13daf87ad --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/SaveEventHandlerApiculture.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import net.minecraft.world.World; + +import forestry.core.interfaces.ISaveEventHandler; +import forestry.plugins.PluginApiculture; + +public class SaveEventHandlerApiculture implements ISaveEventHandler { + + @Override + public void onWorldLoad(World world) { + PluginApiculture.beeInterface.resetBeekeepingMode(); + } + + @Override + public void onWorldSave(World world) { + } + + @Override + public void onWorldUnload(World world) { + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/SpeciesNotFoundException.java b/forestry_common/apiculture/forestry/apiculture/SpeciesNotFoundException.java new file mode 100755 index 000000000..99d47b8a3 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/SpeciesNotFoundException.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import net.minecraft.command.CommandException; + +public class SpeciesNotFoundException extends CommandException { + + private static final long serialVersionUID = 1L; + + public SpeciesNotFoundException(String title) { + super("Could not find bee species with Name or UID %s", title); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/TemplateNotFoundException.java b/forestry_common/apiculture/forestry/apiculture/TemplateNotFoundException.java new file mode 100755 index 000000000..6f05e7401 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/TemplateNotFoundException.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import net.minecraft.command.CommandException; + +import forestry.api.genetics.IAlleleSpecies; + +public class TemplateNotFoundException extends CommandException { + + private static final long serialVersionUID = 1L; + + public TemplateNotFoundException(IAlleleSpecies species) { + super("Could not find template for species %s with UID %s", species.getName(), species.getUID()); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/VillageHandlerApiculture.java b/forestry_common/apiculture/forestry/apiculture/VillageHandlerApiculture.java new file mode 100755 index 000000000..c5f711fb8 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/VillageHandlerApiculture.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture; + +import java.util.List; +import java.util.Random; + +import net.minecraft.entity.passive.EntityVillager; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MathHelper; +import net.minecraft.village.MerchantRecipe; +import net.minecraft.village.MerchantRecipeList; +import net.minecraft.world.gen.structure.MapGenStructureIO; +import net.minecraft.world.gen.structure.StructureVillagePieces; + +import cpw.mods.fml.common.registry.VillagerRegistry.IVillageCreationHandler; +import cpw.mods.fml.common.registry.VillagerRegistry.IVillageTradeHandler; + +import forestry.api.apiculture.EnumBeeType; +import forestry.apiculture.genetics.BeeTemplates; +import forestry.apiculture.items.ItemHoneycomb; +import forestry.apiculture.worldgen.ComponentVillageBeeHouse; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.plugins.PluginApiculture; + +public class VillageHandlerApiculture implements IVillageCreationHandler, IVillageTradeHandler { + + public static void registerVillageComponents() { + try { + MapGenStructureIO.func_143031_a(ComponentVillageBeeHouse.class, "Forestry:BeeHouse"); + } catch (Throwable e) { + } + } + + @SuppressWarnings("unchecked") + @Override + public void manipulateTradesForVillager(EntityVillager villager, MerchantRecipeList recipeList, Random random) { + recipeList.add(new MerchantRecipe(ForestryItem.beePrincessGE.getItemStack(1, Defaults.WILDCARD), new ItemStack(Items.emerald, 1))); + recipeList.add(new MerchantRecipe(new ItemStack(Items.wheat, 2), ItemHoneycomb.getRandomComb(1, random, false))); + recipeList.add(new MerchantRecipe(new ItemStack(Blocks.log, 24, Defaults.WILDCARD), new ItemStack(ForestryBlock.apiculture, 1, + Defaults.DEFINITION_APIARY_META))); + recipeList.add(new MerchantRecipe(new ItemStack(Items.emerald, 1), ForestryItem.frameProven.getItemStack(6))); + recipeList.add(new MerchantRecipe(new ItemStack(Items.emerald, 12), ForestryItem.beePrincessGE.getItemStack(1, Defaults.WILDCARD), + PluginApiculture.beeInterface.getMemberStack( + PluginApiculture.beeInterface.getBee(villager.worldObj, PluginApiculture.beeInterface.templateAsGenome(BeeTemplates.getMonasticTemplate())), + EnumBeeType.DRONE.ordinal()))); + } + + @Override + public StructureVillagePieces.PieceWeight getVillagePieceWeight(Random random, int size) { + return new StructureVillagePieces.PieceWeight(ComponentVillageBeeHouse.class, 15, MathHelper.getRandomIntegerInRange(random, 0 + size, 1 + size)); + } + + @Override + public Class getComponentClass() { + return ComponentVillageBeeHouse.class; + } + + @SuppressWarnings("rawtypes") + @Override + public Object buildComponent(StructureVillagePieces.PieceWeight villagePiece, StructureVillagePieces.Start startPiece, List pieces, Random random, int p1, int p2, + int p3, int p4, int p5) { + return ComponentVillageBeeHouse.buildComponent(startPiece, pieces, random, p1, p2, p3, p4, p5); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/entities/EntityBee.java b/forestry_common/apiculture/forestry/apiculture/entities/EntityBee.java new file mode 100755 index 000000000..8e765e4e7 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/entities/EntityBee.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.entities; + +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.passive.IAnimals; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBee; +import forestry.core.config.Defaults; +import forestry.core.utils.ForestryResource; +import forestry.plugins.PluginApiculture; + +public class EntityBee extends EntityCreature implements IAnimals { + + private static final String DEFAULT_TEXTURE = Defaults.TEXTURE_PATH_ENTITIES + "/bees/honeyBee.png"; + + IBee contained; + IAlleleBeeSpecies species; + EnumBeeType type = EnumBeeType.DRONE; + + private String beeTexture = DEFAULT_TEXTURE; + private long lastUpdate; + + public EntityBee(World world) { + super(world); + } + + private void resetAppearance() { + beeTexture = species.getEntityTexture(); + } + + public EntityBee setIndividual(IBee bee) { + if(bee != null) + contained = bee; + else + contained = PluginApiculture.beeInterface.templateAsIndividual(PluginApiculture.beeInterface.getDefaultTemplate()); + + //isImmuneToFire = contained.getGenome().getFireResist(); + setSpecies(contained.getGenome().getPrimary()); + //dataWatcher.updateObject(DATAWATCHER_ID_SPECIES, species.getUID()); + //dataWatcher.updateObject(DATAWATCHER_ID_SCALE, (int)(contained.getSize() * 100)); + return this; + } + + public IBee getBee() { + return contained; + } + + public EntityBee setType(EnumBeeType type) { + this.type = type; + return this; + } + + public EnumBeeType getType() { + return type; + } + + public EntityBee setSpecies(IAlleleBeeSpecies species) { + this.species = species; + resetAppearance(); + lastUpdate = worldObj.getTotalWorldTime(); + return this; + } + + @SideOnly(Side.CLIENT) + private ResourceLocation textureResource; + private long lastTextureUpdate; + @SideOnly(Side.CLIENT) + public ResourceLocation getTexture() { + if(textureResource == null || lastTextureUpdate != lastUpdate) + textureResource = new ForestryResource(beeTexture); + + return textureResource; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/BlockAlveary.java b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockAlveary.java new file mode 100755 index 000000000..00b42a0b4 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockAlveary.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.Tabs; +import forestry.apiculture.MaterialBeehive; +import forestry.core.gadgets.BlockStructure; +import forestry.core.render.TextureManager; + +public class BlockAlveary extends BlockStructure { + + public BlockAlveary() { + super(new MaterialBeehive(false)); + setHardness(1.0f); + setCreativeTab(Tabs.tabApiculture); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + @SideOnly(Side.CLIENT) + public void getSubBlocks(Item item, CreativeTabs tab, List list) { + for (int i = 0; i < 8; i++) { + if (i == 1) + continue; + list.add(new ItemStack(item, 1, i)); + } + } + + @Override + public int getRenderType() { + return 0; + } + + @Override + public boolean renderAsNormalBlock() { + return true; + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + ArrayList drop = new ArrayList(); + drop.add(new ItemStack(this, 1, metadata != 1 ? metadata : 0)); + return drop; + } + + @Override + public int getDamageValue(World world, int x, int y, int z) { + int meta = world.getBlockMetadata(x, y, z); + return meta != 1 ? meta : 0; + } + + /* TILE ENTITY CREATION */ + @Override + public TileEntity createTileEntity(World world, int metadata) { + switch (metadata) { + case TileAlvearySwarmer.BLOCK_META: + return new TileAlvearySwarmer(); + case TileAlvearyFan.BLOCK_META: + return new TileAlvearyFan(); + case TileAlvearyHeater.BLOCK_META: + return new TileAlvearyHeater(); + case TileAlvearyHygroregulator.BLOCK_META: + return new TileAlvearyHygroregulator(); + case TileAlvearyStabiliser.BLOCK_META: + return new TileAlvearyStabiliser(); + case TileAlvearySieve.BLOCK_META: + return new TileAlvearySieve(); + default: + return new TileAlvearyPlain(); + } + } + + @Override + public TileEntity createNewTileEntity(World world, int meta) { + return createTileEntity(world, meta); + } + + /* ICONS */ + public static final int PLAIN = 0; + public static final int ENTRANCE = 1; + public static final int BOTTOM = 2; + public static final int LEFT = 3; + public static final int RIGHT = 4; + public static final int TX_55_SWOF = 5; + public static final int TX_56_SWON = 6; + public static final int TX_57_HTOF = 7; + public static final int TX_58_HTON = 8; + public static final int TX_71_FNOF = 9; + public static final int TX_72_FNON = 10; + public static final int TX_73_VLVE = 11; + public static final int STABILISER = 12; + public static final int SIEVE = 13; + + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + icons = new IIcon[14]; + icons[0] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.plain"); + icons[1] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.entrance"); + icons[2] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.bottom"); + icons[3] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.left"); + icons[4] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.right"); + icons[5] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.swarmer.off"); + icons[6] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.swarmer.on"); + icons[7] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.heater.off"); + icons[8] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.heater.on"); + icons[9] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.fan.off"); + icons[10] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.fan.on"); + icons[11] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.valve"); + icons[12] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.stabiliser"); + icons[13] = TextureManager.getInstance().registerTex(register, "apiculture/alveary.sieve"); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int metadata) { + if ((metadata <= 1 + || metadata == TileAlvearySieve.BLOCK_META || metadata == TileAlvearySwarmer.BLOCK_META || metadata == TileAlvearyStabiliser.BLOCK_META) + && (side == 1 || side == 0)) + return icons[BOTTOM]; + + switch (metadata) { + case 1: + return icons[ENTRANCE]; + case TileAlvearySwarmer.BLOCK_META: + return icons[TX_55_SWOF]; + case TileAlvearyFan.BLOCK_META: + return icons[TX_71_FNOF]; + case TileAlvearyHeater.BLOCK_META: + return icons[TX_57_HTOF]; + case TileAlvearyHygroregulator.BLOCK_META: + return icons[TX_73_VLVE]; + case TileAlvearyStabiliser.BLOCK_META: + return icons[STABILISER]; + case TileAlvearySieve.BLOCK_META: + return icons[SIEVE]; + default: + return icons[PLAIN]; + } + + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + int meta = world.getBlockMetadata(x, y, z); + + if (meta == 1) + return this.getIcon(side, meta); + else if (meta > 1) + return getBlockTextureFromSideAndTile(world, x, y, z, side); + + Block blockXP = world.getBlock(x + 1, y, z); + Block blockXM = world.getBlock(x - 1, y, z); + + if (blockXP == this && blockXM != this) { + + if (world.getBlockMetadata(x + 1, y, z) == 1) { + + if (world.getBlock(x, y, z + 1) != this) + return switchForSide(42, side); + else + return switchForSide(41, side); + + } else + return this.getIcon(side, meta); + + } else if (blockXP != this && blockXM == this) + if (world.getBlockMetadata(x - 1, y, z) == 1) { + + if (world.getBlock(x, y, z + 1) != this) + return switchForSide(41, side); + else + return switchForSide(42, side); + + } else + return this.getIcon(side, meta); + + return this.getIcon(side, meta); + } + + @SideOnly(Side.CLIENT) + private IIcon getBlockTextureFromSideAndTile(IBlockAccess world, int x, int y, int z, int side) { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile == null || !(tile instanceof TileAlveary)) + return getIcon(side, 0); + + return icons[((TileAlveary) tile).getIcon(side, world.getBlockMetadata(x, y, z))]; + } + + @SideOnly(Side.CLIENT) + private IIcon switchForSide(int textureId, int side) { + + if (side == 4 || side == 5) { + if (textureId == 41) + return icons[LEFT]; + else + return icons[RIGHT]; + } else if (textureId == 41) + return icons[RIGHT]; + else + return icons[LEFT]; + + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/BlockBeehives.java b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockBeehives.java new file mode 100755 index 000000000..97c4fce26 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockBeehives.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.minecraft.block.BlockContainer; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.apiculture.BeeManager; +import forestry.api.apiculture.IHiveDrop; +import forestry.api.core.Tabs; +import forestry.apiculture.MaterialBeehive; +import forestry.core.config.Config; +import forestry.core.render.TextureManager; +import forestry.core.utils.StackUtils; + +public class BlockBeehives extends BlockContainer { + + public BlockBeehives() { + super(new MaterialBeehive(true)); + setLightLevel(0.8f); + setHardness(1.0f); + setCreativeTab(Tabs.tabApiculture); + } + + @Override + public TileEntity createNewTileEntity(World world, int meta) { + return new TileSwarm(); + } + + @Override + public boolean canEntityDestroy(IBlockAccess world, int x, int y, int z, Entity entity) { + return false; + } + + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + if (canHarvestBlock(player, world.getBlockMetadata(x, y, z))) { + // Handle TE'd beehives + TileEntity tile = world.getTileEntity(x, y, z); + + if (tile instanceof TileSwarm) { + TileSwarm swarm = (TileSwarm) tile; + if (swarm.containsBees()) + for (ItemStack beeStack : swarm.contained.getStacks()) + if (beeStack != null) + StackUtils.dropItemStackAsEntity(beeStack, world, x, y, z); + } + } + + return world.setBlockToAir(x, y, z); + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + ArrayList ret = new ArrayList(); + + // Handle legacy block + if (metadata == 0) { + ret.add(new ItemStack(this)); + return ret; + } + + ArrayList dropList = BeeManager.hiveDrops[metadata - 1]; + + Collections.shuffle(dropList); + // Grab a princess + int tries = 0; + boolean hasPrincess = false; + while (tries <= 10 && !hasPrincess) { + tries++; + + for (IHiveDrop drop : dropList) + if (world.rand.nextInt(100) < drop.getChance(world, x, y, z)) { + ret.add(drop.getPrincess(world, x, y, z, fortune)); + hasPrincess = true; + break; + } + } + + // Grab drones + for (IHiveDrop drop : dropList) + if (world.rand.nextInt(100) < drop.getChance(world, x, y, z)) { + ret.addAll(drop.getDrones(world, x, y, z, fortune)); + break; + } + // Grab anything else on offer + for (IHiveDrop drop : dropList) + if (world.rand.nextInt(100) < drop.getChance(world, x, y, z)) { + ret.addAll(drop.getAdditional(world, x, y, z, fortune)); + break; + } + + return ret; + } + + // / CREATIVE INVENTORY + @Override + public int damageDropped(int meta) { + return meta; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + itemList.add(new ItemStack(this, 1, 1)); + itemList.add(new ItemStack(this, 1, 2)); + itemList.add(new ItemStack(this, 1, 3)); + itemList.add(new ItemStack(this, 1, 4)); + if (Config.isDebug) { + itemList.add(new ItemStack(this, 1 ,5)); + } + itemList.add(new ItemStack(this, 1, 6)); + itemList.add(new ItemStack(this, 1, 7)); + // Swarm hive not added + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister register) { + icons = new IIcon[18]; + for (int i = 1; i < 9; i++) { + icons[i * 2] = TextureManager.getInstance().registerTex(register, "beehives/beehive." + i + ".top"); + icons[(i * 2) + 1] = TextureManager.getInstance().registerTex(register, "beehives/beehive." + i + ".side"); + } + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(int i, int j) { + if (i == 0 || i == 1) { + if (j * 2 < icons.length && icons[j * 2] != null) + return icons[j * 2]; + else + return icons[2]; + } else if (j * 2 + 1 < icons.length && icons[j * 2 + 1] != null) + return icons[j * 2 + 1]; + else + return icons[3]; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/BlockCandle.java b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockCandle.java new file mode 100755 index 000000000..899eae65b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockCandle.java @@ -0,0 +1,416 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockTorch; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.oredict.OreDictionary; + +import forestry.api.core.Tabs; +import forestry.core.ForestryClient; +import forestry.core.config.Defaults; +import forestry.core.render.TextureManager; +import forestry.core.utils.StackUtils; + +public class BlockCandle extends BlockTorch { + + private final ArrayList lightingItems = new ArrayList(); + + @SideOnly(Side.CLIENT) + private IIcon litStump; + @SideOnly(Side.CLIENT) + private IIcon litTip; + @SideOnly(Side.CLIENT) + private IIcon unlitStump; + @SideOnly(Side.CLIENT) + private IIcon unlitTip; + + public BlockCandle() { + super(); + this.setHardness(0.0F); + this.setStepSound(soundTypeWood); + setCreativeTab(Tabs.tabApiculture); + + lightingItems.add(Items.flint_and_steel); + lightingItems.add(Items.flint); + lightingItems.add(Item.getItemFromBlock(Blocks.torch)); + } + + @Override + public boolean hasTileEntity(int metadata) { + return true; + } + + @Override + public TileEntity createTileEntity(World world, int metadata) { + return new TileCandle(); + } + + @Override + public int getRenderType() { + return ForestryClient.candleRenderId; + } + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + String fileBase = this.getUnlocalizedName().replace("tile.", ""); + this.blockIcon = TextureManager.getInstance().registerTex(register, "stump"); + this.litStump = TextureManager.getInstance().registerTex(register, fileBase + "StumpLit"); + this.litTip = TextureManager.getInstance().registerTex(register, fileBase + "TipLit"); + this.unlitStump = TextureManager.getInstance().registerTex(register, fileBase + "StumpUnlit"); + this.unlitTip = TextureManager.getInstance().registerTex(register, fileBase + "TipUnlit"); + } + + @Override + public int getLightValue(IBlockAccess world, int x, int y, int z) { + int meta = world.getBlockMetadata(x, y, z); + return (isLit(meta))? 14 : 0; + } + + /*@SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + IIcon i = this.unlitStump; + if (this.isLit(world.getBlockMetadata(x, y, z))) { + i = this.litStump; + } + return i; + }*/ + + @SideOnly(Side.CLIENT) + public IIcon getTextureFromPassAndMeta(int meta, int pass) { + IIcon i = this.unlitStump; + if (pass == 0) { + if (isLit(meta)) { + i = this.litTip; + } + else { + i = this.unlitTip; + } + } + else { + if (isLit(meta)) { + i = this.litStump; + } + else { + i = this.unlitStump; + } + } + return i; + } + + public int getColourFromItemStack(ItemStack stack) { + int colour = 0xffffff; + if (stack.hasTagCompound()) { + NBTTagCompound tag = stack.getTagCompound(); + colour = (tag.getByte("red") << 16) | (tag.getByte("green") << 8) | tag.getByte("blue"); + } + return colour; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + itemList.add(new ItemStack(this, 1, 0)); + } + + // Dye names correspond to colour values as below. + private static final String[] dyes = { "dyeWhite", "dyeOrange", "dyeMagenta", "dyeLightBlue", + "dyeYellow", "dyeLime", "dyePink", "dyeGray", + "dyeLightGray", "dyeCyan", "dyePurple", "dyeBlue", + "dyeBrown", "dyeGreen", "dyeRed", "dyeBlack" }; + + private static final int[][] colours = { { 255, 255, 255 } , { 219, 125, 62 } , { 255, 20, 255 } , { 107, 138, 201 } , + { 255, 255, 20 } , { 20, 255, 20 } , { 208, 132, 153 } , { 74, 74, 74 } , + { 154, 161, 161 } , { 20, 255, 255 } , { 126, 61, 181 } , { 20, 20, 255 } , + { 79, 50, 31 } , { 53, 70, 27 } , { 150, 52, 48 } , { 20, 20, 20 } }; + + public static final String colourTagName = "colour"; + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int facing, float facingX, float facingY, float facingZ) { + boolean flag = false; + int meta = world.getBlockMetadata(x, y, z); + boolean toggleLitState = true; + ItemStack held = player.getCurrentEquippedItem(); + + if (!isLit(meta)) { + if (held == null || !lightingItems.contains(held.getItem())) { + toggleLitState = false; + } + else if (StackUtils.equals(this, held) && isLit(held)) { + toggleLitState = true; + } + } + + if (held != null) { + // Ensure a TileEntity exists. May be able to remove this in future versions. + TileCandle te = (TileCandle)world.getTileEntity(x, y, z); + if (te == null) { + world.setTileEntity(x, y, z, this.createTileEntity(world, meta)); + } + + if (StackUtils.equals(this, held)) { + if (!isLit(held)) { + // Copy the colour of an unlit, coloured candle. + if (held.hasTagCompound() && held.getTagCompound().hasKey(colourTagName)) { + te.setColour(held.getTagCompound().getInteger(colourTagName)); + } + else { + // Reset to white if item has no + te.setColour(0xffffff); + } + } + else { + toggleLitState = true; + } + flag = true; + } + else { + // Check for dye-able ness. + boolean matched = false; + for (int i = 0; i < dyes.length; ++i) { + for (ItemStack stack : OreDictionary.getOres(dyes[i])) { + if (OreDictionary.itemMatches(stack, held, true)) { + if (isLit(meta)) { + te.setColour(colours[i][0], colours[i][1], colours[i][2]); + } + else { + te.addColour(colours[i][0], colours[i][1], colours[i][2]); + } + world.markBlockForUpdate(x, y, z); + matched = true; + toggleLitState = false; + flag = true; + break; + } + } + if (matched) { + break; + } + } + } + } + + if (toggleLitState) { + meta = this.toggleLitStatus(meta); + world.setBlockMetadataWithNotify(x, y, z, meta, Defaults.FLAG_BLOCK_SYNCH | Defaults.FLAG_BLOCK_UPDATE); + flag = true; + } + return flag; + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + if (!world.isRemote) { + TileCandle tc = (TileCandle)world.getTileEntity(x, y, z); + int newMeta = isLit(meta) ? 1 : 0; + ItemStack stack = new ItemStack(this, 1, newMeta); + if (tc != null && tc.getColour() != 0xffffff) { + // When dropped, tag new item stack with colour. Unless it's white, then do no such thing for maximum stacking. + NBTTagCompound tag = new NBTTagCompound(); + tag.setInteger(colourTagName, tc.getColour()); + stack.setTagCompound(tag); + } + this.dropBlockAsItem(world, x, y, z, stack); + } + super.breakBlock(world, x, y, z, block, meta); + } + + @Override + public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase player, ItemStack itemStack) { + TileCandle tc = (TileCandle)(world.getTileEntity(x, y, z)); + tc.setColour(this.getColourValueFromItemStack(itemStack)); + if (isLit(itemStack)) { + int meta = world.getBlockMetadata(x, y, z); + world.setBlockMetadataWithNotify(x, y, z, this.toggleLitStatus(meta), Defaults.FLAG_BLOCK_SYNCH | Defaults.FLAG_BLOCK_UPDATE); + } + } + + @Override + public void dropBlockAsItemWithChance(World par1World, int par2, int par3, int par4, int par5, float par6, int par7) { + // Does nothing to prevent extra candles from falling. + } + + @Override + public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) { + // Does nothing to prevent extra candles from falling. + } + + @Override + protected boolean func_150109_e(World world, int x, int y, int z) { + // Slightly tweaked version of BlockTorch's version to account for TE nonsense. + if (!this.canPlaceBlockAt(world, x, y, z)) { + if (world.getBlock(x, y, z) == this) { + world.setBlockToAir(x, y, z); + } + return false; + } + else { + return true; + } + } + + @Override + @SideOnly(Side.CLIENT) + public void randomDisplayTick(World world, int x, int y, int z, Random random) { + if (isLit(world.getBlockMetadata(x, y, z))) { + int l = world.getBlockMetadata(x, y, z) & 0x07; + double d0 = x + 0.5F; + double d1 = y + 0.7F; + double d2 = z + 0.5F; + double d3 = 0.2199999988079071D; + double d4 = 0.27000001072883606D; + + if (l == 1) + { + world.spawnParticle("smoke", d0 - d4, d1 + d3, d2, 0.0D, 0.0D, 0.0D); + world.spawnParticle("flame", d0 - d4, d1 + d3, d2, 0.0D, 0.0D, 0.0D); + } + else if (l == 2) + { + world.spawnParticle("smoke", d0 + d4, d1 + d3, d2, 0.0D, 0.0D, 0.0D); + world.spawnParticle("flame", d0 + d4, d1 + d3, d2, 0.0D, 0.0D, 0.0D); + } + else if (l == 3) + { + world.spawnParticle("smoke", d0, d1 + d3, d2 - d4, 0.0D, 0.0D, 0.0D); + world.spawnParticle("flame", d0, d1 + d3, d2 - d4, 0.0D, 0.0D, 0.0D); + } + else if (l == 4) + { + world.spawnParticle("smoke", d0, d1 + d3, d2 + d4, 0.0D, 0.0D, 0.0D); + world.spawnParticle("flame", d0, d1 + d3, d2 + d4, 0.0D, 0.0D, 0.0D); + } + else + { + world.spawnParticle("smoke", d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.spawnParticle("flame", d0, d1, d2, 0.0D, 0.0D, 0.0D); + } + } + } + + @Override + protected boolean func_150108_b(World par1World, int par2, int par3, int par4, Block block) + { + if (this.func_150109_e(par1World, par2, par3, par4)) + { + int i1 = par1World.getBlockMetadata(par2, par3, par4) & 0x07; + boolean flag = false; + + if (!par1World.isSideSolid(par2 - 1, par3, par4, ForgeDirection.EAST, true) && i1 == 1) + { + flag = true; + } + + if (!par1World.isSideSolid(par2 + 1, par3, par4, ForgeDirection.WEST, true) && i1 == 2) + { + flag = true; + } + + if (!par1World.isSideSolid(par2, par3, par4 - 1, ForgeDirection.SOUTH, true) && i1 == 3) + { + flag = true; + } + + if (!par1World.isSideSolid(par2, par3, par4 + 1, ForgeDirection.NORTH, true) && i1 == 4) + { + flag = true; + } + + if (!this.canPlaceTorchOn(par1World, par2, par3 - 1, par4) && i1 == 5) + { + flag = true; + } + + if (flag) + { + this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0); + par1World.setBlockToAir(par2, par3, par4); + return true; + } + else + { + return false; + } + } + else + { + return true; + } + } + + // Yes, function hiding. Go away. + public boolean canPlaceTorchOn(World par1World, int par2, int par3, int par4) + { + if (World.doesBlockHaveSolidTopSurface(par1World, par2, par3, par4)) + { + return true; + } + else + { + Block block = par1World.getBlock(par2, par3, par4); + return block.canPlaceTorchOnTop(par1World, par2, par3, par4); + } + } + + protected int getColourValueFromItemStack(ItemStack itemStack) { + int value = 0xffffff; // default to white. + if (itemStack.hasTagCompound()) { + NBTTagCompound tag = itemStack.getTagCompound(); + if (tag.hasKey(colourTagName)) { + value = tag.getInteger(colourTagName); + } + } + return value; + } + + public static boolean isLit(int meta) { + return (meta & 0x08) > 0; + } + + public static boolean isLit(ItemStack itemStack) { + return itemStack.getItemDamage() > 0; + } + + protected int toggleLitStatus(int meta) { + return meta ^ 0x08; + } + + public void addItemToLightingList(Item item) { + if (item == null) throw new NullPointerException(); + + if (!this.lightingItems.contains(item)) { + this.lightingItems.add(item); + } + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/BlockStump.java b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockStump.java new file mode 100755 index 000000000..298c9c9a9 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/BlockStump.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.List; +import java.util.Random; + +import net.minecraft.block.BlockTorch; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.Tabs; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.render.TextureManager; +import forestry.core.utils.StackUtils; + +public class BlockStump extends BlockTorch { + + public BlockStump() { + super(); + this.setHardness(0.0F); + this.setStepSound(soundTypeWood); + setCreativeTab(Tabs.tabApiculture); + } + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + this.blockIcon = TextureManager.getInstance().registerTex(register, this.getUnlocalizedName().replace("tile.", "")); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + itemList.add(new ItemStack(this, 1, 0)); + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int facing, float facingX, float facingY, float facingZ) { + + ItemStack held = player.getCurrentEquippedItem(); + if (held != null && + (held.getItem() == Items.flint_and_steel || + held.getItem() == Items.flint || + StackUtils.equals(Blocks.torch, held))) { + world.setBlock(x, y, z, ForestryBlock.candle, world.getBlockMetadata(x, y, z) | 0x08, Defaults.FLAG_BLOCK_SYNCH); + TileCandle tc = new TileCandle(); + tc.setColour(0); // default to white + world.setTileEntity(x, y, z, tc); + return true; + } + + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public int getRenderColor(int par1) { + return 0xee0000; + } + + @Override + public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random) { + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/StructureLogicAlveary.java b/forestry_common/apiculture/forestry/apiculture/gadgets/StructureLogicAlveary.java new file mode 100755 index 000000000..53b7e2b90 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/StructureLogicAlveary.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.HashSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.TileEntity; + +import forestry.api.apiculture.IAlvearyComponent; +import forestry.api.core.ITileStructure; +import forestry.core.config.ForestryBlock; +import forestry.core.gadgets.BlockStructure.EnumStructureState; +import forestry.core.gadgets.StructureLogic; +import forestry.core.utils.Schemata; +import forestry.core.utils.Schemata.EnumStructureBlock; +import forestry.core.utils.Vect; + +public class StructureLogicAlveary extends StructureLogic { + + /* CONSTANTS */ + public static final String UID_ALVEARY = "alveary"; + public static final Schemata SCHEMATA_ALVEARY = new Schemata("alveary3x3", 5, 6, 5, "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FAAAF", + "FAAAF", "FABAF", "FCCCF", "FFFFF", "FFFFF", "FAAAF", "FAAAF", "FBMBF", "FCCCF", "FFFFF", "FFFFF", "FAAAF", "FAAAF", "FABAF", "FCCCF", "FFFFF", + "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF").setOffsets(-2, -3, -2); + + public static HashSet slabBlocks = new HashSet(); + static { + slabBlocks.add(Blocks.stone_slab); + slabBlocks.add(Blocks.wooden_slab); + slabBlocks.add(ForestryBlock.slabs1); + slabBlocks.add(ForestryBlock.slabs2); + slabBlocks.add(ForestryBlock.slabs3); + if (ForestryBlock.slabs4 != null) + slabBlocks.add(ForestryBlock.slabs4); + } + + public StructureLogicAlveary(ITileStructure structure) { + super(UID_ALVEARY, structure); + schematas = new Schemata[] { SCHEMATA_ALVEARY }; + metaOnValid.put(EnumStructureBlock.BLOCK_B, 1); + } + + @Override + protected EnumStructureState determineMasterState(Schemata schemata, boolean rotate) { + + Vect dimensions = schemata.getDimensions(rotate); + int offsetX = schemata.getxOffset(); + int offsetZ = schemata.getzOffset(); + if (rotate) { + offsetX = schemata.getzOffset(); + offsetZ = schemata.getxOffset(); + } + + for (int i = 0; i < dimensions.x; i++) + for (int j = 0; j < schemata.getHeight(); j++) + for (int k = 0; k < dimensions.z; k++) { + int x = structureTile.xCoord + i + offsetX; + int y = structureTile.yCoord + j + schemata.getyOffset(); + int z = structureTile.zCoord + k + offsetZ; + + if (!structureTile.getWorldObj().blockExists(x, y, z)) + return EnumStructureState.INDETERMINATE; + + EnumStructureBlock required = schemata.getAt(i, j, k, rotate); + if (required == EnumStructureBlock.ANY) + continue; + + TileEntity tile = structureTile.getWorldObj().getTileEntity(x, y, z); + Block block = structureTile.getWorldObj().getBlock(x, y, z); + + switch (required) { + case AIR: + if (!block.isAir(structureTile.getWorldObj(), x, y, z)) + return EnumStructureState.INVALID; + break; + case BLOCK_A: + if (tile == null || !(tile instanceof IAlvearyComponent)) + return EnumStructureState.INVALID; + if (!((ITileStructure) tile).getTypeUID().equals(UID_ALVEARY)) + return EnumStructureState.INVALID; + break; + case MASTER: + case BLOCK_B: + if (tile == null || !(tile instanceof TileAlvearyPlain)) + return EnumStructureState.INVALID; + break; + case BLOCK_C: + if (!slabBlocks.contains(block)) + return EnumStructureState.INVALID; + if ((structureTile.getWorldObj().getBlockMetadata(x, y, z) & 8) != 0) + return EnumStructureState.INVALID; + break; + case BLOCK_D: + if (block != Blocks.spruce_stairs) + return EnumStructureState.INVALID; + break; + case FOREIGN: + if (tile instanceof ITileStructure) + return EnumStructureState.INVALID; + break; + default: + return EnumStructureState.INDETERMINATE; + } + } + + return EnumStructureState.VALID; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlveary.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlveary.java new file mode 100755 index 000000000..360cf557a --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlveary.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.LinkedList; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; + +import buildcraft.api.gates.ITrigger; + +import forestry.api.apiculture.IAlvearyComponent; +import forestry.api.apiculture.IBeeListener; +import forestry.api.apiculture.IBeeModifier; +import forestry.api.core.IStructureLogic; +import forestry.api.core.ITileStructure; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.gadgets.TileForestry; +import forestry.core.network.PacketPayload; +import forestry.core.proxy.Proxies; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.TileInventoryAdapter; +import forestry.core.utils.Utils; + +public abstract class TileAlveary extends TileForestry implements IAlvearyComponent { + + protected TileInventoryAdapter inventory; + protected final int componentBlockMeta; + + public TileAlveary(int componentBlockMeta) { + this.structureLogic = new StructureLogicAlveary(this); + this.componentBlockMeta = componentBlockMeta; + } + + /* UPDATING */ + @Override + public void initialize() { + Block block = worldObj.getBlock(xCoord, yCoord, zCoord); + if (block != ForestryBlock.alveary) { + Proxies.log.info("Updating alveary block at %s/%s/%s.", xCoord, yCoord, zCoord); + worldObj.setBlock(xCoord, yCoord, zCoord, ForestryBlock.alveary, componentBlockMeta, Defaults.FLAG_BLOCK_SYNCH); + validate(); + worldObj.setTileEntity(xCoord, yCoord, zCoord, this); + } + } + + @Override + public void updateEntity() { + if (!Proxies.common.isSimulating(worldObj)) + updateClientSide(); + else { + if (!isInited) { + initialize(); + isInited = true; + } + + // Periodic validation if needed + if (worldObj.getTotalWorldTime() % 200 == 0 && (!isIntegratedIntoStructure() || isMaster())) + validateStructure(); + + updateServerSide(); + } + } + + protected void updateServerSide() { + } + + protected void updateClientSide() { + } + + /* TEXTURES */ + public int getIcon(int side, int metadata) { + return BlockAlveary.PLAIN; + } + + /* LOADING & SAVING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + this.isMaster = nbttagcompound.getBoolean("IsMaster"); + this.masterX = nbttagcompound.getInteger("MasterX"); + this.masterY = nbttagcompound.getInteger("MasterY"); + this.masterZ = nbttagcompound.getInteger("MasterZ"); + + // Init for master state + if (isMaster) + makeMaster(); + + structureLogic.readFromNBT(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setBoolean("IsMaster", isMaster); + nbttagcompound.setInteger("MasterX", masterX); + nbttagcompound.setInteger("MasterY", masterY); + nbttagcompound.setInteger("MasterZ", masterZ); + + structureLogic.writeToNBT(nbttagcompound); + } + + protected void createInventory() {} + + @Override + public void fromPacketPayload(PacketPayload payload) { + } + + @Override + public PacketPayload getPacketPayload() { + return null; + } + + /* ITILESTRUCTURE */ + IStructureLogic structureLogic; + + private boolean isMaster; + protected int masterX, masterZ; + protected int masterY = -99; + + @Override + public String getTypeUID() { + return structureLogic.getTypeUID(); + } + + @Override + public void validateStructure() { + structureLogic.validateStructure(); + } + + @Override + public void makeMaster() { + setCentralTE(null); + isMaster = true; + + if (inventory == null) + createInventory(); + } + + @Override + public void onStructureReset() { + setCentralTE(null); + if (worldObj.getBlockMetadata(xCoord, yCoord, zCoord) == 1) + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, 0, 0); + isMaster = false; + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + @Override + public ITileStructure getCentralTE() { + + if (!isIntegratedIntoStructure()) + return null; + + if (!isMaster()) { + TileEntity tile = worldObj.getTileEntity(masterX, masterY, masterZ); + if (tile instanceof ITileStructure) { + ITileStructure master = (ITileStructure) worldObj.getTileEntity(masterX, masterY, masterZ); + if (master.isMaster()) + return master; + else + return null; + } else + return null; + } else + return this; + + } + + private boolean isSameTile(TileEntity tile) { + return tile.xCoord == xCoord && tile.yCoord == yCoord && tile.zCoord == zCoord; + } + + @Override + public void setCentralTE(TileEntity tile) { + if (tile == null || tile == this || isSameTile(tile)) { + this.masterX = this.masterZ = 0; + this.masterY = -99; + return; + } + + this.isMaster = false; + this.masterX = tile.xCoord; + this.masterY = tile.yCoord; + this.masterZ = tile.zCoord; + } + + @Override + public boolean isMaster() { + return isMaster; + } + + protected boolean hasMaster() { + return masterY >= 0; + } + + @Override + public boolean isIntegratedIntoStructure() { + return isMaster || masterY >= 0; + } + + @Override + public IInventory getInventory() { + return inventory; + } + + /* IALVEARY COMPONENT */ + @Override + public boolean hasFunction() { + return false; + } + + @Override + public void addTemperatureChange(float change, float boundaryDown, float boundaryUp) { + } + + @Override + public void addHumidityChange(float change, float boundaryDown, float boundaryUp) { + } + + @Override + public void registerBeeModifier(IBeeModifier modifier) { + } + + @Override + public void removeBeeModifier(IBeeModifier modifier) { + } + + @Override + public void registerBeeListener(IBeeListener event) { + } + + @Override + public void removeBeeListener(IBeeListener event) { + } + + // / ITRIGGERPROVIDER + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.missingQueen); + res.add(ForestryTrigger.missingDrone); + return res; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return Utils.isUseableByPlayer(player, this, worldObj, xCoord, yCoord, zCoord); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyClimatiser.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyClimatiser.java new file mode 100755 index 000000000..84bd6d4e1 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyClimatiser.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.power.IPowerReceptor; +import buildcraft.api.power.PowerHandler; +import buildcraft.api.power.PowerHandler.PowerReceiver; +import buildcraft.api.power.PowerHandler.Type; + +import forestry.api.apiculture.IAlvearyComponent; +import forestry.core.network.PacketPayload; + +public abstract class TileAlvearyClimatiser extends TileAlveary implements IPowerReceptor { + + public static class ClimateControl { + + final float changePerTransfer; + final float boundaryUp; + final float boundaryDown; + + public ClimateControl(float changePerTransfer, float boundaryDown, float boundaryUp) { + this.changePerTransfer = changePerTransfer; + this.boundaryDown = boundaryDown; + this.boundaryUp = boundaryUp; + } + } + PowerHandler powerProvider; + ClimateControl climateControl; + private int transferTime = 0; + private int animationDelay = 0; + private final int textureOff; + private final int textureOn; + + public TileAlvearyClimatiser(ClimateControl control, int textureOff, int textureOn, int componentBlockMeta) { + super(componentBlockMeta); + this.climateControl = control; + powerProvider = new PowerHandler(this, Type.MACHINE); + powerProvider.configure(10, 100, 25, 200); + this.textureOff = textureOff; + this.textureOn = textureOn; + } + + @Override + public void openGui(EntityPlayer player) { + } + + /* UPDATING */ + @Override + protected void updateServerSide() { + super.updateServerSide(); + + // BC Power + if (powerProvider != null) { + powerProvider.update(); + } + + if (!this.hasMaster()) + return; + + if (transferTime > 0) { + transferTime--; + IAlvearyComponent component = (IAlvearyComponent) this.getCentralTE(); + if (component != null) + component.addTemperatureChange(climateControl.changePerTransfer, climateControl.boundaryDown, climateControl.boundaryUp); + } + + if (animationDelay > 0) { + animationDelay--; + if (animationDelay <= 0) + sendNetworkUpdate(); + } + } + + @Override + public boolean hasFunction() { + return true; + } + + /* TEXTURES */ + @Override + public int getIcon(int side, int metadata) { + if (animationDelay > 0) + return textureOn; + else + return textureOff; + } + + /* IPOWERRECEPTOR */ + @Override + public void doWork(PowerHandler workProvider) { + if (!this.hasMaster()) + return; + + if (powerProvider.useEnergy(powerProvider.getActivationEnergy(), powerProvider.getEnergyStored(), false) < powerProvider.getActivationEnergy()) + return; + + transferTime = (int) Math.round(powerProvider.useEnergy(powerProvider.getActivationEnergy(), powerProvider.getEnergyStored(), true)); + + if (animationDelay <= 0) { + animationDelay = 100; + sendNetworkUpdate(); + } else + animationDelay = 100; + } + + @Override + public PowerReceiver getPowerReceiver(ForgeDirection side) { + return powerProvider.getPowerReceiver(); + } + + /* LOADING & SAVING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + powerProvider.readFromNBT(nbttagcompound); + transferTime = nbttagcompound.getInteger("Heating"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + powerProvider.writeToNBT(nbttagcompound); + nbttagcompound.setInteger("Heating", transferTime); + } + + @Override + public String getInventoryName() { + return "tile.alveary.climatiser"; + } + + /* NETWORK */ + @Override + public void fromPacketPayload(PacketPayload payload) { + short delay = payload.shortPayload[0]; + if (animationDelay != delay) { + animationDelay = delay; + worldObj.func_147479_m(xCoord, yCoord, zCoord); + } + } + + @Override + public PacketPayload getPacketPayload() { + PacketPayload payload = new PacketPayload(0, 1); + payload.shortPayload[0] = (short) animationDelay; + return payload; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyFan.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyFan.java new file mode 100755 index 000000000..795279aab --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyFan.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +public class TileAlvearyFan extends TileAlvearyClimatiser { + + /* CONSTANTS */ + public static final int BLOCK_META = 3; + + public TileAlvearyFan() { + super(new ClimateControl(-0.01f, 0.05f, 2.5f), BlockAlveary.TX_71_FNOF, BlockAlveary.TX_72_FNON, BLOCK_META); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHeater.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHeater.java new file mode 100755 index 000000000..8d7c9898e --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHeater.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +public class TileAlvearyHeater extends TileAlvearyClimatiser { + + public static final int TEXTURE_OFF = 57; + public static final int TEXTURE_ON = 58; + + /* CONSTANTS */ + public static final int BLOCK_META = 4; + + public TileAlvearyHeater() { + super(new ClimateControl(0.01f, 0.0f, 2.5f), BlockAlveary.TX_57_HTOF, BlockAlveary.TX_58_HTON, BLOCK_META); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java new file mode 100755 index 000000000..320ccefd4 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java @@ -0,0 +1,294 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import forestry.api.apiculture.IAlvearyComponent; +import forestry.api.core.ForestryAPI; +import forestry.core.config.Defaults; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; + +public class TileAlvearyHygroregulator extends TileAlveary implements IInventory, ILiquidTankContainer { + + /* CONSTANTS */ + public static final int BLOCK_META = 5; + + /* RECIPE MANAGMENT */ + private static class HygroregulatorRecipe { + public final FluidStack liquid; + public final int transferTime; + public final float humidChange; + public final float tempChange; + + public HygroregulatorRecipe(FluidStack liquid, int transferTime, float humidChange, float tempChange) { + this.liquid = liquid; + this.transferTime = transferTime; + this.humidChange = humidChange; + this.tempChange = tempChange; + } + } + + private final HygroregulatorRecipe[] recipes; + + /* MEMBERS */ + InventoryAdapter canInventory = new InventoryAdapter(1, "CanInv"); + private ForestryTank liquidTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + + private HygroregulatorRecipe currentRecipe; + private int transferTime; + + public TileAlvearyHygroregulator() { + super(BLOCK_META); + + recipes = new HygroregulatorRecipe[] { new HygroregulatorRecipe(new FluidStack(LiquidHelper.getFluid(Defaults.LIQUID_WATER), 1), 1, 0.01f, -0.005f), + new HygroregulatorRecipe(new FluidStack(LiquidHelper.getFluid(Defaults.LIQUID_LAVA), 1), 10, -0.01f, +0.005f), + new HygroregulatorRecipe(new FluidStack(LiquidHelper.getFluid(Defaults.LIQUID_ICE), 1), 10, 0.02f, -0.01f) }; + } + + @Override + public void openGui(EntityPlayer player) { + player.openGui(ForestryAPI.instance, GuiId.HygroregulatorGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + } + + @Override + public String getInventoryName() { + return "tile.alveary.5"; + } + + /* UPDATING */ + private HygroregulatorRecipe getRecipe(FluidStack liquid) { + HygroregulatorRecipe recipe = null; + for (HygroregulatorRecipe rec : recipes) + if (rec.liquid.isFluidEqual(liquid)) { + recipe = rec; + break; + } + return recipe; + } + + @Override + protected void updateServerSide() { + super.updateServerSide(); + + if (transferTime <= 0 && liquidTank.getFluidAmount() > 0) { + currentRecipe = getRecipe(liquidTank.getFluid()); + + if (currentRecipe != null) { + liquidTank.drain(currentRecipe.liquid.amount, true); + transferTime = currentRecipe.transferTime; + } + } + + if (transferTime > 0) { + + transferTime--; + if (currentRecipe != null) { + IAlvearyComponent component = (IAlvearyComponent) this.getCentralTE(); + if (component != null) { + component.addHumidityChange(currentRecipe.humidChange, 0.0f, 1.0f); + component.addTemperatureChange(currentRecipe.tempChange, 0.0f, 2.0f); + } + } else + transferTime = 0; + } + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + // Check if we have suitable items waiting in the item slot + if (canInventory.getStackInSlot(0) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(canInventory.getStackInSlot(0)); + if (container != null && + (container.fluid.getFluid() == FluidRegistry.WATER || container.fluid.getFluid() == FluidRegistry.LAVA)) { + + canInventory.setInventorySlotContents(0, StackUtils.replenishByContainer(this, canInventory.getStackInSlot(0), container, liquidTank)); + if (canInventory.getStackInSlot(0).stackSize <= 0) + canInventory.setInventorySlotContents(0, null); + } + } + + } + + @Override + public boolean hasFunction() { + return true; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + canInventory.readFromNBT(nbttagcompound); + + liquidTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("LiquidTank")) + liquidTank.readFromNBT(nbttagcompound.getCompoundTag("LiquidTank")); + + transferTime = nbttagcompound.getInteger("TransferTime"); + + if (nbttagcompound.hasKey("CurrentLiquid")) { + FluidStack liquid = FluidStack.loadFluidStackFromNBT(nbttagcompound.getCompoundTag("CurrentLiquid")); + currentRecipe = getRecipe(liquid); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + canInventory.writeToNBT(nbttagcompound); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + liquidTank.writeToNBT(NBTresourceSlot); + nbttagcompound.setTag("LiquidTank", NBTresourceSlot); + + nbttagcompound.setInteger("TransferTime", transferTime); + if (currentRecipe != null) { + NBTTagCompound subcompound = new NBTTagCompound(); + currentRecipe.liquid.writeToNBT(subcompound); + nbttagcompound.setTag("CurrentLiquid", subcompound); + } + + } + + /* TEXTURES */ + @Override + public int getIcon(int side, int metadata) { + return BlockAlveary.TX_73_VLVE; + } + + @Override + public IInventory getInventory() { + return canInventory; + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + if (canInventory != null) + return canInventory.getSizeInventory(); + else + return 0; + } + + @Override + public ItemStack getStackInSlot(int slotIndex) { + if (canInventory != null) + return canInventory.getStackInSlot(slotIndex); + else + return null; + } + + @Override + public ItemStack decrStackSize(int slotIndex, int amount) { + if (canInventory != null) + return canInventory.decrStackSize(slotIndex, amount); + else + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int slotIndex) { + if (canInventory != null) + return canInventory.getStackInSlotOnClosing(slotIndex); + else + return null; + } + + @Override + public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { + // Client side handling for container synch + if (canInventory == null && !Proxies.common.isSimulating(worldObj)) + createInventory(); + + if (canInventory != null) + canInventory.setInventorySlotContents(slotIndex, itemstack); + } + + @Override + public int getInventoryStackLimit() { + if (canInventory != null) + return canInventory.getInventoryStackLimit(); + else + return 0; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /* ILIQUIDTANKCONTAINER */ + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + return liquidTank.fill(resource, doFill); + } + + @Override + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + return liquidTank.drain(maxDrain, doDrain); + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { liquidTank }; + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyPlain.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyPlain.java new file mode 100755 index 000000000..7fcb7063c --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyPlain.java @@ -0,0 +1,839 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.LinkedHashSet; +import java.util.Set; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeeListener; +import forestry.api.apiculture.IBeeModifier; +import forestry.api.apiculture.IBeekeepingLogic; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.ForestryAPI; +import forestry.api.core.ITileStructure; +import forestry.api.genetics.IIndividual; +import forestry.apiculture.gui.ContainerAlveary; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IClimatised; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.IHintSource; +import forestry.core.network.GuiId; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketInventoryStack; +import forestry.core.proxy.Proxies; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.TileInventoryAdapter; +import forestry.plugins.PluginApiculture; + +public class TileAlvearyPlain extends TileAlveary implements ISidedInventory, ISpecialInventory, IBeeHousing, IClimatised, IHintSource { + + // / CONSTANTS + public static final int SLOT_QUEEN = 0; + public static final int SLOT_DRONE = 1; + public static final int SLOT_PRODUCT_1 = 2; + public static final int SLOT_PRODUCTION_COUNT = 7; + // / MEMBERS + protected IBeekeepingLogic beekeepingLogic; + protected int biomeId; + protected float temperature; + protected float humidity; + protected float tempChange = 0.0f; + protected float humidChange = 0.0f; + private int displayHealthMax = 0; + private int displayHealth = 0; + + public TileAlvearyPlain() { + super(0); + } + + @Override + public void openGui(EntityPlayer player) { + if (isMaster()) + player.openGui(ForestryAPI.instance, GuiId.AlvearyGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + else if (this.hasMaster()) + player.openGui(ForestryAPI.instance, GuiId.AlvearyGUI.ordinal(), worldObj, masterX, masterY, masterZ); + } + + /* LOADING & SAVING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + this.tempChange = nbttagcompound.getFloat("TempChange"); + this.humidChange = nbttagcompound.getFloat("HumidChange"); + + if (inventory != null) + inventory.readFromNBT(nbttagcompound); + if (beekeepingLogic != null) + beekeepingLogic.readFromNBT(nbttagcompound); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setFloat("TempChange", tempChange); + nbttagcompound.setFloat("HumidChange", humidChange); + + if (inventory != null) + inventory.writeToNBT(nbttagcompound); + if (beekeepingLogic != null) + beekeepingLogic.writeToNBT(nbttagcompound); + + } + + /* UPDATING */ + @Override + public void initialize() { + super.initialize(); + BiomeGenBase biome = worldObj.getBiomeGenForCoordsBody(xCoord, zCoord); + this.biomeId = biome.biomeID; + this.temperature = biome.temperature; + this.humidity = biome.rainfall; + setErrorState(EnumErrorCode.OK); + } + + @Override + protected void updateServerSide() { + + if (beekeepingLogic == null) + return; + if (!isMaster()) + return; + + beekeepingLogic.update(); + + // Equalize humidity and temperature + equalizeTemperature(); + equalizeHumidity(); + + IBee queen = beekeepingLogic.getQueen(); + if (queen == null) + return; + + // Add swarm effects + if (worldObj.getTotalWorldTime() % 200 * 10 == 0) + onQueenChange(inventory.getStackInSlot(SLOT_QUEEN)); + if (getErrorState() == EnumErrorCode.OK) + queen.doFX(beekeepingLogic.getEffectData(), this); + + if (getErrorState() == EnumErrorCode.OK && worldObj.getTotalWorldTime() % 50 == 0) { + float f = xCoord + 0.5F; + float f1 = yCoord + 0.0F + (worldObj.rand.nextFloat() * 6F) / 16F; + float f2 = zCoord + 0.5F; + float f3 = 0.52F; + float f4 = worldObj.rand.nextFloat() * 0.6F - 0.3F; + + Proxies.common.addEntitySwarmFX(worldObj, (f - f3), f1, (f2 + f4), 0F, 0F, 0F); + Proxies.common.addEntitySwarmFX(worldObj, (f + f3), f1, (f2 + f4), 0F, 0F, 0F); + Proxies.common.addEntitySwarmFX(worldObj, (f + f4), f1, (f2 - f3), 0F, 0F, 0F); + Proxies.common.addEntitySwarmFX(worldObj, (f + f4), f1, (f2 + f3), 0F, 0F, 0F); + } + + } + + @Override + protected void updateClientSide() { + + if (!isMaster()) + return; + + if (inventory == null) + return; + + // / Multiplayer FX + if (PluginApiculture.beeInterface.isMated(inventory.getStackInSlot(SLOT_QUEEN))) + if (getErrorState() == EnumErrorCode.OK && worldObj.getTotalWorldTime() % 2 == 0) { + IBee displayQueen = PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(SLOT_QUEEN)); + displayQueen.doFX(beekeepingLogic.getEffectData(), this); + } + return; + + } + + private void equalizeTemperature() { + if (tempChange == 0) + return; + + tempChange -= 0.05f * tempChange; + if (tempChange <= 0.001f && tempChange >= -0.001f) + tempChange = 0; + } + + private void equalizeHumidity() { + if (humidChange == 0) + return; + + humidChange -= 0.05f * humidChange; + if (humidChange <= 0.001f && humidChange >= 0.001f) + humidChange = 0; + } + + /* STATE INFORMATION */ + private int getHealthDisplay() { + if (inventory == null || inventory.getStackInSlot(SLOT_QUEEN) == null) + return 0; + + if (PluginApiculture.beeInterface.isMated(inventory.getStackInSlot(SLOT_QUEEN))) + return PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(SLOT_QUEEN)).getHealth(); + else if (!PluginApiculture.beeInterface.isDrone(inventory.getStackInSlot(SLOT_QUEEN))) + return displayHealth; + else + return 0; + } + + private int getMaxHealthDisplay() { + if (inventory == null || inventory.getStackInSlot(SLOT_QUEEN) == null) + return 0; + + if (PluginApiculture.beeInterface.isMated(inventory.getStackInSlot(SLOT_QUEEN))) + return PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(SLOT_QUEEN)).getMaxHealth(); + else if (!PluginApiculture.beeInterface.isDrone(inventory.getStackInSlot(SLOT_QUEEN))) + return displayHealthMax; + else + return 0; + } + + public int getHealthScaled(int i) { + if (getMaxHealthDisplay() == 0) + return 0; + + return (getHealthDisplay() * i) / getMaxHealthDisplay(); + } + + @Override + public boolean allowsInteraction(EntityPlayer player) { + if (!super.allowsInteraction(player)) + return false; + + return this.isIntegratedIntoStructure(); + } + + /* STRUCTURE MANAGMENT */ + @Override + protected void createInventory() { + this.inventory = new TileInventoryAdapter(this, 9, "Items"); + } + + @Override + public void makeMaster() { + super.makeMaster(); + if (beekeepingLogic == null) + this.beekeepingLogic = PluginApiculture.beeInterface.createBeekeepingLogic(this); + } + + @Override + public void onStructureReset() { + super.onStructureReset(); + modifiers.clear(); + eventHandlers.clear(); + } + + /* IALVEARYCOMPONENT */ + private final Set modifiers = new LinkedHashSet(); + private final Set eventHandlers = new LinkedHashSet(); + + @Override + public void registerBeeModifier(IBeeModifier modifier) { + modifiers.add(modifier); + } + + @Override + public void removeBeeModifier(IBeeModifier modifier) { + modifiers.remove(modifier); + } + + @Override + public void registerBeeListener(IBeeListener modifier) { + eventHandlers.add(modifier); + } + + @Override + public void removeBeeListener(IBeeListener modifier) { + eventHandlers.remove(modifier); + } + + @Override + public void addTemperatureChange(float change, float boundaryDown, float boundaryUp) { + tempChange = Math.min(boundaryUp - temperature, Math.max(boundaryDown - temperature, tempChange + change)); + } + + @Override + public void addHumidityChange(float change, float boundaryDown, float boundaryUp) { + humidChange = Math.min(boundaryUp - humidity, Math.max(boundaryDown - humidity, humidChange + change)); + } + + /* IBEEHOUSING */ + @Override + public int getXCoord() { + return xCoord; + } + + @Override + public int getYCoord() { + return yCoord; + } + + @Override + public int getZCoord() { + return zCoord; + } + + @Override + public ItemStack getQueen() { + return getStackInSlot(SLOT_QUEEN); + } + + @Override + public ItemStack getDrone() { + return getStackInSlot(SLOT_DRONE); + } + + @Override + public void setQueen(ItemStack itemstack) { + setInventorySlotContents(SLOT_QUEEN, itemstack); + } + + @Override + public void setDrone(ItemStack itemstack) { + setInventorySlotContents(SLOT_DRONE, itemstack); + } + + @Override + public int getBiomeId() { + return this.biomeId; + } + + @Override + public EnumTemperature getTemperature() { + if (EnumTemperature.isBiomeHellish(biomeId) && tempChange >= 0) + return EnumTemperature.HELLISH; + + return EnumTemperature.getFromValue(getExactTemperature()); + } + + @Override + public EnumHumidity getHumidity() { + return EnumHumidity.getFromValue(getExactHumidity()); + } + + @Override + public float getTerritoryModifier(IBeeGenome genome, float currentModifier) { + float mod = 2.0f; + for (IBeeModifier modifier : modifiers) { + mod *= modifier.getTerritoryModifier(genome, mod); + } + return mod; + } + + @Override + public float getProductionModifier(IBeeGenome genome, float currentModifier) { + float mod = 1.0f; + for (IBeeModifier modifier : modifiers) { + mod *= modifier.getProductionModifier(genome, mod); + } + return mod; + } + + @Override + public float getMutationModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + float mod = 1.0f; + for (IBeeModifier modifier : modifiers) { + mod *= modifier.getMutationModifier(genome, mate, mod); + } + return mod; + } + + @Override + public float getLifespanModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + float mod = 1.0f; + for (IBeeModifier modifier : modifiers) { + mod *= modifier.getLifespanModifier(genome, mate, mod); + } + return mod; + } + + @Override + public float getFloweringModifier(IBeeGenome genome, float currentModifier) { + float mod = 1.0f; + for (IBeeModifier modifier : modifiers) { + mod *= modifier.getFloweringModifier(genome, mod); + } + return mod; + } + + @Override + public float getGeneticDecay(IBeeGenome genome, float currentModifier) { + float mod = 1.0f; + for (IBeeModifier modifier : modifiers) { + mod *= modifier.getGeneticDecay(genome, mod); + } + return mod; + } + + @Override + public World getWorld() { + return worldObj; + } + + @Override + public void setErrorState(int state) { + setErrorState(EnumErrorCode.values()[state]); + } + + @Override + public int getErrorOrdinal() { + return getErrorState().ordinal(); + } + + @Override + public boolean canBreed() { + return true; + } + + @Override + public boolean addProduct(ItemStack product, boolean all) { + if (inventory == null) + return false; + + return inventory.tryAddStack(product, SLOT_PRODUCT_1, inventory.getSizeInventory() - SLOT_PRODUCT_1, all); + } + + @Override + public void wearOutEquipment(int amount) { + for (IBeeListener eventHandler : eventHandlers) { + eventHandler.wearOutEquipment(amount); + } + } + + @Override + public void onQueenChange(ItemStack queenStack) { + if (!Proxies.common.isSimulating(worldObj)) + return; + + Proxies.net.sendNetworkPacket(new PacketInventoryStack(PacketIds.IINVENTORY_STACK, xCoord, yCoord, zCoord, SLOT_QUEEN, queenStack), xCoord, yCoord, + zCoord); + + for (IBeeListener eventHandler : eventHandlers) { + eventHandler.onQueenChange(queenStack); + } + } + + @Override + public void onQueenDeath(IBee queen) { + for (IBeeListener eventHandler : eventHandlers) { + eventHandler.onQueenDeath(queen); + } + } + + @Override + public void onPostQueenDeath(IBee queen) { + for (IBeeListener eventHandler : eventHandlers) { + eventHandler.onPostQueenDeath(queen); + } + } + + @Override + public boolean onPollenRetrieved(IBee queen, IIndividual pollen, boolean isHandled) { + + for (IBeeListener eventHandler : eventHandlers) { + if (eventHandler.onPollenRetrieved(queen, pollen, isHandled)) + isHandled = true; + } + + return isHandled; + } + + @Override + public boolean onEggLaid(IBee queen) { + for (IBeeListener eventHandler : eventHandlers) { + if (eventHandler.onEggLaid(queen)) + return true; + } + + return false; + } + + @Override + public boolean isSealed() { + for (IBeeModifier modifier : modifiers) { + if (modifier.isSealed()) + return true; + } + return false; + } + + @Override + public boolean isSelfLighted() { + for (IBeeModifier modifier : modifiers) { + if (modifier.isSelfLighted()) + return true; + } + return false; + } + + @Override + public boolean isSunlightSimulated() { + for (IBeeModifier modifier : modifiers) { + if (modifier.isSunlightSimulated()) + return true; + } + return false; + } + + @Override + public boolean isHellish() { + for (IBeeModifier modifier : modifiers) { + if (modifier.isHellish()) + return true; + } + return false; + } + + /* IINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return (InventoryAdapter) getStructureInventory(); + } + + private IInventory getStructureInventory() { + + if (inventory != null) { + if (isMaster() || !Proxies.common.isSimulating(worldObj)) + return inventory; + } else if (hasMaster()) { + ITileStructure central = getCentralTE(); + if (central != null) + return central.getInventory(); + } + + return null; + } + + @Override + public int getSizeInventory() { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getSizeInventory(); + else + return 0; + } + + @Override + public ItemStack getStackInSlot(int slotIndex) { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getStackInSlot(slotIndex); + else + return null; + } + + @Override + public ItemStack decrStackSize(int slotIndex, int amount) { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.decrStackSize(slotIndex, amount); + else + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int slotIndex) { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getStackInSlotOnClosing(slotIndex); + else + return null; + } + + @Override + public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { + // Client side handling for container synch + if (inventory == null && !Proxies.common.isSimulating(worldObj)) + createInventory(); + + IInventory inv = getStructureInventory(); + if (inv != null) + inv.setInventorySlotContents(slotIndex, itemstack); + } + + @Override + public String getInventoryName() { + return "alveary.0"; + } + + @Override + public int getInventoryStackLimit() { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getInventoryStackLimit(); + else + return 0; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if (!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex != SLOT_QUEEN && slotIndex != SLOT_DRONE) + return true; + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if (!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex == SLOT_QUEEN && PluginApiculture.beeInterface.isMember(itemstack) + && !PluginApiculture.beeInterface.isDrone(itemstack)) + return true; + if (slotIndex == SLOT_DRONE && PluginApiculture.beeInterface.isDrone(itemstack)) + return true; + + return false; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + + IInventory inv = getStructureInventory(); + if (inv == null) + return 0; + + // Princesses && Queens + if (ForestryItem.beePrincessGE.isItemEqual(stack) || ForestryItem.beeQueenGE.isItemEqual(stack)) + if (inv.getStackInSlot(SLOT_QUEEN) == null) { + if (doAdd) { + inv.setInventorySlotContents(SLOT_QUEEN, stack.copy()); + inv.getStackInSlot(SLOT_QUEEN).stackSize = 1; + } + return 1; + } + + // Drones + if (ForestryItem.beeDroneGE.isItemEqual(stack)) { + + ItemStack droneStack = inv.getStackInSlot(SLOT_DRONE); + if (droneStack == null) { + if (doAdd) + inv.setInventorySlotContents(SLOT_DRONE, stack.copy()); + return stack.stackSize; + } else { + if (!droneStack.isItemEqual(stack)) + return 0; + if (!ItemStack.areItemStackTagsEqual(droneStack, stack)) + return 0; + int space = droneStack.getMaxStackSize() - droneStack.stackSize; + if (space <= 0) + return 0; + + int added = space > stack.stackSize ? stack.stackSize : space; + if (doAdd) + droneStack.stackSize += added; + return added; + } + } + + return 0; + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + + IInventory inv = getStructureInventory(); + if (inv == null) + return new ItemStack[0]; + + ItemStack product = null; + + for (int i = SLOT_PRODUCT_1; i < inv.getSizeInventory(); i++) { + if (inv.getStackInSlot(i) == null) + continue; + + ItemStack stack = inv.getStackInSlot(i); + + if (doRemove) + product = inv.decrStackSize(i, 1); + else { + product = stack.copy(); + product.stackSize = 1; + } + break; + } + + return new ItemStack[] { product }; + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + switch (i) { + case 0: + displayHealth = j; + break; + case 1: + displayHealthMax = j; + break; + case 2: + this.temperature = (float) j / 100; + break; + case 3: + this.humidity = (float) j / 100; + break; + case 4: + this.tempChange = (float) j / 100; + break; + case 5: + this.humidChange = (float) j / 100; + break; + case 6: + this.biomeId = j; + break; + } + + } + + public void sendGUINetworkData(ContainerAlveary container, ICrafting iCrafting) { + if (beekeepingLogic == null) + return; + + iCrafting.sendProgressBarUpdate(container, 0, beekeepingLogic.getBreedingTime()); + iCrafting.sendProgressBarUpdate(container, 1, beekeepingLogic.getTotalBreedingTime()); + iCrafting.sendProgressBarUpdate(container, 2, Math.round(temperature * 100)); + iCrafting.sendProgressBarUpdate(container, 3, Math.round(humidity * 100)); + iCrafting.sendProgressBarUpdate(container, 4, Math.round(tempChange * 100)); + iCrafting.sendProgressBarUpdate(container, 5, Math.round(humidChange * 100)); + iCrafting.sendProgressBarUpdate(container, 6, biomeId); + } + + /* IERRORSOURCE */ + @Override + public EnumErrorCode getErrorState() { + if (hasMaster()) { + ITileStructure tile = this.getCentralTE(); + if (tile != null) + return ((IErrorSource) tile).getErrorState(); + } + + return errorState; + } + + /* ICLIMATISED */ + @Override + public boolean isClimatized() { + return true; + } + + @Override + public float getExactTemperature() { + return this.temperature + this.tempChange; + } + + @Override + public float getExactHumidity() { + return this.humidity + this.humidChange; + } + + /* IHINTSOURCE */ + @Override + public boolean hasHints() { + return Config.hints.get("alveary").length > 0; + } + + @Override + public String[] getHints() { + return Config.hints.get("alveary"); + } + + /* IOWNABLE */ + @Override + public boolean isOwnable() { + return true; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySieve.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySieve.java new file mode 100755 index 000000000..8c3c378f2 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySieve.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.apiculture.IAlvearyComponent; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeListener; +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import forestry.core.interfaces.ICrafter; +import forestry.core.network.GuiId; +import forestry.core.utils.InventoryAdapter; + +public class TileAlvearySieve extends TileAlveary implements ICrafter, IBeeListener { + + /* CONSTANTS */ + public static final int BLOCK_META = 7; + + public static final int SLOT_POLLEN_1 = 0; + public static final int SLOTS_POLLEN_COUNT = 4; + public static final int SLOT_SIEVE = 4; + + InventoryAdapter inventory = new InventoryAdapter(5, "Items", 1); + + public TileAlvearySieve() { + super(BLOCK_META); + } + + @Override + public void openGui(EntityPlayer player) { + player.openGui(ForestryAPI.instance, GuiId.AlvearySieveGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + } + + @Override + public String getInventoryName() { + return "tile.alveary.7"; + } + + @Override + public boolean hasFunction() { + return true; + } + + /* UPDATING */ + @Override + public void initialize() { + super.initialize(); + + if(!hasMaster() || !isIntegratedIntoStructure()) + return; + + ((IAlvearyComponent)getCentralTE()).registerBeeListener(this); + } + + + @Override + protected void updateServerSide() { + super.updateServerSide(); + if(worldObj.getTotalWorldTime() % 200 != 0) + return; + + if(!hasMaster() || !isIntegratedIntoStructure()) + return; + + ((IAlvearyComponent)getCentralTE()).registerBeeListener(this); + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + inventory.readFromNBT(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + inventory.writeToNBT(nbttagcompound); + } + + /* TEXTURES & INTERNAL */ + @Override + public int getIcon(int side, int metadata) { + if(side == 0 || side == 1) + return BlockAlveary.BOTTOM; + return BlockAlveary.SIEVE; + } + + private void destroySieve() { + inventory.setInventorySlotContents(SLOT_SIEVE, null); + } + private void destroyPollen() { + for(int i = SLOT_POLLEN_1; i < SLOT_POLLEN_1 + SLOTS_POLLEN_COUNT; i++) { + inventory.setInventorySlotContents(i, null); + } + } + + private boolean canStorePollen() { + if(inventory.getStackInSlot(SLOT_SIEVE) == null) + return false; + + for(int i = SLOT_POLLEN_1; i < SLOT_POLLEN_1 + SLOTS_POLLEN_COUNT; i++) { + if(inventory.getStackInSlot(i) == null) + return true; + } + + return false; + } + + private void storePollenStack(ItemStack itemstack) { + for(int i = SLOT_POLLEN_1; i < SLOT_POLLEN_1 + SLOTS_POLLEN_COUNT; i++) { + if(inventory.getStackInSlot(i) == null) { + inventory.setInventorySlotContents(i, itemstack); + return; + } + } + } + + /* INVENTORY */ + public InventoryAdapter getInternalInventory() { + return inventory; + } + + /* ICRAFTER */ + @Override + public boolean canTakeStack(int slotIndex) { + return true; + } + + @Override + public ItemStack takenFromSlot(int slotIndex, boolean consumeRecipe, EntityPlayer player) { + if(slotIndex == SLOT_SIEVE) { + destroyPollen(); + return inventory.getStackInSlot(SLOT_SIEVE); + } else { + destroySieve(); + return inventory.getStackInSlot(slotIndex); + } + } + + @Override + public ItemStack getResult() { + return null; + } + + /* IBEELISTENER */ + @Override public void onQueenChange(ItemStack queen) {} + @Override public void wearOutEquipment(int amount) {} + @Override public void onQueenDeath(IBee queen) {} + @Override public void onPostQueenDeath(IBee queen) {} + + @Override + public boolean onPollenRetrieved(IBee queen, IIndividual pollen, boolean isHandled) { + + if(isHandled) + return isHandled; + if(!canStorePollen()) + return false; + + storePollenStack(AlleleManager.alleleRegistry.getSpeciesRoot(pollen.getClass()).getMemberStack(pollen, EnumGermlingType.POLLEN.ordinal())); + return true; + } + + @Override + public boolean onEggLaid(IBee queen) { + return false; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyStabiliser.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyStabiliser.java new file mode 100755 index 000000000..300b9d79a --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearyStabiliser.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import forestry.api.apiculture.IAlvearyComponent; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeModifier; + +public class TileAlvearyStabiliser extends TileAlveary implements IBeeModifier { + + public static final int BLOCK_META = 6; + + public TileAlvearyStabiliser() { + super(BLOCK_META); + } + + /* UPDATING */ + @Override + public void initialize() { + super.initialize(); + + if(!hasMaster() || !isIntegratedIntoStructure()) + return; + + ((IAlvearyComponent)getCentralTE()).registerBeeModifier(this); + + } + + @Override + protected void updateServerSide() { + super.updateServerSide(); + if(worldObj.getTotalWorldTime() % 200 != 0) + return; + + if(!hasMaster() || !isIntegratedIntoStructure()) + return; + + ((IAlvearyComponent)getCentralTE()).registerBeeModifier(this); + } + + @Override + public String getInventoryName() { + return "tile.alveary.6"; + } + + @Override + public boolean hasFunction() { + return true; + } + + /* TEXTURES */ + public int getIcon(int side, int metadata) { + if(side == 0 || side == 1) + return BlockAlveary.BOTTOM; + + return BlockAlveary.STABILISER; + } + + /* IBEEMODIFIER */ + @Override + public float getMutationModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return 0.0f; + } + + @Override + public float getTerritoryModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getLifespanModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return 1.0f; + } + + @Override + public float getProductionModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getFloweringModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getGeneticDecay(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public boolean isSealed() { + return false; + } + + @Override + public boolean isSelfLighted() { + return false; + } + + @Override + public boolean isSunlightSimulated() { + return false; + } + + @Override + public boolean isHellish() { + return false; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySwarmer.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySwarmer.java new file mode 100755 index 000000000..de7de05db --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileAlvearySwarmer.java @@ -0,0 +1,305 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.Map.Entry; +import java.util.Stack; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.apiculture.BeeManager; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IAlvearyComponent; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.core.ForestryAPI; +import forestry.apiculture.worldgen.WorldGenHive; +import forestry.apiculture.worldgen.WorldGenHiveSwamer; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.TileInventoryAdapter; +import forestry.plugins.PluginApiculture; + +public class TileAlvearySwarmer extends TileAlveary implements ISpecialInventory { + + /* CONSTANTS */ + public static final int BLOCK_META = 2; + + TileInventoryAdapter swarmerInventory; + private final Stack pendingSpawns = new Stack(); + + public TileAlvearySwarmer() { + super(BLOCK_META); + } + + @Override + public void initialize() { + super.initialize(); + if (swarmerInventory == null) + createInventory(); + } + + @Override + public void openGui(EntityPlayer player) { + player.openGui(ForestryAPI.instance, GuiId.AlvearySwarmerGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + } + + /* UPDATING */ + @Override + protected void updateServerSide() { + super.updateServerSide(); + + if (worldObj.getTotalWorldTime() % 100 != 0) + if (pendingSpawns.size() > 0) + trySpawnSwarm(); + + if (worldObj.getTotalWorldTime() % 500 != 0) + return; + + if (!this.hasMaster()) + return; + + IAlvearyComponent master = (IAlvearyComponent) this.getCentralTE(); + if (!(master instanceof IBeeHousing)) + return; + + IBeeHousing housing = (IBeeHousing) master; + ItemStack queenstack = housing.getQueen(); + if (queenstack == null) + return; + if (!PluginApiculture.beeInterface.isMated(queenstack)) + return; + + // Calculate chance + int slot = getInducerSlot(); + if (slot < 0) + return; + int chance = getChanceFor(swarmerInventory.getStackInSlot(slot)); + + // Remove resource + swarmerInventory.decrStackSize(slot, 1); + + // Try to spawn princess + if (worldObj.rand.nextInt(1000) >= chance) + return; + + // Queue swarm spawn + IBee spawn = PluginApiculture.beeInterface.getMember(queenstack); + spawn.setIsNatural(false); + pendingSpawns.push(PluginApiculture.beeInterface.getMemberStack(spawn, EnumBeeType.PRINCESS.ordinal())); + + } + + private int getChanceFor(ItemStack stack) { + for (Entry entry : BeeManager.inducers.entrySet()) { + if (entry.getKey().isItemEqual(stack)) + return entry.getValue(); + } + + return 0; + } + + private int getInducerSlot() { + for (int i = 0; i < swarmerInventory.getSizeInventory(); i++) { + if (swarmerInventory.getStackInSlot(i) == null) + continue; + for (Entry entry : BeeManager.inducers.entrySet()) { + if (entry.getKey().isItemEqual(swarmerInventory.getStackInSlot(i))) + return i; + } + } + + return -1; + } + + private void trySpawnSwarm() { + + ItemStack toSpawn = pendingSpawns.peek(); + WorldGenHive generator = new WorldGenHiveSwamer(new ItemStack[] { toSpawn }); + + int i = 0; + while (i < 10) { + i++; + int spawnX = xCoord + worldObj.rand.nextInt(40 * 2) - 40; + int spawnY = yCoord + worldObj.rand.nextInt(40); + int spawnZ = zCoord + worldObj.rand.nextInt(40 * 2) - 40; + if (generator.generate(worldObj, worldObj.rand, spawnX, spawnY, spawnZ)) { + pendingSpawns.pop(); + break; + } + } + + } + + @Override + public boolean hasFunction() { + return true; + } + + /* TEXTURES */ + @Override + public int getIcon(int side, int metadata) { + if(side == 0 || side == 1) + return BlockAlveary.BOTTOM; + + if (pendingSpawns.size() > 0) + return BlockAlveary.TX_56_SWON; + else + return BlockAlveary.TX_55_SWOF; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + if (swarmerInventory == null) + createInventory(); + swarmerInventory.readFromNBT(nbttagcompound); + + NBTTagList nbttaglist = nbttagcompound.getTagList("PendingSpawns", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + pendingSpawns.add(ItemStack.loadItemStackFromNBT(nbttagcompound1)); + } + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + if (swarmerInventory != null) + swarmerInventory.writeToNBT(nbttagcompound); + + NBTTagList nbttaglist = new NBTTagList(); + ItemStack[] offspring = pendingSpawns.toArray(new ItemStack[pendingSpawns.size()]); + for (int i = 0; i < offspring.length; i++) + if (offspring[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + offspring[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("PendingSpawns", nbttaglist); + + } + + @Override + protected void createInventory() { + swarmerInventory = new TileInventoryAdapter(this, 4, "SwarmInv"); + } + + @Override + public IInventory getInventory() { + return swarmerInventory; + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + if (swarmerInventory != null) + return swarmerInventory.addStack(stack, false, doAdd); + else + return 0; + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + return null; + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + if (swarmerInventory != null) + return swarmerInventory.getSizeInventory(); + else + return 0; + } + + @Override + public ItemStack getStackInSlot(int slotIndex) { + if (swarmerInventory != null) + return swarmerInventory.getStackInSlot(slotIndex); + else + return null; + } + + @Override + public ItemStack decrStackSize(int slotIndex, int amount) { + if (swarmerInventory != null) + return swarmerInventory.decrStackSize(slotIndex, amount); + else + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int slotIndex) { + if (swarmerInventory != null) + return swarmerInventory.getStackInSlotOnClosing(slotIndex); + else + return null; + } + + @Override + public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { + // Client side handling for container synch + if (swarmerInventory == null && !Proxies.common.isSimulating(worldObj)) + createInventory(); + + if (swarmerInventory != null) + swarmerInventory.setInventorySlotContents(slotIndex, itemstack); + } + + @Override + public String getInventoryName() { + return "tile.alveary.2"; + } + + @Override + public int getInventoryStackLimit() { + if (swarmerInventory != null) + return swarmerInventory.getInventoryStackLimit(); + else + return 0; + } + + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileApiaristChest.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileApiaristChest.java new file mode 100755 index 000000000..10cb5fdbd --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileApiaristChest.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import forestry.api.genetics.AlleleManager; +import forestry.apiculture.genetics.BeeHelper; +import forestry.core.gadgets.TileNaturalistChest; +import forestry.core.network.GuiId; + +public class TileApiaristChest extends TileNaturalistChest { + + public TileApiaristChest() { + super(AlleleManager.alleleRegistry.getSpeciesRoot(BeeHelper.UID), GuiId.ApiaristChestGUI.ordinal()); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileApiary.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileApiary.java new file mode 100755 index 000000000..fa2192abb --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileApiary.java @@ -0,0 +1,352 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import java.util.LinkedList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; + +import buildcraft.api.gates.ITrigger; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IHiveFrame; +import forestry.api.core.ForestryAPI; +import forestry.core.gadgets.TileBase; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.plugins.PluginApiculture; + +public class TileApiary extends TileBeehouse implements ISidedInventory { + + @Override + public String getInventoryName() { + return "apiculture.0"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.ApiaryGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + } + + /* IBEEHOUSING */ + @Override + public float getTerritoryModifier(IBeeGenome genome, float currentModifier) { + float mod = 1.0f; + for (int i = SLOT_FRAMES_1; i < SLOT_FRAMES_1 + SLOT_FRAMES_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).getItem() instanceof IHiveFrame) + mod *= ((IHiveFrame) inventory.getStackInSlot(i).getItem()).getTerritoryModifier(genome, mod); + } + return mod; + } + + @Override + public float getProductionModifier(IBeeGenome genome, float currentModifier) { + float mod = 0.1f; + for (int i = SLOT_FRAMES_1; i < SLOT_FRAMES_1 + SLOT_FRAMES_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).getItem() instanceof IHiveFrame) + mod *= ((IHiveFrame) inventory.getStackInSlot(i).getItem()).getProductionModifier(genome, mod); + } + return mod; + } + + @Override + public float getMutationModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + float mod = 1.0f; + for (int i = SLOT_FRAMES_1; i < SLOT_FRAMES_1 + SLOT_FRAMES_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).getItem() instanceof IHiveFrame) + mod *= ((IHiveFrame) inventory.getStackInSlot(i).getItem()).getMutationModifier(genome, mate, mod); + } + return mod; + } + + @Override + public float getLifespanModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + float mod = 1.0f; + for (int i = SLOT_FRAMES_1; i < SLOT_FRAMES_1 + SLOT_FRAMES_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).getItem() instanceof IHiveFrame) + mod *= ((IHiveFrame) inventory.getStackInSlot(i).getItem()).getLifespanModifier(genome, mate, mod); + } + return mod; + } + + @Override + public float getFloweringModifier(IBeeGenome genome, float currentModifier) { + float mod = 1f; + for (int i = SLOT_FRAMES_1; i < SLOT_FRAMES_1 + SLOT_FRAMES_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).getItem() instanceof IHiveFrame) + mod *= ((IHiveFrame) inventory.getStackInSlot(i).getItem()).getFloweringModifier(genome, mod); + } + return mod; + } + + @Override + public float getGeneticDecay(IBeeGenome genome, float currentModifier) { + float mod = 1f; + for (int i = SLOT_FRAMES_1; i < SLOT_FRAMES_1 + SLOT_FRAMES_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).getItem() instanceof IHiveFrame) + mod *= ((IHiveFrame) inventory.getStackInSlot(i).getItem()).getGeneticDecay(genome, mod); + } + return mod; + } + + @Override + public void wearOutEquipment(int amount) { + int wear = Math.round(amount * PluginApiculture.beeInterface.getBeekeepingMode(worldObj).getWearModifier()); + + for (int i = SLOT_FRAMES_1; i < SLOT_FRAMES_1 + SLOT_FRAMES_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (!(inventory.getStackInSlot(i).getItem() instanceof IHiveFrame)) + continue; + + inventory.setInventorySlotContents( + i, + ((IHiveFrame) inventory.getStackInSlot(i).getItem()).frameUsed(this, inventory.getStackInSlot(i), + PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(SLOT_QUEEN)), wear)); + } + } + + /* IINVENTORY */ + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if (!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + switch (slotIndex) { + case SLOT_QUEEN: + case SLOT_DRONE: + case SLOT_FRAMES_1: + case SLOT_FRAMES_2: + case SLOT_FRAMES_3: + return false; + default: + return true; + } + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if (!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex == SLOT_QUEEN && PluginApiculture.beeInterface.isMember(itemstack) + && !PluginApiculture.beeInterface.isDrone(itemstack)) + return true; + + if (slotIndex == SLOT_DRONE && PluginApiculture.beeInterface.isDrone(itemstack)) + return true; + + return false; + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public ItemStack getStackInSlot(int i) { + return super.getStackInSlot(i); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + super.setSlotContents(i, itemstack); + } + + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISPECIALINVENTORY */ + // @Override + // public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + // ItemStack product = null; + // + // for (int i = SLOT_PRODUCT_1; i < SLOT_PRODUCT_1 + SLOT_PRODUCT_COUNT; i++) { + // if (inventory.getStackInSlot(i) == null) + // continue; + // + // // Princesses can only be extracted from top. + // if (ForestryItem.beePrincessGE.isItemEqual(inventory.getStackInSlot(i))) { + // if (PluginApiculture.apiarySideSensitive && from != ForgeDirection.UP) + // continue; + // + // product = inventory.getStackInSlot(i).copy(); + // if (doRemove) { + // inventory.getStackInSlot(i).stackSize = 0; + // inventory.setInventorySlotContents(i, null); + // } + // break; + // + // // Drones can only be extracted from the bottom. + // } else if (ForestryItem.beeDroneGE.isItemEqual(inventory.getStackInSlot(i))) { + // if (PluginApiculture.apiarySideSensitive && from != ForgeDirection.DOWN) + // continue; + // + // product = StackUtils.createSplitStack(inventory.getStackInSlot(i), 1); + // product.stackSize = 1; + // if (doRemove) { + // inventory.getStackInSlot(i).stackSize--; + // if (inventory.getStackInSlot(i).stackSize <= 0) + // inventory.setInventorySlotContents(i, null); + // } + // break; + // + // // Everything else to be extracted from the sides + // } else { + // if (PluginApiculture.apiarySideSensitive && (from == ForgeDirection.UP || from == ForgeDirection.DOWN)) + // continue; + // + // product = StackUtils.createSplitStack(inventory.getStackInSlot(i), 1); + // if (doRemove) { + // inventory.getStackInSlot(i).stackSize--; + // if (inventory.getStackInSlot(i).stackSize <= 0) + // inventory.setInventorySlotContents(i, null); + // } + // break; + // } + // } + // + // return new ItemStack[] { product }; + // } + // + // @Override + // public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + // // Princesses && Queens + // if (ForestryItem.beePrincessGE.isItemEqual(stack) || ForestryItem.beeQueenGE.isItemEqual(stack)) + // if (inventory.getStackInSlot(SLOT_QUEEN) == null) { + // if (doAdd) { + // inventory.setInventorySlotContents(SLOT_QUEEN, stack.copy()); + // inventory.getStackInSlot(SLOT_QUEEN).stackSize = 1; + // } + // + // return 1; + // } + // + // // Drones + // if (ForestryItem.beeDroneGE.isItemEqual(stack)) { + // + // ItemStack droneStack = inventory.getStackInSlot(SLOT_DRONE); + // if (droneStack == null) { + // if (doAdd) + // inventory.setInventorySlotContents(SLOT_DRONE, stack.copy()); + // return stack.stackSize; + // } else { + // if (!droneStack.isItemEqual(stack)) + // return 0; + // if (!ItemStack.areItemStackTagsEqual(droneStack, stack)) + // return 0; + // int space = droneStack.getMaxStackSize() - droneStack.stackSize; + // if (space <= 0) + // return 0; + // + // int added = space > stack.stackSize ? stack.stackSize : space; + // if (doAdd) + // droneStack.stackSize += added; + // return added; + // } + // } + // + // return 0; + // } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.missingQueen); + res.add(ForestryTrigger.missingDrone); + res.add(PluginApiculture.triggerNoFrames); + return res; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileBeehouse.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileBeehouse.java new file mode 100755 index 000000000..031f338e5 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileBeehouse.java @@ -0,0 +1,438 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeekeepingLogic; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.IIndividual; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.TileBase; +import forestry.core.interfaces.IClimatised; +import forestry.core.network.GuiId; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketInventoryStack; +import forestry.core.network.PacketTileUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.Utils; +import forestry.plugins.PluginApiculture; + +public class TileBeehouse extends TileBase implements IBeeHousing, IClimatised { + + // CONSTANTS + public static final int SLOT_QUEEN = 0; + public static final int SLOT_DRONE = 1; + public static final int SLOT_INVENTORY_1 = 2; + protected static int SLOT_PRODUCT_1 = 2; + protected static int SLOT_PRODUCT_COUNT = 7; + public static final int SLOT_FRAMES_1 = 9; + public static final int SLOT_FRAMES_2 = 10; + public static final int SLOT_FRAMES_3 = 11; + public static final int SLOT_INVENTORY_COUNT = 7; + public static final int SLOT_FRAMES_COUNT = 3; + // Inventory + protected InventoryAdapter inventory = new InventoryAdapter(12, "Items"); + private final IBeekeepingLogic logic; + private int biomeId = -1; + private float temperature; + private float humidity; + private int displayHealthMax = 0; + private int displayHealth = 0; + + public TileBeehouse() { + setHints(Config.hints.get("apiary")); + logic = PluginApiculture.beeInterface.createBeekeepingLogic(this); + } + + @Override + public String getInventoryName() { + return "apiculture.2"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.BeehouseGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + } + + /* LOADING & SAVING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setFloat("Temp", temperature); + nbttagcompound.setFloat("Humidity", humidity); + nbttagcompound.setInteger("BiomeId", biomeId); + + inventory.writeToNBT(nbttagcompound); + if (logic != null) + logic.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + temperature = nbttagcompound.getFloat("Temp"); + humidity = nbttagcompound.getFloat("Humidity"); + biomeId = nbttagcompound.getInteger("BiomeId"); + + inventory.readFromNBT(nbttagcompound); + logic.readFromNBT(nbttagcompound); + + } + + @Override + public void initialize() { + super.initialize(); + updateBiome(); + } + + @Override + public void validate() { + updateBiome(); + } + + /* ICLIMATISED */ + @Override + public boolean isClimatized() { + return true; + } + + @Override + public EnumTemperature getTemperature() { + if (EnumTemperature.isBiomeHellish(biomeId)) + return EnumTemperature.HELLISH; + return EnumTemperature.getFromValue(temperature); + } + + @Override + public EnumHumidity getHumidity() { + return EnumHumidity.getFromValue(humidity); + } + + @Override + public float getExactTemperature() { + return this.temperature; + } + + @Override + public float getExactHumidity() { + return this.humidity; + } + + /* UPDATING */ + @Override + public void updateClientSide() { + + // / Multiplayer FX + if (PluginApiculture.beeInterface.isMated(inventory.getStackInSlot(SLOT_QUEEN))) + if (getErrorState() == EnumErrorCode.OK && worldObj.getTotalWorldTime() % 2 % 2 == 0) { + IBee displayQueen = PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(SLOT_QUEEN)); + displayQueen.doFX(logic.getEffectData(), this); + } + return; + + } + + @Override + public void updateServerSide() { + + logic.update(); + + IBee queen = logic.getQueen(); + if (queen == null) + return; + + // Add swarm effects + if (worldObj.getTotalWorldTime() % 200 * 10 == 0) + onQueenChange(inventory.getStackInSlot(SLOT_QUEEN)); + /* These should get already done on the client / doesn't work server-side anyway + if (getErrorState() == EnumErrorCode.OK && worldObj.getTotalWorldTime() % 2 % 2 == 0) + queen.doFX(logic.getEffectData(), this); + + if (getErrorState() == EnumErrorCode.OK && worldObj.getTotalWorldTime() % 50 == 0) { + float f = xCoord + 0.5F; + float f1 = yCoord + 0.0F + (worldObj.rand.nextFloat() * 6F) / 16F; + float f2 = zCoord + 0.5F; + float f3 = 0.52F; + float f4 = worldObj.rand.nextFloat() * 0.6F - 0.3F; + + Proxies.common.addEntitySwarmFX(worldObj, (f - f3), f1, (f2 + f4), 0F, 0F, 0F); + Proxies.common.addEntitySwarmFX(worldObj, (f + f3), f1, (f2 + f4), 0F, 0F, 0F); + Proxies.common.addEntitySwarmFX(worldObj, (f + f4), f1, (f2 - f3), 0F, 0F, 0F); + Proxies.common.addEntitySwarmFX(worldObj, (f + f4), f1, (f2 + f3), 0F, 0F, 0F); + }*/ + + } + + // @Override + public boolean isWorking() { + return getErrorState() == EnumErrorCode.OK; + } + + @Override + public boolean addProduct(ItemStack product, boolean all) { + return inventory.tryAddStack(product, SLOT_PRODUCT_1, SLOT_PRODUCT_COUNT, all, true); + } + + /* NETWORK SYNCH */ + @Override + public void onQueenChange(ItemStack queenStack) { + if (!Proxies.common.isSimulating(worldObj)) + return; + + Proxies.net.sendNetworkPacket(new PacketInventoryStack(PacketIds.IINVENTORY_STACK, xCoord, yCoord, zCoord, SLOT_QUEEN, queenStack), xCoord, yCoord, + zCoord); + Proxies.net.sendNetworkPacket(new PacketTileUpdate(this), xCoord, yCoord, zCoord); + } + + /* STATE INFORMATION */ + private int getHealthDisplay() { + if (inventory.getStackInSlot(SLOT_QUEEN) == null) + return 0; + + if (ForestryItem.beeQueenGE.isItemEqual(inventory.getStackInSlot(SLOT_QUEEN))) + return PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(SLOT_QUEEN)).getHealth(); + else if (ForestryItem.beePrincessGE.isItemEqual(inventory.getStackInSlot(SLOT_QUEEN))) + return displayHealth; + else + return 0; + } + + private int getMaxHealthDisplay() { + if (inventory.getStackInSlot(SLOT_QUEEN) == null) + return 0; + + if (ForestryItem.beeQueenGE.isItemEqual(inventory.getStackInSlot(SLOT_QUEEN))) + return PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(SLOT_QUEEN)).getMaxHealth(); + else if (ForestryItem.beePrincessGE.isItemEqual(inventory.getStackInSlot(SLOT_QUEEN))) + return displayHealthMax; + else + return 0; + } + + /** + * Returns scaled queen health or breeding progress + * + * @param i + * @return + */ + public int getHealthScaled(int i) { + if (getMaxHealthDisplay() == 0) + return 0; + + return (getHealthDisplay() * i) / getMaxHealthDisplay(); + } + + public int getTemperatureScaled(int i) { + return Math.round(i * (temperature / 2)); + } + + public int getHumidityScaled(int i) { + return Math.round(i * humidity); + } + + public void updateBiome() { + if (worldObj != null) { + BiomeGenBase biome = Utils.getBiomeAt(worldObj, xCoord, zCoord); + if (biome != null) { + this.biomeId = biome.biomeID; + this.temperature = biome.temperature; + this.humidity = biome.rainfall; + setErrorState(EnumErrorCode.OK); + } + } + } + + /* SMP */ + // @Override + public void getGUINetworkData(int i, int j) { + if (logic == null) + return; + + switch (i) { + case 0: + displayHealth = j; + break; + case 1: + displayHealthMax = j; + break; + } + } + + // @Override + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + if (logic == null) + return; + + iCrafting.sendProgressBarUpdate(container, 0, logic.getBreedingTime()); + iCrafting.sendProgressBarUpdate(container, 1, logic.getTotalBreedingTime()); + } + + /* INVENTORY MANAGMENT */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + public void setSlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + // / IBEEHOUSING + @Override + public int getXCoord() { + return xCoord; + } + + @Override + public int getYCoord() { + return yCoord; + } + + @Override + public int getZCoord() { + return zCoord; + } + + @Override + public int getBiomeId() { + return this.biomeId; + } + + @Override + public ItemStack getQueen() { + return getStackInSlot(SLOT_QUEEN); + } + + @Override + public ItemStack getDrone() { + return getStackInSlot(SLOT_DRONE); + } + + @Override + public void setQueen(ItemStack itemstack) { + setSlotContents(SLOT_QUEEN, itemstack); + } + + @Override + public void setDrone(ItemStack itemstack) { + setSlotContents(SLOT_DRONE, itemstack); + } + + @Override + public World getWorld() { + return worldObj; + } + + @Override + public void setErrorState(int state) { + setErrorState(EnumErrorCode.values()[state]); + } + + @Override + public int getErrorOrdinal() { + return getErrorState().ordinal(); + } + + @Override + public boolean canBreed() { + return true; + } + + @Override + public float getTerritoryModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getProductionModifier(IBeeGenome genome, float currentModifier) { + return 0.25f; + } + + @Override + public float getMutationModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return 0.0f; + } + + @Override + public float getLifespanModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return 3.0f; + } + + @Override + public float getFloweringModifier(IBeeGenome genome, float currentModifier) { + return 3.0f; + } + + @Override + public float getGeneticDecay(IBeeGenome genome, float currentModifier) { + return 0.0f; + } + + @Override + public void wearOutEquipment(int amount) { + } + + @Override + public boolean isSealed() { + return false; + } + + @Override + public boolean isSelfLighted() { + return false; + } + + @Override + public boolean isSunlightSimulated() { + return false; + } + + @Override + public boolean isHellish() { + return false; + } + + @Override + public void onQueenDeath(IBee queen) { + } + + @Override + public void onPostQueenDeath(IBee queen) { + } + + @Override + public boolean onPollenRetrieved(IBee queen, IIndividual pollen, boolean isHandled) { + return false; + } + + @Override + public boolean onEggLaid(IBee queen) { + return false; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileCandle.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileCandle.java new file mode 100755 index 000000000..8fb61efee --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileCandle.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; + +public class TileCandle extends TileEntity { + private int colour; + + // This is a non-ticking Tile Entity. + @Override + public boolean canUpdate() { + return false; + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + writeToNBT(nbt); + + return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, nbt); + } + + @Override + public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { + readFromNBT(pkt.func_148857_g()); + } + + @Override + public void readFromNBT(NBTTagCompound tagRoot) { + super.readFromNBT(tagRoot); + this.setColour(tagRoot.getInteger("colour")); + } + + @Override + public void writeToNBT(NBTTagCompound tagRoot) { + super.writeToNBT(tagRoot); + tagRoot.setInteger("colour", this.colour); + } + + public int getColour() { + return this.colour; + } + + public void setColour(int value) { + this.colour = value; + } + + public void setColour(int red, int green, int blue) { + this.colour = toIntColour(red, green, blue); + } + + /*public void setColour(int[] cs) { + this.colour = toIntColour(cs[0], cs[1], cs[2]); + }*/ + + public void addColour(int red, int green, int blue) { + int[] myColour = fromIntColour(this.colour); + this.colour = toIntColour((red + myColour[0]) / 2, (green + myColour[0]) / 2, (blue + myColour[2]) / 2); + } + + private static int[] fromIntColour(int value) { + int[] cs = new int[3]; + cs[0] = (value & 0xff0000) >> 16; + cs[1] = (value & 0x00ff00) >> 8; + cs[2] = value & 0x0000ff; + return cs; + } + + private static int toIntColour(int r, int g, int b) { + return r << 16 | g << 8 | b; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gadgets/TileSwarm.java b/forestry_common/apiculture/forestry/apiculture/gadgets/TileSwarm.java new file mode 100755 index 000000000..d494f420d --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gadgets/TileSwarm.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gadgets; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; + +import forestry.core.utils.InventoryAdapter; + +public class TileSwarm extends TileEntity { + + public InventoryAdapter contained = new InventoryAdapter(2, "Contained"); + + @Override + public boolean canUpdate() { + return false; + } + + public TileSwarm setContained(ItemStack[] bees) { + for (ItemStack itemstack : bees) + contained.addStack(itemstack, false, true); + + return this; + } + + public boolean containsBees() { + for (int i = 0; i < contained.getSizeInventory(); i++) + if (contained.getStackInSlot(i) != null) + return true; + + return false; + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + contained.readFromNBT(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + contained.writeToNBT(nbttagcompound); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AIAvoidPlayers.java b/forestry_common/apiculture/forestry/apiculture/genetics/AIAvoidPlayers.java new file mode 100755 index 000000000..d80e7820d --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AIAvoidPlayers.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.entity.ai.RandomPositionGenerator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.pathfinding.PathEntity; +import net.minecraft.pathfinding.PathNavigate; +import net.minecraft.util.Vec3; + +public class AIAvoidPlayers extends EntityAIBase { + + private EntityCreature mob; + + private float farSpeed; + private float nearSpeed; + private float minDistance; + + private PathEntity pathing; + + private PathNavigate pathNavigator; + + private EntityPlayer player; + + public AIAvoidPlayers(EntityCreature mob, float minDistance, float farSpeed, float nearSpeed) { + this.mob = mob; + this.minDistance = minDistance; + this.farSpeed = farSpeed; + this.nearSpeed = nearSpeed; + this.pathNavigator = mob.getNavigator(); + this.setMutexBits(1); + } + + @Override + public boolean shouldExecute() { + + player = mob.worldObj.getClosestPlayerToEntity(mob, minDistance); + + if (player == null) + return false; + + if (!mob.getEntitySenses().canSee(player)) + return false; + + Vec3 randomTarget = RandomPositionGenerator.findRandomTargetBlockAwayFrom(mob, 16, 7, + mob.worldObj.getWorldVec3Pool().getVecFromPool(player.posX, player.posY, player.posZ)); + + if (randomTarget == null) + return false; + + if (player.getDistanceSq(randomTarget.xCoord, randomTarget.yCoord, randomTarget.zCoord) < player.getDistanceSqToEntity(mob)) + return false; + + pathing = pathNavigator.getPathToXYZ(randomTarget.xCoord, randomTarget.yCoord, randomTarget.zCoord); + return pathing == null ? false : pathing.isDestinationSame(randomTarget); + } + + @Override + public boolean continueExecuting() { + return !this.pathNavigator.noPath(); + } + + @Override + public void startExecuting() { + this.pathNavigator.setPath(pathing, farSpeed); + } + + @Override + public void resetTask() { + player = null; + } + + @Override + public void updateTask() { + if (mob.getDistanceSqToEntity(player) < 49.0D) + mob.getNavigator().setSpeed(nearSpeed); + else + mob.getNavigator().setSpeed(farSpeed); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleBeeSpecies.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleBeeSpecies.java new file mode 100755 index 000000000..1eefe2a7c --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleBeeSpecies.java @@ -0,0 +1,233 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeeRoot; +import forestry.api.core.IIconProvider; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.core.config.Defaults; +import forestry.core.genetics.AlleleSpecies; +import forestry.core.render.TextureManager; +import forestry.core.utils.StackUtils; + +public class AlleleBeeSpecies extends AlleleSpecies implements IAlleleBeeSpecies, IIconProvider { + + public IJubilanceProvider jubilanceProvider; + + private IBeeRoot root; + + private HashMap products = new HashMap(); + private HashMap specialty = new HashMap(); + + private String texture; + private int primaryColour; + private int secondaryColour; + + private String iconType = "default"; + + public AlleleBeeSpecies(String uid, boolean dominant, String name, IClassification branch, int primaryColor, int secondaryColor) { + this(uid, dominant, name, branch, null, primaryColor, secondaryColor); + } + + public AlleleBeeSpecies(String uid, boolean dominant, String name, IClassification branch, String binomial, int primaryColor, int secondaryColor) { + this(uid, dominant, name, branch, binomial, primaryColor, secondaryColor, new JubilanceDefault()); + } + + public AlleleBeeSpecies(String uid, boolean dominant, String name, IClassification branch, String binomial, int primaryColor, int secondaryColor, + IJubilanceProvider jubilanceProvider) { + super(uid, dominant, name, branch, binomial); + + this.root = (IBeeRoot)AlleleManager.alleleRegistry.getSpeciesRoot("rootBees"); + this.primaryColour = primaryColor; + this.secondaryColour = secondaryColor; + this.jubilanceProvider = jubilanceProvider; + texture = Defaults.TEXTURE_PATH_ENTITIES + "/bees/honeyBee.png"; + } + + @Override + public IBeeRoot getRoot() { + return root; + } + + public AlleleBeeSpecies setEntityTexture(String texture) { + this.texture = Defaults.TEXTURE_PATH_ENTITIES + "/bees/" + texture + ".png"; + return this; + } + + public AlleleBeeSpecies addProduct(ItemStack product, int chance) { + this.products.put(product, chance); + return this; + } + + public AlleleBeeSpecies addSpecialty(ItemStack specialty, int chance) { + this.specialty.put(specialty, chance); + return this; + } + + public AlleleBeeSpecies setJubilanceProvider(IJubilanceProvider provider) { + this.jubilanceProvider = provider; + return this; + } + + /* RESEARCH */ + @Override + public int getComplexity() { + return 1 + getGeneticAdvancement(this, new ArrayList()); + } + + private int getGeneticAdvancement(IAllele species, ArrayList exclude) { + + int own = 1; + int highest = 0; + exclude.add(species); + + for(IMutation mutation : getRoot().getPaths(species, EnumBeeChromosome.SPECIES.ordinal())) { + if(!exclude.contains(mutation.getAllele0())) { + int otherAdvance = getGeneticAdvancement(mutation.getAllele0(), exclude); + if(otherAdvance > highest) + highest = otherAdvance; + } + if(!exclude.contains(mutation.getAllele1())) { + int otherAdvance = getGeneticAdvancement(mutation.getAllele1(), exclude); + if(otherAdvance > highest) + highest = otherAdvance; + } + } + + return own + (highest < 0 ? 0 : highest); + } + + @Override + public float getResearchSuitability(ItemStack itemstack) { + if(itemstack == null) + return 0f; + + for(ItemStack stack : products.keySet()) + if(stack.isItemEqual(itemstack)) + return 1.0f; + for(ItemStack stack : specialty.keySet()) + if(stack.isItemEqual(itemstack)) + return 1.0f; + + return super.getResearchSuitability(itemstack); + } + + @Override + public ItemStack[] getResearchBounty(World world, String researcher, IIndividual individual, int bountyLevel) { + ArrayList bounty = new ArrayList(); + for(ItemStack stack : super.getResearchBounty(world, researcher, individual, bountyLevel)) + bounty.add(stack); + + if(bountyLevel > 10) { + for(ItemStack stack : specialty.keySet()) { + bounty.add(StackUtils.copyWithRandomSize(stack, (int)((float)bountyLevel / 2), world.rand)); + } + } + for(ItemStack stack : products.keySet()) { + bounty.add(StackUtils.copyWithRandomSize(stack, (int)((float)bountyLevel / 2), world.rand)); + } + return bounty.toArray(StackUtils.EMPTY_STACK_ARRAY); + } + + /* OTHER */ + @Override + public boolean isNocturnal() { + return false; + } + + @Override + public HashMap getProducts() { + return products; + } + + @Override + public HashMap getSpecialty() { + return specialty; + } + + @Override + public boolean isJubilant(IBeeGenome genome, IBeeHousing housing) { + return jubilanceProvider.isJubilant(this, genome, housing); + } + + @Override + public String getEntityTexture() { + return texture; + } + + @Override + public int getIconColour(int renderPass) { + if (renderPass == 0) + return primaryColour; + if (renderPass == 1) + return secondaryColour; + return 0xffffff; + } + + @SideOnly(Side.CLIENT) + private static IIcon[][] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + icons = new IIcon[EnumBeeType.values().length][3]; + + IIcon body1 = TextureManager.getInstance().registerTex(register, "bees/" + iconType + "/body1"); + + for (int i = 0; i < EnumBeeType.values().length; i++) { + if(EnumBeeType.values()[i] == EnumBeeType.NONE) + continue; + + icons[i][0] = TextureManager.getInstance().registerTex(register, "bees/" + iconType + "/" + EnumBeeType.values()[i].toString().toLowerCase(Locale.ENGLISH) + ".outline");; + icons[i][1] = (EnumBeeType.values()[i] != EnumBeeType.LARVAE) ? body1 + : TextureManager.getInstance().registerTex(register, "bees/" + iconType + "/" + EnumBeeType.values()[i].toString().toLowerCase(Locale.ENGLISH) + ".body"); + icons[i][2] = TextureManager.getInstance().registerTex(register, "bees/" + iconType + "/" + EnumBeeType.values()[i].toString().toLowerCase(Locale.ENGLISH) + ".body2"); + } + + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(EnumBeeType type, int renderPass) { + return icons[type.ordinal()][renderPass]; + } + + @Override + @SideOnly(Side.CLIENT) + public IIconProvider getIconProvider() { + return this; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(short texUID) { + return null; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectAggressive.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectAggressive.java new file mode 100755 index 000000000..aff8f5ebb --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectAggressive.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.DamageSource; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.apiculture.items.ItemArmorApiarist; +import forestry.core.utils.DamageSourceForestry; + +public class AlleleEffectAggressive extends AlleleEffectThrottled { + + public static DamageSource damageSourceBeeAggressive = new DamageSourceForestry("bee.aggressive"); + + public AlleleEffectAggressive(String uid) { + super(uid, "aggressive", true, 40, false, false); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB hurtBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityLivingBase.class, hurtBox); + + for (Object obj : list) { + EntityLivingBase entity = (EntityLivingBase) obj; + + int damage = 4; + + // Players are not attacked if they wear a full set of apiarist's + // armor. + if (entity instanceof EntityPlayer) { + int count = ItemArmorApiarist.wearsItems((EntityPlayer) entity, getUID(), true); + // Full set, no damage/effect + if (count > 3) + continue; + else if (count > 2) + damage = 1; + else if (count > 1) + damage = 2; + else if (count > 0) + damage = 3; + } + + entity.attackEntityFrom(damageSourceBeeAggressive, damage); + } + + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectCreeper.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectCreeper.java new file mode 100755 index 000000000..1f9130270 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectCreeper.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.apiculture.items.ItemArmorApiarist; +import forestry.core.genetics.EffectData; + +public class AlleleEffectCreeper extends AlleleEffectThrottled { + + private final int explosionChance = 50; + byte defaultForce = 12; + byte indexExplosionTimer = 1; + byte indexExplosionForce = 2; + + public AlleleEffectCreeper(String uid) { + super(uid, "creeper", true, 20, false, true); + } + + @Override + public IEffectData validateStorage(IEffectData storedData) { + if (!(storedData instanceof EffectData)) + return new EffectData(3, 0); + + if (((EffectData) storedData).getIntSize() < 3) + return new EffectData(3, 0); + + return storedData; + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + World world = housing.getWorld(); + + if (isHalted(storedData, housing)) + return storedData; + + // If we are already triggered, we continue the explosion sequence. + if (storedData.getInteger(indexExplosionTimer) > 0) { + progressExplosion(storedData, world, housing.getXCoord(), housing.getYCoord(), housing.getZCoord()); + return storedData; + } + + AxisAlignedBB infectionBox = getBounding(genome, housing, 1.0f); + + @SuppressWarnings("rawtypes") + List list = world.getEntitiesWithinAABB(EntityPlayer.class, infectionBox); + + for (Object obj : list) { + + EntityPlayer player = (EntityPlayer) obj; + + int chance = explosionChance; + storedData.setInteger(indexExplosionForce, defaultForce); + + // Players are not attacked if they wear a full set of apiarist's + // armor. + int count = ItemArmorApiarist.wearsItems(player, getUID(), true); + // Full set, no damage/effect + if (count > 3) + continue; + else if (count > 2) { + chance = 5; + storedData.setInteger(indexExplosionForce, 6); + } else if (count > 1) { + chance = 20; + storedData.setInteger(indexExplosionForce, 8); + } else if (count > 0) { + chance = 35; + storedData.setInteger(indexExplosionForce, 10); + } + + if (world.rand.nextInt(1000) >= chance) + continue; + + world.playSoundEffect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord(), "mob.creeper", 4F, + (1.0F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.2F) * 0.7F); + storedData.setInteger(indexExplosionTimer, 2); // Set explosion + // timer + } + + return storedData; + } + + private void progressExplosion(IEffectData storedData, World world, int x, int y, int z) { + + int explosionTimer = storedData.getInteger(indexExplosionTimer); + explosionTimer--; + storedData.setInteger(indexExplosionTimer, explosionTimer); + + if (explosionTimer > 0) + return; + + world.createExplosion(null, x, y, z, storedData.getInteger(indexExplosionForce), false); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectExploration.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectExploration.java new file mode 100755 index 000000000..d629c26a0 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectExploration.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; + +public class AlleleEffectExploration extends AlleleEffectThrottled { + + public AlleleEffectExploration(String uid) { + super(uid, "exploration", false, 80, true, false); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB beatifyBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityPlayer.class, beatifyBox); + + for (Object obj : list) { + EntityPlayer player = (EntityPlayer) obj; + player.addExperience(2); + } + + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectGlacial.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectGlacial.java new file mode 100755 index 000000000..f4a35b8a2 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectGlacial.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.IEffectData; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Vect; + +public class AlleleEffectGlacial extends AlleleEffectThrottled { + + public AlleleEffectGlacial(String uid) { + super(uid, "glacial", false, 200, true, false); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + World world = housing.getWorld(); + + if (isHalted(storedData, housing)) + return storedData; + + EnumTemperature temp = EnumTemperature.getFromValue(BiomeGenBase.getBiome(housing.getBiomeId()).temperature); + + switch (temp) { + case HELLISH: + case HOT: + case WARM: + return storedData; + default: + } + + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + for (int i = 0; i < 10; i++) { + + Vect randomPos = new Vect(world.rand.nextInt(area.x), world.rand.nextInt(area.y), world.rand.nextInt(area.z)); + + Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord())); + posBlock = posBlock.add(offset); + + // Freeze water + Block block = world.getBlock(posBlock.x, posBlock.y, posBlock.z); + if (block != Blocks.water) + continue; + + if (!world.isAirBlock(posBlock.x, posBlock.y + 1, posBlock.z)) + continue; + + Proxies.common.setBlockWithNotify(world, posBlock.x, posBlock.y, posBlock.z, Blocks.ice); + } + + return storedData; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectHeroic.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectHeroic.java new file mode 100755 index 000000000..834865759 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectHeroic.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.monster.EntityMob; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.DamageSource; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; + +public class AlleleEffectHeroic extends AlleleEffectThrottled { + + public AlleleEffectHeroic(String uid) { + super(uid, "heroic", false, 40, true, false); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB hurtBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityMob.class, hurtBox); + + for (Object obj : list) { + EntityMob mob = (EntityMob) obj; + mob.attackEntityFrom(DamageSource.generic, 2); + } + + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectIgnition.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectIgnition.java new file mode 100755 index 000000000..6f6b9d26b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectIgnition.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.apiculture.items.ItemArmorApiarist; +import forestry.plugins.PluginApiculture; + +public class AlleleEffectIgnition extends AlleleEffectThrottled { + + int ignitionChance = 50; + int fireDuration = 500; + + public AlleleEffectIgnition(String uid) { + super(uid, "ignition", false, 20, false, true); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + World world = housing.getWorld(); + + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB hurtBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = world.getEntitiesWithinAABB(EntityLivingBase.class, hurtBox); + + for (Object obj : list) { + EntityLivingBase entity = (EntityLivingBase) obj; + + int chance = ignitionChance; + int duration = fireDuration; + + // Players are not attacked if they wear a full set of apiarist's + // armor. + if (entity instanceof EntityPlayer) { + int count = ItemArmorApiarist.wearsItems((EntityPlayer) entity, getUID(), true); + // Full set, no damage/effect + if (count > 3) + continue; + else if (count > 2) { + chance = 5; + duration = 50; + } else if (count > 1) { + chance = 20; + duration = 200; + } else if (count > 0) { + chance = 35; + duration = 350; + } + } + + if (world.rand.nextInt(1000) >= chance) + continue; + + entity.setFire(duration); + } + + return storedData; + } + + @Override + public IEffectData doFX(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + int[] area = getModifiedArea(genome, housing); + + if (housing.getWorld().rand.nextBoolean()) + PluginApiculture.proxy.addBeeHiveFX("particles/swarm_bee", housing.getWorld(), housing.getXCoord(), housing.getYCoord(), + housing.getZCoord(), genome.getPrimary().getIconColour(0), area[0], area[1], area[2]); + else + PluginApiculture.proxy.addBeeHiveFX("particles/ember", housing.getWorld(), housing.getXCoord(), housing.getYCoord(), + housing.getZCoord(), 0xffffff, area[0], area[1], area[2]); + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMiasmic.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMiasmic.java new file mode 100755 index 000000000..6cb7837aa --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMiasmic.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.apiculture.items.ItemArmorApiarist; +import forestry.plugins.PluginApiculture; + +public class AlleleEffectMiasmic extends AlleleEffectThrottled { + + private final int infectionChance = 50; + + public AlleleEffectMiasmic(String uid) { + super(uid, "misasmic", false, 50, false, false); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + World world = housing.getWorld(); + + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB infectionBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = world.getEntitiesWithinAABB(EntityPlayer.class, infectionBox); + + for (Object obj : list) { + + if (world.rand.nextInt(1000) >= infectionChance) + continue; + + EntityPlayer player = (EntityPlayer) obj; + + int duration = 800; + + // Players are not attacked if they wear a full set of apiarist's + // armor. + int count = ItemArmorApiarist.wearsItems(player, getUID(), true); + // Full set, no damage/effect + if (count > 3) + continue; + else if (count > 2) + duration = 200; + else if (count > 1) + duration = 400; + else if (count > 0) + duration = 600; + + player.addPotionEffect(new PotionEffect(Potion.poison.id, duration, 0)); + } + + return storedData; + } + + @Override + public IEffectData doFX(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + int[] area = getModifiedArea(genome, housing); + + if (housing.getWorld().rand.nextBoolean()) + PluginApiculture.proxy.addBeeHiveFX("particles/swarm_bee", housing.getWorld(), housing.getXCoord(), housing.getYCoord(), + housing.getZCoord(), genome.getPrimary().getIconColour(0), area[0], area[1], area[2]); + else + PluginApiculture.proxy.addBeeHiveFX("particles/poison", housing.getWorld(), housing.getXCoord(), housing.getYCoord(), + housing.getZCoord(), 0xffffff, area[0], area[1], area[2]); + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMisanthrope.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMisanthrope.java new file mode 100755 index 000000000..f557de48d --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectMisanthrope.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.DamageSource; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.apiculture.items.ItemArmorApiarist; +import forestry.core.utils.DamageSourceForestry; + +public class AlleleEffectMisanthrope extends AlleleEffectThrottled { + + public static DamageSource damageSourceBeeEnd = new DamageSourceForestry("bee.end"); + + public AlleleEffectMisanthrope(String uid) { + super(uid, "misanthrope", true, 20, false, false); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB beatifyBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityPlayer.class, beatifyBox); + + for (Object obj : list) { + EntityPlayer player = (EntityPlayer) obj; + + int damage = 4; + + // Players are not attacked if they wear a full set of apiarist's + // armor. + int count = ItemArmorApiarist.wearsItems(player, getUID(), true); + // Full set, no damage/effect + if (count > 3) + continue; + else if (count > 2) + damage = 1; + else if (count > 1) + damage = 2; + else if (count > 0) + damage = 3; + + player.attackEntityFrom(damageSourceBeeEnd, damage); + } + + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectNone.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectNone.java new file mode 100755 index 000000000..cd8aabbc4 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectNone.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.world.World; + +import forestry.api.apiculture.IAlleleBeeEffect; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.core.genetics.Allele; +import forestry.plugins.PluginApiculture; + +public class AlleleEffectNone extends Allele implements IAlleleBeeEffect { + + public AlleleEffectNone(String uid) { + super(uid, true); + } + + @Override + public IEffectData validateStorage(IEffectData storedData) { + return null; + } + + @Override + public boolean isCombinable() { + return false; + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + return doEffect(genome, storedData, housing.getWorld(), housing.getBiomeId(), housing.getXCoord(), housing.getYCoord(), housing.getZCoord()); + } + + protected IEffectData doEffect(IBeeGenome genome, IEffectData storedData, World world, int biomeid, int x, int y, int z) { + return storedData; + } + + @Override + public String getName() { + return "None"; + } + + @Override + public IEffectData doFX(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + int[] area = genome.getTerritory(); + area[0] *= housing.getTerritoryModifier(genome, 1f); + area[1] *= housing.getTerritoryModifier(genome, 1f); + area[2] *= housing.getTerritoryModifier(genome, 1f); + + if (area[0] < 1) + area[0] = 1; + if (area[1] < 1) + area[1] = 1; + if (area[2] < 1) + area[2] = 1; + + PluginApiculture.proxy.addBeeHiveFX("particles/swarm_bee", housing.getWorld(), housing.getXCoord(), housing.getYCoord(), + housing.getZCoord(), genome.getPrimary().getIconColour(0), area[0], area[1], area[2]); + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectPotion.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectPotion.java new file mode 100755 index 000000000..9a53f84f8 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectPotion.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.util.AxisAlignedBB; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; + +public class AlleleEffectPotion extends AlleleEffectThrottled { + + private int potionId = 0; + private final int duration; + + public AlleleEffectPotion(String uid, String name, boolean isDominant, Potion potion, int duration, boolean requiresWorking) { + super(uid, name, isDominant, 200, requiresWorking, false); + potionId = potion.getId(); + this.duration = duration; + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB beatifyBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityPlayer.class, beatifyBox); + + for (Object obj : list) { + EntityPlayer player = (EntityPlayer) obj; + player.addPotionEffect(new PotionEffect(potionId, duration, 0)); + } + + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRadioactive.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRadioactive.java new file mode 100755 index 000000000..2e658d0fe --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRadioactive.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.DamageSource; +import net.minecraft.world.World; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.apiculture.gadgets.BlockAlveary; +import forestry.apiculture.gadgets.TileAlveary; +import forestry.apiculture.items.ItemArmorApiarist; +import forestry.core.utils.DamageSourceForestry; +import forestry.core.utils.Vect; + +public class AlleleEffectRadioactive extends AlleleEffectThrottled { + + public static DamageSource damageSourceBeeRadioactive = new DamageSourceForestry("bee.radioactive"); + + public AlleleEffectRadioactive(String uid) { + super(uid, "radioactive", true, 40, false, true); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + World world = housing.getWorld(); + + if (isHalted(storedData, housing)) + return storedData; + + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0] * 2, areaAr[1] * 2, areaAr[2] * 2); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + // Radioactivity hurts players and mobs + Vect min = new Vect(housing.getXCoord() + offset.x, housing.getYCoord() + offset.y, housing.getZCoord() + offset.z); + Vect max = new Vect(housing.getXCoord() + offset.x + area.x, housing.getYCoord() + offset.y + area.y, housing.getZCoord() + offset.z + area.z); + + AxisAlignedBB hurtBox = AxisAlignedBB.getAABBPool().getAABB(min.x, min.y, min.z, max.x, max.y, max.z); + + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityLivingBase.class, hurtBox); + + for (Object obj : list) { + EntityLivingBase entity = (EntityLivingBase) obj; + + int damage = 8; + + // Players are not attacked if they wear a full set of apiarist's + // armor. + if (entity instanceof EntityPlayer) { + int count = ItemArmorApiarist.wearsItems((EntityPlayer) entity, getUID(), true); + // Full set, no damage/effect + if (count > 3) + continue; + else if (count > 2) + damage = 1; + else if (count > 1) + damage = 2; + else if (count > 0) + damage = 3; + } + + entity.attackEntityFrom(damageSourceBeeRadioactive, damage); + + } + + Random rand = housing.getWorld().rand; + // Radioactivity destroys environment + for (int i = 0; i < 20; i++) { + + Vect randomPos = new Vect(rand.nextInt(area.x), rand.nextInt(area.y), rand.nextInt(area.z)); + + Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord())); + posBlock = posBlock.add(offset); + + if(posBlock.y <= 1 || posBlock.y >= housing.getWorld().getActualHeight()) + continue; + + // Don't destroy ourself and blocks below us. + if (posBlock.x == housing.getXCoord() && posBlock.z == housing.getZCoord() && posBlock.y <= housing.getYCoord()) + continue; + + if (world.isAirBlock(posBlock.x, posBlock.y, posBlock.z)) + continue; + + Block block = world.getBlock(posBlock.x, posBlock.y, posBlock.z); + + if (block instanceof BlockAlveary) + continue; + + TileEntity tile = world.getTileEntity(posBlock.x, posBlock.y, posBlock.z); + if (tile instanceof IBeeHousing) + continue; + if (tile instanceof TileAlveary) + continue; + + if (block.getBlockHardness(world, posBlock.x, posBlock.y, posBlock.z) < 0) + continue; + + world.setBlockToAir(posBlock.x, posBlock.y, posBlock.z); + break; + } + + return storedData; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRepulsion.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRepulsion.java new file mode 100755 index 000000000..0a7034503 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectRepulsion.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry; +import net.minecraft.entity.monster.EntityMob; +import net.minecraft.util.AxisAlignedBB; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; + +public class AlleleEffectRepulsion extends AlleleEffectThrottled { + + public AlleleEffectRepulsion(String uid) { + super(uid, "repulsion", false, 100, true, true); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + if (isHalted(storedData, housing)) + return storedData; + + if (housing.getOwnerName() == null || housing.getOwnerName().isEmpty()) + return storedData; + + AxisAlignedBB hurtBox = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityMob.class, hurtBox); + + for (Object obj : list) { + EntityMob mob = (EntityMob) obj; + + for (Object objT : mob.tasks.taskEntries) { + EntityAITaskEntry task = (EntityAITaskEntry) objT; + if (task.action instanceof AIAvoidPlayers) + return storedData; + } + + mob.tasks.addTask(3, new AIAvoidPlayers(mob, 6.0f, 0.25f, 0.3f)); + mob.tasks.onUpdateTasks(); + + } + + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectResurrection.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectResurrection.java new file mode 100755 index 000000000..d7fabfcc2 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectResurrection.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.boss.EntityDragon; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.monster.EntityBlaze; +import net.minecraft.entity.monster.EntityCaveSpider; +import net.minecraft.entity.monster.EntityCreeper; +import net.minecraft.entity.monster.EntityEnderman; +import net.minecraft.entity.monster.EntityGhast; +import net.minecraft.entity.monster.EntitySkeleton; +import net.minecraft.entity.monster.EntitySpider; +import net.minecraft.entity.monster.EntityZombie; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.AxisAlignedBB; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class AlleleEffectResurrection extends AlleleEffectThrottled { + + public static class Resurrectable { + public final ItemStack res; + public final Class risen; + + public Resurrectable(ItemStack res, Class risen) { + this.res = res; + this.risen = risen; + } + } + + public static List getReanimationList() { + ArrayList list = new ArrayList(); + list.add(new Resurrectable(new ItemStack(Items.bone), EntitySkeleton.class)); + list.add(new Resurrectable(new ItemStack(Items.arrow), EntitySkeleton.class)); + list.add(new Resurrectable(new ItemStack(Items.rotten_flesh), EntityZombie.class)); + list.add(new Resurrectable(new ItemStack(Items.blaze_rod), EntityBlaze.class)); + return list; + } + + public static List getResurrectionList() { + ArrayList list = new ArrayList(); + list.add(new Resurrectable(new ItemStack(Items.gunpowder), EntityCreeper.class)); + list.add(new Resurrectable(new ItemStack(Items.ender_pearl), EntityEnderman.class)); + list.add(new Resurrectable(new ItemStack(Items.string), EntitySpider.class)); + list.add(new Resurrectable(new ItemStack(Items.spider_eye), EntitySpider.class)); + list.add(new Resurrectable(new ItemStack(Items.string), EntityCaveSpider.class)); + list.add(new Resurrectable(new ItemStack(Items.spider_eye), EntityCaveSpider.class)); + list.add(new Resurrectable(new ItemStack(Items.ghast_tear), EntityGhast.class)); + list.add(new Resurrectable(new ItemStack(Blocks.dragon_egg), EntityDragon.class)); + return list; + } + + private final List resurrectables; + + public AlleleEffectResurrection(String uid, String name, List resurrectables) { + super(uid, name, true, 40, true, true); + this.resurrectables = resurrectables; + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + if (isHalted(storedData, housing)) + return storedData; + + AxisAlignedBB bounding = getBounding(genome, housing, 1.0f); + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityItem.class, bounding); + + if (list.size() > 0) + Collections.shuffle(resurrectables); + + for (Object obj : list) { + EntityItem item = (EntityItem) obj; + if (item.isDead) + continue; + + ItemStack contained = item.getEntityItem(); + for (Resurrectable entry : resurrectables) + if (StackUtils.isIdenticalItem(entry.res, contained)) { + Utils.spawnEntity(housing.getWorld(), entry.risen, item.posX, item.posY, item.posZ); + contained.stackSize--; + if (contained.stackSize <= 0) + item.setDead(); + break; + } + } + + return storedData; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectSnowing.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectSnowing.java new file mode 100755 index 000000000..3364f631e --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectSnowing.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.IEffectData; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Vect; + +public class AlleleEffectSnowing extends AlleleEffectThrottled { + + public AlleleEffectSnowing(String uid) { + super(uid, "snowing", false, 20, true, true); + } + + @Override + public IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + World world = housing.getWorld(); + + if (isHalted(storedData, housing)) + return storedData; + + EnumTemperature temp = EnumTemperature.getFromValue(BiomeGenBase.getBiome(housing.getBiomeId()).temperature); + + switch (temp) { + case HELLISH: + case HOT: + case WARM: + return storedData; + default: + } + + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + for (int i = 0; i < 1; i++) { + + Vect randomPos = new Vect(world.rand.nextInt(area.x), world.rand.nextInt(area.y), world.rand.nextInt(area.z)); + + Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord())); + posBlock = posBlock.add(offset); + + // Put snow on the ground + if (!world.isSideSolid(posBlock.x, posBlock.y - 1, posBlock.z, ForgeDirection.UP, false)) + continue; + + if (!world.isAirBlock(posBlock.x, posBlock.y, posBlock.z)) + continue; + + Proxies.common.setBlockWithNotify(world, posBlock.x, posBlock.y, posBlock.z, Blocks.snow_layer); + } + + return storedData; + } + + @Override + public IEffectData doFX(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + if (housing.getWorld().rand.nextInt(3) == 0) { + int[] area = getModifiedArea(genome, housing); + Proxies.render.addSnowFX(housing.getWorld(), housing.getXCoord(), housing.getYCoord(), housing.getZCoord(), genome.getPrimary().getIconColour(0), area[0], area[1], area[2]); + } + return storedData; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectThrottled.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectThrottled.java new file mode 100755 index 000000000..f64bb8b0c --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleEffectThrottled.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.util.AxisAlignedBB; + +import forestry.api.apiculture.IAlleleBeeEffect; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IEffectData; +import forestry.core.EnumErrorCode; +import forestry.core.genetics.Allele; +import forestry.core.genetics.EffectData; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Vect; +import forestry.plugins.PluginApiculture; + +public abstract class AlleleEffectThrottled extends Allele implements IAlleleBeeEffect { + + private String name; + private boolean isCombinable = false; + private int throttle; + private boolean requiresWorkingQueen = false; + + public AlleleEffectThrottled(String uid, String name, boolean isDominant, int throttle, boolean requiresWorking, boolean isCombinable) { + super(uid, isDominant); + this.name = "apiculture.effect." + name; + this.throttle = throttle; + this.isCombinable = isCombinable; + this.requiresWorkingQueen = requiresWorking; + } + + @Override + public String getName() { + return StringUtil.localize(name); + } + + public int getThrottle() { + return throttle; + } + + @Override + public boolean isCombinable() { + return isCombinable; + } + + @Override + public IEffectData validateStorage(IEffectData storedData) { + if (storedData instanceof EffectData) + return storedData; + + return new EffectData(1, 0); + } + + public boolean isHalted(IEffectData storedData, IBeeHousing housing) { + + if (requiresWorkingQueen && housing.getErrorOrdinal() != EnumErrorCode.OK.ordinal()) + return true; + + int throttle = storedData.getInteger(0); + throttle++; + storedData.setInteger(0, throttle); + + if (throttle < getThrottle()) + return true; + + // Reset since we are done throttling. + storedData.setInteger(0, 0); + return false; + } + + @Override + public IEffectData doFX(IBeeGenome genome, IEffectData storedData, IBeeHousing housing) { + + int[] area = getModifiedArea(genome, housing); + + PluginApiculture.proxy.addBeeHiveFX("particles/swarm_bee", housing.getWorld(), housing.getXCoord(), housing.getYCoord(), + housing.getZCoord(), genome.getPrimary().getIconColour(0), area[0], area[1], area[2]); + return storedData; + } + + protected int[] getModifiedArea(IBeeGenome genome, IBeeHousing housing) { + int[] area = genome.getTerritory(); + area[0] *= housing.getTerritoryModifier(genome, 1f) * 3; + area[1] *= housing.getTerritoryModifier(genome, 1f) * 3; + area[2] *= housing.getTerritoryModifier(genome, 1f) * 3; + + if (area[0] < 1) + area[0] = 1; + if (area[1] < 1) + area[1] = 1; + if (area[2] < 1) + area[2] = 1; + + return area; + } + + protected AxisAlignedBB getBounding(IBeeGenome genome, IBeeHousing housing, float modifier) { + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(modifier); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + // Radioactivity hurts players and mobs + Vect min = new Vect(housing.getXCoord() + offset.x, housing.getYCoord() + offset.y, housing.getZCoord() + offset.z); + Vect max = new Vect(housing.getXCoord() + offset.x + area.x, housing.getYCoord() + offset.y + area.y, housing.getZCoord() + offset.z + area.z); + + return AxisAlignedBB.getAABBPool().getAABB(min.x, min.y, min.z, max.x, max.y, max.z); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/AlleleFlowers.java b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleFlowers.java new file mode 100755 index 000000000..0f9c85c44 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/AlleleFlowers.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import forestry.api.genetics.IAlleleFlowers; +import forestry.api.genetics.IFlowerProvider; +import forestry.core.genetics.Allele; + +public class AlleleFlowers extends Allele implements IAlleleFlowers { + + IFlowerProvider provider; + + public AlleleFlowers(String uid, IFlowerProvider provider) { + this(uid, provider, false); + } + + public AlleleFlowers(String uid, IFlowerProvider provider, boolean isDominant) { + super(uid, isDominant); + this.provider = provider; + } + + @Override + public IFlowerProvider getProvider() { + return provider; + } + + @Override + public String getName() { + return getProvider().getDescription(); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/ApiaristTracker.java b/forestry_common/apiculture/forestry/apiculture/genetics/ApiaristTracker.java new file mode 100755 index 000000000..d3e80d541 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/ApiaristTracker.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IIndividual; +import forestry.core.genetics.BreedingTracker; +import forestry.plugins.PluginApiculture; + +public class ApiaristTracker extends BreedingTracker implements IApiaristTracker { + + public ApiaristTracker(String s) { + this(s, ""); + } + + public ApiaristTracker(String s, String player) { + super(s, player); + } + + private int queensTotal = 0; + private int dronesTotal = 0; + private int princessesTotal = 0; + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + queensTotal = nbttagcompound.getInteger("QueensTotal"); + princessesTotal = nbttagcompound.getInteger("PrincessesTotal"); + dronesTotal = nbttagcompound.getInteger("DronesTotal"); + + super.readFromNBT(nbttagcompound); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + nbttagcompound.setInteger("QueensTotal", queensTotal); + nbttagcompound.setInteger("PrincessesTotal", princessesTotal); + nbttagcompound.setInteger("DronesTotal", dronesTotal); + + super.writeToNBT(nbttagcompound); + + } + + @Override + public void registerPickup(IIndividual individual) { + if(!individual.getGenome().getPrimary().getRoot().getUID().equals(BeeHelper.UID)) + return; + if(!individual.isPureBred(0)) + return; + if(PluginApiculture.beeInterface.getCombinations(individual.getGenome().getPrimary()).size() > 0) + return; + + registerSpecies(individual.getGenome().getPrimary()); + } + + @Override + public void registerQueen(IIndividual bee) { + queensTotal++; + } + + @Override + public int getQueenCount() { + return queensTotal; + } + + @Override + public void registerPrincess(IIndividual bee) { + + princessesTotal++; + registerBirth(bee); + } + + @Override + public int getPrincessCount() { + return princessesTotal; + } + + @Override + public void registerDrone(IIndividual bee) { + dronesTotal++; + registerBirth(bee); + } + + @Override + public int getDroneCount() { + return dronesTotal; + } + + @Override + protected IBreedingTracker getCommonTracker(EntityPlayer player) { + return PluginApiculture.beeInterface.getBreedingTracker(player.worldObj, "__COMMON_"); + } + + @Override + protected String getPacketTag() { + return BeeHelper.UID; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/Bee.java b/forestry_common/apiculture/forestry/apiculture/genetics/Bee.java new file mode 100755 index 000000000..0e65f93f8 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/Bee.java @@ -0,0 +1,713 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.IAlleleBeeEffect; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeeMutation; +import forestry.api.apiculture.IBeekeepingMode; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IEffectData; +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IGenome; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.EnumErrorCode; +import forestry.core.config.Defaults; +import forestry.core.genetics.Chromosome; +import forestry.core.genetics.ClimateHelper; +import forestry.core.genetics.GenericRatings; +import forestry.core.genetics.IndividualLiving; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; +import forestry.plugins.PluginApiculture; + +public class Bee extends IndividualLiving implements IBee { + + public IBeeGenome genome; + public IBeeGenome mate; + + /* CONSTRUCTOR */ + public Bee(NBTTagCompound nbttagcompound) { + readFromNBT(nbttagcompound); + } + + public Bee(World world, IBeeGenome genome, IBee mate) { + this(world, genome); + this.mate = mate.getGenome(); + this.isIrregularMating = mate.isNatural() != this.isNatural; + } + + public Bee(IBeeGenome genome, IBee mate) { + this(genome); + this.mate = mate.getGenome(); + this.isIrregularMating = mate.isNatural() != this.isNatural; + } + + public Bee(World world, IBeeGenome genome) { + this(world, genome, true, 0); + } + + public Bee(IBeeGenome genome) { + this(genome, true, 0); + } + + public Bee(World world, IBeeGenome genome, boolean isNatural, int generation) { + super(genome.getLifespan(), isNatural, generation); + this.genome = genome; + } + + public Bee(IBeeGenome genome, boolean isNatural, int generation) { + super(genome.getLifespan(), isNatural, generation); + this.genome = genome; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + if (nbttagcompound == null) { + this.genome = PluginApiculture.beeInterface.templateAsGenome(BeeTemplates.getForestTemplate()); + return; + } + + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("Genome")) + genome = new BeeGenome(nbttagcompound.getCompoundTag("Genome")); + else + genome = PluginApiculture.beeInterface.templateAsGenome(BeeTemplates.getForestTemplate()); + if (nbttagcompound.hasKey("Mate")) + mate = new BeeGenome(nbttagcompound.getCompoundTag("Mate")); + + } + + @Override + public void mate(IIndividual individual) { + if(!(individual instanceof IBee)) + return; + + IBee drone = (IBee)individual; + mate = drone.getGenome(); + this.isIrregularMating = drone.isNatural() != this.isNatural; + } + + /* EFFECTS */ + @Override + public IEffectData[] doEffect(IEffectData[] storedData, IBeeHousing housing) { + IAlleleBeeEffect effect = genome.getEffect(); + + if (effect == null) + return null; + + storedData[0] = doEffect(effect, storedData[0], housing); + + // Return here if the primary can already not be combined + if (!effect.isCombinable()) + return storedData; + + IAlleleBeeEffect secondary = (IAlleleBeeEffect) genome.getInactiveAllele(EnumBeeChromosome.EFFECT.ordinal()); + if (!secondary.isCombinable()) + return storedData; + + storedData[1] = doEffect(secondary, storedData[1], housing); + + return storedData; + } + + private IEffectData doEffect(IAlleleBeeEffect effect, IEffectData storedData, IBeeHousing housing) { + storedData = effect.validateStorage(storedData); + return effect.doEffect(genome, storedData, housing); + } + + @Override + public IEffectData[] doFX(IEffectData[] storedData, IBeeHousing housing) { + IAlleleBeeEffect effect = genome.getEffect(); + + if (effect == null) + return null; + + storedData[0] = doFX(effect, storedData[0], housing); + + // Return here if the primary can already not be combined + if (!effect.isCombinable()) + return storedData; + + IAlleleBeeEffect secondary = (IAlleleBeeEffect) genome.getInactiveAllele(EnumBeeChromosome.EFFECT.ordinal()); + if (!secondary.isCombinable()) + return storedData; + + storedData[1] = doFX(secondary, storedData[1], housing); + + return storedData; + } + + private IEffectData doFX(IAlleleBeeEffect effect, IEffectData storedData, IBeeHousing housing) { + return effect.doFX(genome, storedData, housing); + } + + // / INFORMATION + @Override + public IBeeGenome getGenome() { + return genome; + } + + @Override + public IBeeGenome getMate() { + return mate; + } + + @Override + public IBee copy() { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + this.writeToNBT(nbttagcompound); + return new Bee(nbttagcompound); + + } + + @Override + public boolean canSpawn() { + return mate != null; + } + + @Override + public int isWorking(IBeeHousing housing) { + + World world = housing.getWorld(); + // / Rain needs tolerant flyers + if (world.isRaining() && !genome.getTolerantFlyer() && housing.getHumidity() != EnumHumidity.ARID && !housing.isSealed()) + return EnumErrorCode.ISRAINING.ordinal(); + + // / Night or darkness requires nocturnal species + if(world.isDaytime()) { + if(!canWorkDuringDay()) + return EnumErrorCode.NOTNIGHT.ordinal(); + } else if (!canWorkAtNight() && !housing.isSelfLighted()) + return EnumErrorCode.NOTDAY.ordinal(); + + if (world.getBlockLightValue(housing.getXCoord(), housing.getYCoord() + 2, housing.getZCoord()) > Defaults.APIARY_MIN_LEVEL_LIGHT) { + if(!canWorkDuringDay()) + return EnumErrorCode.NOTGLOOMY.ordinal(); + } else if(!canWorkAtNight() && !housing.isSelfLighted()) + return EnumErrorCode.NOTLUCID.ordinal(); + + // / No sky, except if in hell + BiomeGenBase biome = BiomeGenBase.getBiome(housing.getBiomeId()); + if(biome == null) + return EnumErrorCode.NOSKY.ordinal(); + if (!BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.NETHER) && !world.canBlockSeeTheSky(housing.getXCoord(), housing.getYCoord() + 3, housing.getZCoord()) + && !genome.getCaveDwelling() && !housing.isSunlightSimulated()) + return EnumErrorCode.NOSKY.ordinal(); + + // / And finally biome check + if (!checkBiomeHazard(world, housing.getTemperature(), housing.getHumidity(), housing.getXCoord(), housing.getYCoord(), housing.getZCoord())) + return EnumErrorCode.INVALIDBIOME.ordinal(); + + return EnumErrorCode.OK.ordinal(); + } + + private boolean canWorkAtNight() { + return genome.getPrimary().isNocturnal() || genome.getNocturnal(); + } + + private boolean canWorkDuringDay() { + return !genome.getPrimary().isNocturnal() || genome.getNocturnal(); + } + + private boolean checkBiomeHazard(World world, EnumTemperature temperature, EnumHumidity humidity, int x, int y, int z) { + + return ClimateHelper.isWithinLimits(temperature, humidity, + genome.getPrimary().getTemperature(), genome.getToleranceTemp(), + genome.getPrimary().getHumidity(), genome.getToleranceHumid()); + } + + @Override + public boolean hasFlower(IBeeHousing housing) { + + IFlowerProvider provider = genome.getFlowerProvider(); + + Vect coords = new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord()); + Vect posCurrent = new Vect(0, 0, 0); + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f)); + + if (area.x < 1) + area.x = 1; + if (area.y < 1) + area.y = 1; + if (area.z < 1) + area.z = 1; + + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + boolean hasFlower = false; + + while (advancePosition(posCurrent, area)) { + + Vect posBlock = posCurrent.add(coords); + posBlock = posBlock.add(offset); + + if (provider.isAcceptedFlower(housing.getWorld(), this, posBlock.x, posBlock.y, posBlock.z)) { + hasFlower = true; + break; + } + + } + + return hasFlower; + } + + private boolean advancePosition(Vect posCurrent, Vect area) { + // Increment z first until end reached + if (posCurrent.z < area.z - 1) + posCurrent.z++; + else { + posCurrent.z = 0; + + if (posCurrent.x < area.x - 1) + posCurrent.x++; + else { + posCurrent.x = 0; + + if (posCurrent.y < area.y - 1) + posCurrent.y++; + else + return false; + } + } + + return true; + } + + @Override + public ArrayList getSuitableBiomeIds() { + EnumTemperature temperature = genome.getPrimary().getTemperature(); + EnumTolerance temperatureTolerance = genome.getToleranceTemp(); + + ArrayList toleratedTemperatures = ClimateHelper.getToleratedTemperature(temperature, temperatureTolerance); + + EnumHumidity humidity = genome.getPrimary().getHumidity(); + EnumTolerance humidityTolerance = genome.getToleranceHumid(); + + ArrayList toleratedHumidities = ClimateHelper.getToleratedHumidity(humidity, humidityTolerance); + + ArrayList biomeIdsTemp = new ArrayList(); + for (EnumTemperature temp : toleratedTemperatures) + biomeIdsTemp.addAll(EnumTemperature.getBiomeIds(temp)); + + ArrayList biomeIdsHumid = new ArrayList(); + for (EnumHumidity humid : toleratedHumidities) + biomeIdsHumid.addAll(EnumHumidity.getBiomeIds(humid)); + + biomeIdsTemp.retainAll(biomeIdsHumid); + + return biomeIdsTemp; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addTooltip(List list) { + + // No info 4 u! + if (!isAnalyzed) { + list.add("<" + StringUtil.localize("gui.unknown") + ">"); + return; + } + + // You analyzed it? Juicy tooltip coming up! + IAlleleBeeSpecies primary = genome.getPrimary(); + IAlleleBeeSpecies secondary = genome.getSecondary(); + if (!isPureBred(EnumBeeChromosome.SPECIES.ordinal())) + list.add("\u00A79" + primary.getName() + StringUtil.localize("bees.hyphen.adj.add") + "-" + secondary.getName() + + StringUtil.localize("bees.hybrid.adj.add") + " " + StringUtil.localize("gui.hybrid")); + list.add(genome.getActiveAllele(EnumBeeChromosome.SPEED.ordinal()).getName() + " " + StringUtil.localize("gui.worker")); + list.add(genome.getActiveAllele(EnumBeeChromosome.LIFESPAN.ordinal()).getName() + " " + StringUtil.localize("gui.life")); + list.add("\u00A7aT: " + ClimateHelper.toDisplay(genome.getPrimary().getTemperature()) + " / " + + StringUtil.capitalize(genome.getToleranceTemp().name())); + list.add("\u00A7aH: " + ClimateHelper.toDisplay(genome.getPrimary().getHumidity()) + " / " + + StringUtil.capitalize(genome.getToleranceHumid().name())); + list.add(StringUtil.localize(genome.getFlowerProvider().getDescription())); + if (genome.getNocturnal()) + list.add("\u00A7c" + GenericRatings.rateActivityTime(genome.getNocturnal(), false)); + } + + @Override + public void age(World world, float housingLifespanModifier) { + IBeekeepingMode mode = PluginApiculture.beeInterface.getBeekeepingMode(world); + float finalModifier = housingLifespanModifier * mode.getLifespanModifier(genome, mate, housingLifespanModifier); + + super.age(world, finalModifier); + } + + // / PRODUCTION + @Override + public ItemStack[] getProduceList() { + ArrayList products = new ArrayList(); + + IAlleleBeeSpecies primary = genome.getPrimary(); + IAlleleBeeSpecies secondary = genome.getSecondary(); + + products.addAll(primary.getProducts().keySet()); + + Set secondaryProducts = secondary.getProducts().keySet(); + // Remove duplicates + for (ItemStack second : secondaryProducts) { + boolean skip = false; + + for (ItemStack compare : products) + if (second.isItemEqual(compare)) { + skip = true; + break; + } + + if (!skip) + products.add(second); + + } + + return products.toArray(new ItemStack[0]); + } + + @Override + public ItemStack[] getSpecialtyList() { + return genome.getPrimary().getSpecialty().keySet().toArray(new ItemStack[0]); + } + + @Override + public ItemStack[] produceStacks(IBeeHousing housing) { + if (!hasFlower(housing)) + return null; + + if (housing == null) { + Proxies.log.warning("Failed to produce in an apiary because the beehousing was null."); + return null; + } + IBeekeepingMode mode = PluginApiculture.beeInterface.getBeekeepingMode(housing.getWorld()); + if (mode == null) { + Proxies.log.warning("Failed to produce in an apiary because the beekeeping mode was null."); + return null; + } + + ArrayList products = new ArrayList(); + + IAlleleBeeSpecies primary = genome.getPrimary(); + IAlleleBeeSpecies secondary = genome.getSecondary(); + + // All work and no play makes queen a dull girl. + if(mode.isOverworked(this, housing)) + setIsNatural(false); + + // Bee genetic speed * beehousing * beekeeping mode + float speed = genome.getSpeed() * housing.getProductionModifier(genome, 1f) * mode.getProductionModifier(genome, 1f); + + // / Primary Products + for (Map.Entry entry : primary.getProducts().entrySet()) + if (housing.getWorld().rand.nextInt(100) < entry.getValue() * speed) + products.add(entry.getKey().copy()); + // / Secondary Products + for (Map.Entry entry : secondary.getProducts().entrySet()) + if (housing.getWorld().rand.nextInt(100) < Math.round(entry.getValue() / 2) * speed) + products.add(entry.getKey().copy()); + + // We are done if the we are not jubilant. + if (!primary.isJubilant(genome, housing) || !secondary.isJubilant(genome, housing)) + return products.toArray(StackUtils.EMPTY_STACK_ARRAY); + + // / Specialty products + for (Map.Entry entry : primary.getSpecialty().entrySet()) + if (housing.getWorld().rand.nextInt(100) < entry.getValue() * speed) + products.add(entry.getKey().copy()); + + return genome.getFlowerProvider().affectProducts(housing.getWorld(), this, housing.getXCoord(), housing.getYCoord(), housing.getZCoord(), + products.toArray(StackUtils.EMPTY_STACK_ARRAY)); + } + + /* REPRODUCTION */ + @Override + public IBee spawnPrincess(IBeeHousing housing) { + + // We need a mated queen to produce offspring. + if (mate == null) + return null; + + // Fatigued queens do not produce princesses. + if (PluginApiculture.beeInterface.getBeekeepingMode(housing.getWorld()).isFatigued(this, housing)) + return null; + + return createOffspring(housing, getGeneration() + 1); + } + + @Override + public IBee[] spawnDrones(IBeeHousing housing) { + + World world = housing.getWorld(); + + // We need a mated queen to produce offspring. + if (mate == null) + return null; + + ArrayList bees = new ArrayList(); + + int toCreate = PluginApiculture.beeInterface.getBeekeepingMode(world).getFinalFertility(this, world, housing.getXCoord(), housing.getYCoord(), + housing.getZCoord()); + + if (toCreate <= 0) + toCreate = 1; + + for (int i = 0; i < toCreate; i++) { + IBee offspring = createOffspring(housing, -1); + if (offspring != null) { + offspring.setIsNatural(true); + bees.add(offspring); + } + } + + if (bees.size() > 0) + return bees.toArray(new IBee[0]); + else + return null; + } + + private IBee createOffspring(IBeeHousing housing, int generation) { + + World world = housing.getWorld(); + + IChromosome[] chromosomes = new IChromosome[genome.getChromosomes().length]; + IChromosome[] parent1 = genome.getChromosomes(); + IChromosome[] parent2 = mate.getChromosomes(); + + // Check for mutation. Replace one of the parents with the mutation + // template if mutation occured. + IChromosome[] mutated1 = mutateSpecies(housing, genome, mate); + if (mutated1 != null) + parent1 = mutated1; + IChromosome[] mutated2 = mutateSpecies(housing, mate, genome); + if (mutated2 != null) + parent2 = mutated2; + + for (int i = 0; i < parent1.length; i++) + if (parent1[i] != null && parent2[i] != null) + chromosomes[i] = Chromosome.inheritChromosome(world.rand, parent1[i], parent2[i]); + + IBeekeepingMode mode = PluginApiculture.beeInterface.getBeekeepingMode(world); + IBee offspring = new Bee(world, new BeeGenome(chromosomes), mode.isNaturalOffspring(this), generation); + + /* Disabling the mutation rate nerf + // All mutation and no play makes queen a dull girl. + if(mode.isDegenerating(this, offspring, housing)) + offspring.setIsNatural(false);*/ + + return offspring; + } + + private IChromosome[] mutateSpecies(IBeeHousing housing, IGenome genomeOne, IGenome genomeTwo) { + + World world = housing.getWorld(); + + IChromosome[] parent1 = genomeOne.getChromosomes(); + IChromosome[] parent2 = genomeTwo.getChromosomes(); + + IGenome genome0; + IGenome genome1; + IAllele allele0; + IAllele allele1; + + if (world.rand.nextBoolean()) { + allele0 = parent1[EnumBeeChromosome.SPECIES.ordinal()].getPrimaryAllele(); + allele1 = parent2[EnumBeeChromosome.SPECIES.ordinal()].getSecondaryAllele(); + + genome0 = genomeOne; + genome1 = genomeTwo; + } else { + allele0 = parent2[EnumBeeChromosome.SPECIES.ordinal()].getPrimaryAllele(); + allele1 = parent1[EnumBeeChromosome.SPECIES.ordinal()].getSecondaryAllele(); + + genome0 = genomeTwo; + genome1 = genomeOne; + } + + for (IBeeMutation mutation : PluginApiculture.beeInterface.getMutations(true)) { + float chance = 0; + + if ((chance = mutation.getChance(housing, allele0, allele1, genome0, genome1)) > 0) + if (world.rand.nextFloat()*100 < chance) { + IApiaristTracker breedingTracker = PluginApiculture.beeInterface.getBreedingTracker(world, housing.getOwnerName()); + breedingTracker.registerMutation(mutation); + return PluginApiculture.beeInterface.templateAsChromosomes(mutation.getTemplate()); + } + } + + return null; + } + + /* FLOWERS */ + @Override + public IIndividual retrievePollen(IBeeHousing housing) { + + int chance = (int) (genome.getFlowering() * housing.getFloweringModifier(getGenome(), 1f)); + + // Correct speed + if (housing.getWorld().rand.nextInt(100) >= chance) + return null; + + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f)).multiply(3.0f); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + if (area.x < 1) + area.x = 1; + if (area.y < 1) + area.y = 1; + if (area.z < 1) + area.z = 1; + + // We have up to ten attempts + for (int i = 0; i < 20; i++) { + + Vect randomPos = new Vect(housing.getWorld().rand.nextInt(area.x), housing.getWorld().rand.nextInt(area.y), housing.getWorld().rand.nextInt(area.z)); + + Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord())); + posBlock = posBlock.add(offset); + + TileEntity tile = housing.getWorld().getTileEntity(posBlock.x, posBlock.y, posBlock.z); + if (!(tile instanceof IPollinatable)) { + if (housing.getWorld().isAirBlock(posBlock.x, posBlock.y, posBlock.z)) + continue; + + // Test for ersatz genomes + for (Map.Entry entry : AlleleManager.ersatzSpecimen.entrySet()) { + if (!StackUtils.equals(housing.getWorld().getBlock(posBlock.x, posBlock.y, posBlock.z), entry.getKey())) + continue; + if (entry.getKey().getItemDamage() != housing.getWorld().getBlockMetadata(posBlock.x, posBlock.y, posBlock.z)) + continue; + + // We matched, return ersatz genome + return entry.getValue().copy(); + } + + continue; + } + + IPollinatable pitcher = (IPollinatable) tile; + if (!genome.getFlowerProvider().isAcceptedPollinatable(housing.getWorld(), pitcher)) + continue; + + IIndividual pollen = pitcher.getPollen(); + + if (pollen != null) + return pollen; + } + + return null; + } + + @Override + public boolean pollinateRandom(IBeeHousing housing, IIndividual pollen) { + + int chance = (int) (genome.getFlowering() * housing.getFloweringModifier(getGenome(), 1f)); + + // Correct speed + if (housing.getWorld().rand.nextInt(100) >= chance) + return false; + + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f)).multiply(3.0f); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 4), -Math.round(area.z / 2)); + + if (area.x < 1) + area.x = 1; + if (area.y < 1) + area.y = 1; + if (area.z < 1) + area.z = 1; + + // We have up to ten attempts + for (int i = 0; i < 30; i++) { + + Vect randomPos = new Vect(housing.getWorld().rand.nextInt(area.x), housing.getWorld().rand.nextInt(area.y), housing.getWorld().rand.nextInt(area.z)); + + Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord())); + posBlock = posBlock.add(offset); + + IPollinatable receiver = Utils.getOrCreatePollinatable(housing.getOwnerName(), housing.getWorld(), posBlock.x, posBlock.y, posBlock.z); + if(receiver == null) + continue; + + if (!genome.getFlowerProvider().isAcceptedPollinatable(housing.getWorld(), receiver)) + continue; + if (!receiver.canMateWith(pollen)) + continue; + + receiver.mateWith(pollen); + return true; + } + + return false; + } + + @Override + public void plantFlowerRandom(IBeeHousing housing) { + + int chance = (int) (genome.getFlowering() * housing.getFloweringModifier(getGenome(), 1f)); + + // Correct speed + if (housing.getWorld().rand.nextInt(100) >= chance) + return; + + // Gather required info + IFlowerProvider provider = genome.getFlowerProvider(); + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(housing.getTerritoryModifier(genome, 1f)).multiply(3.0f); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 4), -Math.round(area.z / 2)); + + if (area.x < 1) + area.x = 1; + if (area.y < 1) + area.y = 1; + if (area.z < 1) + area.z = 1; + + // We have up to ten attempts + for (int i = 0; i < 10; i++) { + + Vect randomPos = new Vect(housing.getWorld().rand.nextInt(area.x), housing.getWorld().rand.nextInt(area.y), housing.getWorld().rand.nextInt(area.z)); + + Vect posBlock = randomPos.add(new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord())); + posBlock = posBlock.add(offset); + + if (provider.growFlower(housing.getWorld(), this, posBlock.x, posBlock.y, posBlock.z)) + break; + } + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/BeeGenome.java b/forestry_common/apiculture/forestry/apiculture/genetics/BeeGenome.java new file mode 100755 index 000000000..6cfe7727f --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/BeeGenome.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.IAlleleBeeEffect; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IAlleleFloat; +import forestry.api.genetics.IAlleleFlowers; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.genetics.AlleleArea; +import forestry.core.genetics.AlleleBoolean; +import forestry.core.genetics.AlleleTolerance; +import forestry.core.genetics.Genome; +import forestry.core.utils.Vect; +import forestry.plugins.PluginApiculture; + +public class BeeGenome extends Genome implements IBeeGenome { + /** + * 0 - Species (determines product) + * + * 1 - Speed + * + * 2 - Lifespan + * + * 3 - Fertility (Maximum number of offspring) + * + * 4 - Preferred temperature Icy: Snow biomes Cold: Tundra/Steppe, Extreme Mountains/Hills? Normal: Plains, Forests, Mountains Hot: Desert Hellish: Nether + * + * 5 - Temperature tolerance (Range +/-) + * + * 6 - Nocturnal + * + * 7 - Preferred humidity (Arid - Normal - Damp) + * + * 8 - Humidity tolerance (Range +/-) + * + * 9 - Flight interference tolerance (stuff falling from the sky/other hindrances -> tolerates dampness + flight interference tolerance => rain resistance) + * + * 10 - Cave dwelling + * + * 11 - Required flowers + * + * 12 - Flower plant chance + * + * 13 - Territory + */ + /* CONSTRUCTOR */ + public BeeGenome(NBTTagCompound nbttagcompound) { + super(nbttagcompound); + } + + public BeeGenome(IChromosome[] chromosomes) { + super(chromosomes); + } + + // / INFORMATION RETRIEVAL + @Override + public IAlleleBeeSpecies getPrimary() { + return (IAlleleBeeSpecies) getActiveAllele(EnumBeeChromosome.SPECIES.ordinal()); + } + + @Override + public IAlleleBeeSpecies getSecondary() { + return (IAlleleBeeSpecies) getInactiveAllele(EnumBeeChromosome.SPECIES.ordinal()); + } + + @Override + public float getSpeed() { + return ((IAlleleFloat) getActiveAllele(EnumBeeChromosome.SPEED.ordinal())).getValue(); + } + + @Override + public int getLifespan() { + return ((IAlleleInteger) getActiveAllele(EnumBeeChromosome.LIFESPAN.ordinal())).getValue(); + } + + @Override + public int getFertility() { + return ((IAlleleInteger) getActiveAllele(EnumBeeChromosome.FERTILITY.ordinal())).getValue(); + } + + @Override + public EnumTolerance getToleranceTemp() { + return ((AlleleTolerance) getActiveAllele(EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal())).getValue(); + } + + @Override + public boolean getNocturnal() { + return ((AlleleBoolean) getActiveAllele(EnumBeeChromosome.NOCTURNAL.ordinal())).getValue(); + } + + @Override + public EnumTolerance getToleranceHumid() { + return ((AlleleTolerance) getActiveAllele(EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal())).getValue(); + } + + @Override + public boolean getTolerantFlyer() { + return ((AlleleBoolean) getActiveAllele(EnumBeeChromosome.TOLERANT_FLYER.ordinal())).getValue(); + } + + @Override + public boolean getCaveDwelling() { + return ((AlleleBoolean) getActiveAllele(EnumBeeChromosome.CAVE_DWELLING.ordinal())).getValue(); + } + + @Override + public IFlowerProvider getFlowerProvider() { + return ((IAlleleFlowers) getActiveAllele(EnumBeeChromosome.FLOWER_PROVIDER.ordinal())).getProvider(); + } + + @Override + public int getFlowering() { + return ((IAlleleInteger) getActiveAllele(EnumBeeChromosome.FLOWERING.ordinal())).getValue(); + } + + @Override + public int[] getTerritory() { + Vect area = ((AlleleArea) getActiveAllele(EnumBeeChromosome.TERRITORY.ordinal())).getArea(); + return new int[] { area.x, area.y, area.z }; + } + + @Override + public IAlleleBeeEffect getEffect() { + return (IAlleleBeeEffect) getActiveAllele(EnumBeeChromosome.EFFECT.ordinal()); + } + + @Override + public ISpeciesRoot getSpeciesRoot() { + return PluginApiculture.beeInterface; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/BeeHelper.java b/forestry_common/apiculture/forestry/apiculture/genetics/BeeHelper.java new file mode 100755 index 000000000..25a41fed1 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/BeeHelper.java @@ -0,0 +1,331 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map.Entry; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import cpw.mods.fml.common.FMLCommonHandler; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IAlvearyComponent; +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeeMutation; +import forestry.api.apiculture.IBeeRoot; +import forestry.api.apiculture.IBeekeepingLogic; +import forestry.api.apiculture.IBeekeepingMode; +import forestry.api.core.IStructureLogic; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.apiculture.BeekeepingLogic; +import forestry.apiculture.gadgets.StructureLogicAlveary; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.SpeciesRoot; +import forestry.plugins.PluginApiculture; + +public class BeeHelper extends SpeciesRoot implements IBeeRoot { + + public static int beeSpeciesCount = -1; + public static final String UID = "rootBees"; + + @Override + public String getUID() { + return UID; + } + + @Override + public Class getMemberClass() { + return IBee.class; + } + + @Override + public int getSpeciesCount() { + if (beeSpeciesCount < 0) { + beeSpeciesCount = 0; + Iterator > it = AlleleManager.alleleRegistry.getRegisteredAlleles().entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + if (entry.getValue() instanceof IAlleleBeeSpecies) + if (((IAlleleBeeSpecies) entry.getValue()).isCounted()) + beeSpeciesCount++; + } + } + + return beeSpeciesCount; + } + + @Override + public boolean isMember(ItemStack stack) { + return getType(stack) != EnumBeeType.NONE; + } + + @Override + public boolean isMember(ItemStack stack, int type) { + return getType(stack).ordinal() == type; + } + + @Override + public boolean isMember(IIndividual individual) { + return individual instanceof IBee; + } + + @Override + public ItemStack getMemberStack(IIndividual bee, int type) { + if (!isMember(bee)) + return null; + + Item beeItem = null; + switch (EnumBeeType.VALUES[type]) { + case QUEEN: + beeItem = ForestryItem.beeQueenGE.item(); + break; + case PRINCESS: + beeItem = ForestryItem.beePrincessGE.item(); + break; + case DRONE: + beeItem = ForestryItem.beeDroneGE.item(); + break; + case LARVAE: + beeItem = ForestryItem.beeLarvaeGE.item(); + break; + default: + throw new RuntimeException("Cannot instantiate a bee of type " + type); + + } + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + bee.writeToNBT(nbttagcompound); + ItemStack beeStack = new ItemStack(beeItem); + beeStack.setTagCompound(nbttagcompound); + return beeStack; + } + + @Override + public EnumBeeType getType(ItemStack stack) { + if (stack == null) + return EnumBeeType.NONE; + + if (ForestryItem.beeDroneGE.isItemEqual(stack)) + return EnumBeeType.DRONE; + else if (ForestryItem.beePrincessGE.isItemEqual(stack)) + return EnumBeeType.PRINCESS; + else if (ForestryItem.beeQueenGE.isItemEqual(stack)) + return EnumBeeType.QUEEN; + else if (ForestryItem.beeLarvaeGE.isItemEqual(stack)) + return EnumBeeType.LARVAE; + + return EnumBeeType.NONE; + } + + @Override + public boolean isDrone(ItemStack stack) { + return getType(stack) == EnumBeeType.DRONE; + } + + @Override + public boolean isMated(ItemStack stack) { + if (getType(stack) != EnumBeeType.QUEEN) + return false; + + IBee bee = getMember(stack); + return bee.getMate() != null; + } + + @Override + public IBee getMember(ItemStack stack) { + if (!ForestryItem.beeQueenGE.isItemEqual(stack) && !ForestryItem.beePrincessGE.isItemEqual(stack) + && !ForestryItem.beeDroneGE.isItemEqual(stack) && !ForestryItem.beeLarvaeGE.isItemEqual(stack)) + return null; + + return new Bee(stack.getTagCompound()); + } + + @Override + public IBee getMember(NBTTagCompound compound) { + return new Bee(compound); + } + + @Override + public IBee getBee(World world, IBeeGenome genome) { + return new Bee(world, genome); + } + + @Override + public IBee getBee(World world, IBeeGenome genome, IBee mate) { + return new Bee(world, genome, mate); + } + + /* GENOME CONVERSIONS */ + @Override + public IBeeGenome templateAsGenome(IAllele[] template) { + return new BeeGenome(templateAsChromosomes(template)); + } + + @Override + public IBeeGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive) { + return new BeeGenome(templateAsChromosomes(templateActive, templateInactive)); + } + + @Override + public IBee templateAsIndividual(IAllele[] template) { + return new Bee(templateAsGenome(template)); + } + + @Override + public IBee templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive) { + return new Bee(templateAsGenome(templateActive, templateInactive)); + } + + /* TEMPLATES */ + public static ArrayList beeTemplates = new ArrayList(); + + @Override + public ArrayList getIndividualTemplates() { + return beeTemplates; + } + + @Override + public void registerTemplate(String identifier, IAllele[] template) { + beeTemplates.add(new Bee(PluginApiculture.beeInterface.templateAsGenome(template))); + speciesTemplates.put(identifier, template); + } + + @Override + public IAllele[] getDefaultTemplate() { + return BeeTemplates.getDefaultTemplate(); + } + + /* MUTATIONS */ + /** + * List of possible mutations on species alleles. + */ + private static ArrayList beeMutations = new ArrayList(); + + @Override + public Collection getMutations(boolean shuffle) { + if (shuffle) + Collections.shuffle(beeMutations); + return beeMutations; + } + + @Override + public void registerMutation(IMutation mutation) { + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getTemplate()[0].getUID())) + return; + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getAllele0().getUID())) + return; + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getAllele1().getUID())) + return; + + beeMutations.add((IBeeMutation) mutation); + } + + /* BREEDING MODES */ + ArrayList beekeepingModes = new ArrayList(); + public static IBeekeepingMode activeBeekeepingMode; + + @Override + public void resetBeekeepingMode() { + activeBeekeepingMode = null; + } + + @Override + public ArrayList getBeekeepingModes() { + return this.beekeepingModes; + } + + @Override + public IBeekeepingMode getBeekeepingMode(World world) { + if (activeBeekeepingMode != null) + return activeBeekeepingMode; + + // No beekeeping mode yet, get it. + IApiaristTracker tracker = getBreedingTracker(world, "__COMMON_"); + String mode = tracker.getModeName(); + if (mode == null || mode.isEmpty()) + mode = PluginApiculture.beekeepingMode; + + setBeekeepingMode(world, mode); + FMLCommonHandler.instance().getFMLLogger().debug("Set beekeeping mode for a world to " + mode); + + return activeBeekeepingMode; + } + + @Override + public void registerBeekeepingMode(IBeekeepingMode mode) { + beekeepingModes.add(mode); + } + + @Override + public void setBeekeepingMode(World world, String name) { + activeBeekeepingMode = getBeekeepingMode(name); + getBreedingTracker(world, "__COMMON_").setModeName(name); + } + + @Override + public IBeekeepingMode getBeekeepingMode(String name) { + for (IBeekeepingMode mode : beekeepingModes) { + if (mode.getName().equals(name) || mode.getName().equals(name.toLowerCase(Locale.ENGLISH))) + return mode; + } + + FMLCommonHandler.instance().getFMLLogger().debug("Failed to find a beekeeping mode called '%s', reverting to fallback."); + return beekeepingModes.get(0); + } + + @Override + public IApiaristTracker getBreedingTracker(World world, String player) { + String filename = "ApiaristTracker." + player; + ApiaristTracker tracker = (ApiaristTracker) world.loadItemData(ApiaristTracker.class, filename); + + // Create a tracker if there is none yet. + if (tracker == null) { + tracker = new ApiaristTracker(filename, player); + world.setItemData(filename, tracker); + } + + return tracker; + } + + @Override + public IBeekeepingLogic createBeekeepingLogic(IBeeHousing housing) { + return new BeekeepingLogic(housing); + } + + @Override + public IStructureLogic createAlvearyStructureLogic(IAlvearyComponent structure) { + return new StructureLogicAlveary(structure); + } + + @Override + public IChromosomeType[] getKaryotype() { + return EnumBeeChromosome.values(); + } + + @Override + public IChromosomeType getKaryotypeKey() { + return EnumBeeChromosome.SPECIES; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/BeeMutation.java b/forestry_common/apiculture/forestry/apiculture/genetics/BeeMutation.java new file mode 100755 index 000000000..c97da6d4b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/BeeMutation.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.ArrayList; + +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeeMutation; +import forestry.api.apiculture.IBeeRoot; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; +import forestry.core.genetics.Mutation; +import forestry.plugins.PluginApiculture; + +public class BeeMutation extends Mutation implements IBeeMutation { + + private final IBeeRoot root; + + boolean requiresDay = false; + boolean requiresNight = false; + + private final ArrayList restrictBiomeTypes = new ArrayList(); + private boolean strictBiomeCheck = false; + + public BeeMutation(IAllele allele0, IAllele allele1, IAllele[] template, int chance) { + super(allele0, allele1, template, chance); + + root = (IBeeRoot)AlleleManager.alleleRegistry.getSpeciesRoot("rootBees"); + PluginApiculture.beeInterface.registerMutation(this); + } + + @Override + public IBeeRoot getRoot() { + return root; + } + + public BeeMutation enableStrictBiomeCheck() { + strictBiomeCheck = true; + return this; + } + + public BeeMutation restrictBiomeType(BiomeDictionary.Type type) { + restrictBiomeTypes.add(type); + specialConditions.add(String.format("Is restricted to %s-like environments.", type.toString())); + return this; + } + + public BeeMutation requireDay() { + requiresDay = true; + requiresNight = false; + specialConditions.add("Can only occur during the day."); + return this; + } + + public BeeMutation requireNight() { + requiresDay = false; + requiresNight = true; + specialConditions.add("Can only occur during the night."); + return this; + } + + @Override + public float getChance(IBeeHousing housing, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1) { + + World world = housing.getWorld(); + if (requiresDay && !world.isDaytime()) + return 0; + + if (requiresNight && world.isDaytime()) + return 0; + + // Skip if we are restricted by biomes and this one does not match. + if (restrictBiomeTypes.size() > 0) { + boolean noneMatched = true; + + BiomeGenBase biome = BiomeGenBase.getBiome(housing.getBiomeId()); + if(strictBiomeCheck) { + BiomeDictionary.Type[] types = BiomeDictionary.getTypesForBiome(biome); + if(types.length == 1 && restrictBiomeTypes.contains(types[0])) + noneMatched = false; + } else { + for(BiomeDictionary.Type type : restrictBiomeTypes) { + if(BiomeDictionary.isBiomeOfType(biome, type)) { + noneMatched = false; + break; + } + } + } + + if (noneMatched) + return 0; + } + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(housing.getXCoord(), housing.getZCoord()); + if (biome.temperature < minTemperature || biome.temperature > maxTemperature) + return 0; + if (biome.rainfall < minRainfall || biome.rainfall > maxRainfall) + return 0; + + float processedChance = chance * housing.getMutationModifier((IBeeGenome) genome0, (IBeeGenome) genome1, 1f) + * PluginApiculture.beeInterface.getBeekeepingMode(world).getMutationModifier((IBeeGenome) genome0, (IBeeGenome) genome1, 1f); + if(processedChance <= 0) + return 0; + + if (this.allele0.getUID().equals(allele0.getUID()) && this.allele1.getUID().equals(allele1.getUID())) + return processedChance; + if (this.allele1.getUID().equals(allele0.getUID()) && this.allele0.getUID().equals(allele1.getUID())) + return processedChance; + + return 0; + + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/BeeTemplates.java b/forestry_common/apiculture/forestry/apiculture/genetics/BeeTemplates.java new file mode 100755 index 000000000..0c5fce2a0 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/BeeTemplates.java @@ -0,0 +1,595 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IMutation; +import forestry.core.genetics.Allele; + +public class BeeTemplates { + + // / MUTATIONS + public static IMutation commonA; + + public static IMutation commonB; + public static IMutation commonC; + + public static IMutation commonD; + public static IMutation commonE; + public static IMutation commonF; + + public static IMutation commonG; + public static IMutation commonH; + public static IMutation commonI; + public static IMutation commonJ; + + public static IMutation commonK; + public static IMutation commonL; + public static IMutation commonM; + public static IMutation commonN; + public static IMutation commonO; + + public static IMutation cultivatedA; + public static IMutation cultivatedB; + public static IMutation cultivatedC; + public static IMutation cultivatedD; + public static IMutation cultivatedE; + public static IMutation cultivatedF; + + public static IMutation nobleA; + public static IMutation majesticA; + public static IMutation imperialA; + + public static IMutation diligentA; + public static IMutation unwearyA; + public static IMutation industriousA; + + public static IMutation heroicA; + + public static IMutation sinisterA; + public static IMutation sinisterB; + public static IMutation fiendishA; + public static IMutation fiendishB; + public static IMutation fiendishC; + public static IMutation demonicA; + + // Austere branch + public static IMutation frugalA; + public static IMutation frugalB; + public static IMutation austereA; + + // Tropical branch + public static IMutation exoticA; + public static IMutation edenicA; + + // Wintry branch + public static IMutation icyA; + public static IMutation glacialA; + + // Festive branch + public static IMutation leporineA; + public static IMutation merryA; + public static IMutation tipsyA; + public static IMutation trickyA; + + // Agrarian branch + public static IMutation ruralA; + + // Monastic branch + public static IMutation secludedA; + public static IMutation hermiticA; + + // End branch + public static IMutation spectralA; + public static IMutation phantasmalA; + + public static IMutation vindictiveA; + + public static IMutation vengefulA; + public static IMutation vengefulB; + public static IMutation avengingA; + + public static IAllele[] getDefaultTemplate() { + IAllele[] alleles = new IAllele[EnumBeeChromosome.values().length]; + + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesForest; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlowest; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShorter; + alleles[EnumBeeChromosome.FERTILITY.ordinal()] = Allele.fertilityNormal; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceNone; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolFalse; + alleles[EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceNone; + alleles[EnumBeeChromosome.TOLERANT_FLYER.ordinal()] = Allele.boolFalse; + alleles[EnumBeeChromosome.CAVE_DWELLING.ordinal()] = Allele.boolFalse; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersVanilla; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringSlowest; + alleles[EnumBeeChromosome.TERRITORY.ordinal()] = Allele.territoryDefault; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectNone; + + return alleles; + } + + // / COMMON BRANCH + + public static IAllele[] getForestTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringSlower; + alleles[EnumBeeChromosome.FERTILITY.ordinal()] = Allele.fertilityHigh; + return alleles; + } + + public static IAllele[] getForestRainResistTemplate() { + IAllele[] alleles = getForestTemplate(); + alleles[EnumBeeChromosome.TOLERANT_FLYER.ordinal()] = Allele.boolTrue; + return alleles; + } + + public static IAllele[] getMeadowsTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesMeadows; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringSlower; + return alleles; + } + + public static IAllele[] getCommonTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesCommon; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + return alleles; + } + + public static IAllele[] getCultivatedTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesCultivated; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedFast; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShortest; + return alleles; + } + + // / NOBLE BRANCH + + public static IAllele[] getNobleTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesNoble; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringSlow; + return alleles; + } + + public static IAllele[] getMajesticTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesMajestic; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedNorm; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShortened; + alleles[EnumBeeChromosome.FERTILITY.ordinal()] = Allele.fertilityMaximum; + return alleles; + } + + public static IAllele[] getImperialTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesImperial; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectBeatific; + return alleles; + } + + // / INDUSTRIOUS BRANCH + + public static IAllele[] getDiligentTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesDiligent; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringSlow; + return alleles; + } + + public static IAllele[] getUnwearyTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesUnweary; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedNorm; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShortened; + return alleles; + } + + public static IAllele[] getIndustriousTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesIndustrious; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringFast; + return alleles; + } + + // / HEROIC BRANCH + + public static IAllele[] getSteadfastTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesSteadfast; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.CAVE_DWELLING.ordinal()] = Allele.boolTrue; + return alleles; + } + + public static IAllele[] getValiantTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesValiant; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlow; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLong; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.CAVE_DWELLING.ordinal()] = Allele.boolTrue; + return alleles; + } + + public static IAllele[] getHeroicTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesHeroic; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlow; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLong; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.CAVE_DWELLING.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectHeroic; + return alleles; + } + + // / INFERNAL BRANCH + + public static IAllele[] getBranchInfernalTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceDown2; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersNether; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringAverage; + return alleles; + } + + public static IAllele[] getSinisterTemplate() { + IAllele[] alleles = getBranchInfernalTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesSinister; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectAggressive; + return alleles; + } + + public static IAllele[] getFiendishTemplate() { + IAllele[] alleles = getBranchInfernalTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesFiendish; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedNorm; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLong; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectAggressive; + return alleles; + } + + public static IAllele[] getDemonicTemplate() { + IAllele[] alleles = getBranchInfernalTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesDemonic; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLonger; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectIgnition; + return alleles; + } + + // / AUSTERE BRANCH + + public static IAllele[] getAustereBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + alleles[EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceUp1; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersCacti; + return alleles; + } + + public static IAllele[] getModestTemplate() { + IAllele[] alleles = getAustereBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesModest; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + return alleles; + } + + public static IAllele[] getFrugalTemplate() { + IAllele[] alleles = getAustereBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesFrugal; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedNorm; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLong; + return alleles; + } + + public static IAllele[] getAustereTemplate() { + IAllele[] alleles = getAustereBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesAustere; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlowest; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLonger; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceDown2; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectCreeper; + return alleles; + } + + // / TROPICAL BRANCH + public static IAllele[] getTropicalBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + alleles[EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceDown1; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersJungle; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectMiasmic; + return alleles; + } + + public static IAllele[] getTropicalTemplate() { + IAllele[] alleles = getTropicalBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesTropical; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + return alleles; + } + + public static IAllele[] getExoticTemplate() { + IAllele[] alleles = getTropicalBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesExotic; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedNorm; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLong; + return alleles; + } + + public static IAllele[] getEdenicTemplate() { + IAllele[] alleles = getTropicalBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesEdenic; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlowest; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLonger; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth2; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectExploration; + return alleles; + } + + // / END BRANCH + public static IAllele[] getEndBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.FERTILITY.ordinal()] = Allele.fertilityLow; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLonger; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceUp1; + alleles[EnumBeeChromosome.TERRITORY.ordinal()] = Allele.territoryLarge; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersEnd; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectMisanthrope; + return alleles; + } + + public static IAllele[] getEnderTemplate() { + IAllele[] alleles = getEndBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesEnded; + return alleles; + } + + public static IAllele[] getSpectralTemplate() { + IAllele[] alleles = getEndBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesSpectral; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectReanimation; + return alleles; + } + + public static IAllele[] getPhantasmalTemplate() { + IAllele[] alleles = getEndBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesPhantasmal; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlowest; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLongest; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectResurrection; + return alleles; + } + + // / FROZEN BRANCH + public static IAllele[] getFrozenBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceUp1; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersSnow; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectGlacial; + return alleles; + } + + public static IAllele[] getWintryTemplate() { + IAllele[] alleles = getFrozenBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesWintry; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + alleles[EnumBeeChromosome.FERTILITY.ordinal()] = Allele.fertilityMaximum; + return alleles; + } + + public static IAllele[] getIcyTemplate() { + IAllele[] alleles = getFrozenBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesIcy; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlow; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + return alleles; + } + + public static IAllele[] getGlacialTemplate() { + IAllele[] alleles = getFrozenBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesGlacial; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + return alleles; + } + + // / VENGEFUL BRANCH + public static IAllele[] getVengefulBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.TERRITORY.ordinal()] = Allele.territoryLargest; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectRadioactive; + return alleles; + } + + public static IAllele[] getVindictiveTemplate() { + IAllele[] alleles = getVengefulBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesVindictive; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + return alleles; + } + + public static IAllele[] getVengefulTemplate() { + IAllele[] alleles = getVengefulBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesVengeful; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedNorm; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLonger; + return alleles; + } + + public static IAllele[] getAvengingTemplate() { + IAllele[] alleles = getVengefulBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesAvenging; + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlowest; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLongest; + return alleles; + } + + // / REDDENED BRANCH + public static IAllele[] getReddenedBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlow; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth2; + alleles[EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + return alleles; + } + + public static IAllele[] getDarkenedTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesDarkened; + return alleles; + } + + public static IAllele[] getReddenedTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesReddened; + return alleles; + } + + public static IAllele[] getOmegaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesOmega; + return alleles; + } + + // / FESTIVE BRANCH + public static IAllele[] getFestiveBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth2; + alleles[EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + return alleles; + } + + public static IAllele[] getLeporineTemplate() { + IAllele[] alleles = getFestiveBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesLeporine; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectFestiveEaster; + return alleles; + } + + public static IAllele[] getMerryTemplate() { + IAllele[] alleles = getFestiveBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesMerry; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectSnowing; + return alleles; + } + + public static IAllele[] getTipsyTemplate() { + IAllele[] alleles = getFestiveBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesTipsy; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectDrunkard; + return alleles; + } + + public static IAllele[] getTrickyTemplate() { + IAllele[] alleles = getFestiveBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesTricky; + alleles[EnumBeeChromosome.NOCTURNAL.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.TOLERANT_FLYER.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersGourd; + return alleles; + } + + // / AGRARIAN BRANCH + public static IAllele[] getAgrarianBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanShorter; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersWheat; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringFaster; + return alleles; + } + + public static IAllele[] getRuralTemplate() { + IAllele[] alleles = getAgrarianBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesRural; + return alleles; + } + + // / BOGGY BRANCH + public static IAllele[] getBoggyBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersMushrooms; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringSlower; + alleles[EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + return alleles; + } + + public static IAllele[] getMarshyTemplate() { + IAllele[] alleles = getBoggyBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesMarshy; + return alleles; + } + + /* MONASTIC BRANCH */ + public static IAllele[] getMonasticBranchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumBeeChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumBeeChromosome.LIFESPAN.ordinal()] = Allele.lifespanLong; + alleles[EnumBeeChromosome.FERTILITY.ordinal()] = Allele.fertilityLow; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringFaster; + alleles[EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + alleles[EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + alleles[EnumBeeChromosome.CAVE_DWELLING.ordinal()] = Allele.boolTrue; + alleles[EnumBeeChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersWheat; + return alleles; + } + + public static IAllele[] getMonasticTemplate() { + IAllele[] alleles = getMonasticBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesMonastic; + return alleles; + } + + public static IAllele[] getSecludedTemplate() { + IAllele[] alleles = getMonasticBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesSecluded; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringFastest; + return alleles; + } + + public static IAllele[] getHermiticTemplate() { + IAllele[] alleles = getMonasticBranchTemplate(); + alleles[EnumBeeChromosome.SPECIES.ordinal()] = Allele.speciesHermitic; + alleles[EnumBeeChromosome.FLOWERING.ordinal()] = Allele.floweringFastest; + alleles[EnumBeeChromosome.EFFECT.ordinal()] = Allele.effectRepulsion; + return alleles; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/BeekeepingMode.java b/forestry_common/apiculture/forestry/apiculture/genetics/BeekeepingMode.java new file mode 100755 index 000000000..a46143578 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/BeekeepingMode.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.ArrayList; +import java.util.Locale; +import java.util.Random; + +import net.minecraft.world.World; + +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeekeepingMode; + +public class BeekeepingMode implements IBeekeepingMode { + + public static IBeekeepingMode easy = new BeekeepingMode("EASY", 2.0f, 1.0f, 1.0f, false, false); + public static IBeekeepingMode normal = new BeekeepingMode("NORMAL", 1.0f, 1.0f, 1.0f, false, true); + public static IBeekeepingMode hard = new BeekeepingMode("HARD", 0.75f, 1.5f, 1.0f, false, true); + public static IBeekeepingMode hardcore = new BeekeepingMode("HARDCORE", 0.5f, 5.0f, 0.8f, true, true); + public static IBeekeepingMode insane = new BeekeepingMode("INSANE", 0.2f, 10.0f, 0.6f, true, true); + + final Random rand; + final String name; + final float mutationModifier; + final float lifespanModifier; + final float speedModifier; + final boolean reducesFertility; + final boolean canFatigue; + + public BeekeepingMode(String name, float mutationModifier, float lifespanModifier, float speedModifier, boolean reducesFertility, boolean canFatigue) { + this.rand = new Random(); + this.name = name; + this.mutationModifier = mutationModifier; + this.lifespanModifier = lifespanModifier; + this.speedModifier = speedModifier; + this.reducesFertility = reducesFertility; + this.canFatigue = canFatigue; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public ArrayList getDescription() { + ArrayList ret = new ArrayList(); + ret.add("beemode." + name.toLowerCase(Locale.ENGLISH) + ".desc"); + return ret; + } + + @Override + public float getWearModifier() { + return 1.0f; + } + + @Override + public float getMutationModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return this.mutationModifier; + } + + @Override + public float getLifespanModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return this.lifespanModifier; + } + + @Override + public float getProductionModifier(IBeeGenome genome, float currentModifier) { + return this.speedModifier; + } + + @Override + public float getTerritoryModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getFloweringModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getGeneticDecay(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public int getFinalFertility(IBee queen, World world, int x, int y, int z) { + int toCreate = queen.getGenome().getFertility(); + + if (reducesFertility) + toCreate = new Random().nextInt(toCreate); + + return toCreate; + } + + @Override + public boolean isFatigued(IBee queen, IBeeHousing housing) { + if (!canFatigue) + return false; + + if (queen.isNatural()) + return false; + + if (queen.getGeneration() > 96 + rand.nextInt(6) + rand.nextInt(6) && + rand.nextFloat() < 0.02f * housing.getGeneticDecay(queen.getGenome(), 1f)) + return true; + + return false; + } + + @Override + public boolean isOverworked(IBee queen, IBeeHousing housing) { + float productionModifier = housing.getProductionModifier(queen.getGenome(), 1f); + if(productionModifier > 16) { + if(housing.getWorld().rand.nextFloat()*100 < 0.01 * ((productionModifier*productionModifier) - 100)) + return true; + } + + return false; + } + + @Override + public boolean isDegenerating(IBee queen, IBee offspring, IBeeHousing housing) { + float mutationModifier = housing.getMutationModifier(queen.getGenome(), queen.getMate(), 1.0f); + if(mutationModifier > 10) { + if(housing.getWorld().rand.nextFloat()*100 < 0.4 * ((mutationModifier*mutationModifier) - 100)) + return true; + } + + return false; + } + + @Override + public boolean isNaturalOffspring(IBee queen) { + if (!queen.isNatural()) + return false; + + return true; + } + + @Override + public boolean mayMultiplyPrincess(IBee queen) { + return true; + } + + @Override + public boolean isSealed() { + return false; + } + + @Override + public boolean isSelfLighted() { + return false; + } + + @Override + public boolean isSunlightSimulated() { + return false; + } + + @Override + public boolean isHellish() { + return false; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/BranchBees.java b/forestry_common/apiculture/forestry/apiculture/genetics/BranchBees.java new file mode 100755 index 000000000..eea9dc5e1 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/BranchBees.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import forestry.core.genetics.Branch; + +public class BranchBees extends Branch { + + public BranchBees(String uid, String scientific) { + super("bees." + uid, scientific); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/HiveDrop.java b/forestry_common/apiculture/forestry/apiculture/genetics/HiveDrop.java new file mode 100755 index 000000000..366bfb00f --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/HiveDrop.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IHiveDrop; +import forestry.api.genetics.IAllele; +import forestry.plugins.PluginApiculture; + +public class HiveDrop implements IHiveDrop { + + private IAllele[] template; + private ArrayList additional = new ArrayList(); + private int chance; + private float ignobleShare = 0.0f; + + public HiveDrop(IAllele[] template, ItemStack[] bonus, int chance) { + this.template = template; + this.chance = chance; + + for (ItemStack stack : bonus) + this.additional.add(stack); + } + + public HiveDrop setIgnobleShare(float share) { + this.ignobleShare = share; + return this; + } + + private IBee createBee(World world) { + IBee bee = PluginApiculture.beeInterface.getBee(world, PluginApiculture.beeInterface.templateAsGenome(template)); + if(world.rand.nextFloat() < ignobleShare) + bee.setIsNatural(false); + return bee; + } + + @Override + public ItemStack getPrincess(World world, int x, int y, int z, int fortune) { + return PluginApiculture.beeInterface.getMemberStack(createBee(world), EnumBeeType.PRINCESS.ordinal()); + } + + @Override + public ArrayList getDrones(World world, int x, int y, int z, int fortune) { + ArrayList ret = new ArrayList(); + ret.add(PluginApiculture.beeInterface.getMemberStack(createBee(world), + EnumBeeType.DRONE.ordinal())); + return ret; + } + + @Override + public ArrayList getAdditional(World world, int x, int y, int z, int fortune) { + ArrayList ret = new ArrayList(); + for (ItemStack stack : additional) + ret.add(stack.copy()); + + return ret; + } + + @Override + public int getChance(World world, int x, int y, int z) { + return chance; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/IJubilanceProvider.java b/forestry_common/apiculture/forestry/apiculture/genetics/IJubilanceProvider.java new file mode 100755 index 000000000..c10e036ae --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/IJubilanceProvider.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; + +public interface IJubilanceProvider { + boolean isJubilant(IAlleleBeeSpecies species, IBeeGenome genome, IBeeHousing housing); +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceDefault.java b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceDefault.java new file mode 100755 index 000000000..714fe947a --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceDefault.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.core.utils.Vect; + +public class JubilanceDefault implements IJubilanceProvider { + + @Override + public boolean isJubilant(IAlleleBeeSpecies species, IBeeGenome genome, IBeeHousing housing) { + BiomeGenBase biome = BiomeGenBase.getBiome(housing.getBiomeId()); + + if (EnumTemperature.getFromValue(biome.temperature) != species.getTemperature() || + EnumHumidity.getFromValue(biome.rainfall) != species.getHumidity()) + return false; + + return true; + } + + protected AxisAlignedBB getBounding(IBeeGenome genome, IBeeHousing housing, float modifier) { + int[] areaAr = genome.getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(modifier); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + Vect min = new Vect(housing.getXCoord() + offset.x, housing.getYCoord() + offset.y, housing.getZCoord() + offset.z); + Vect max = new Vect(housing.getXCoord() + offset.x + area.x, housing.getYCoord() + offset.y + area.y, housing.getZCoord() + offset.z + area.z); + + return AxisAlignedBB.getAABBPool().getAABB(min.x, min.y, min.z, max.x, max.y, max.z); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceNone.java b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceNone.java new file mode 100755 index 000000000..3419bd953 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceNone.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; + +public class JubilanceNone implements IJubilanceProvider { + + @Override + public boolean isJubilant(IAlleleBeeSpecies species, IBeeGenome genome, IBeeHousing housing) { + return false; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceProviderHermit.java b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceProviderHermit.java new file mode 100755 index 000000000..ba15cea19 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceProviderHermit.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.List; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.util.AxisAlignedBB; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; + +/** + * Hermits will not produce if there are any other living creatures nearby. + */ +public class JubilanceProviderHermit extends JubilanceDefault { + + @Override + public boolean isJubilant(IAlleleBeeSpecies species, IBeeGenome genome, IBeeHousing housing) { + AxisAlignedBB bounding = this.getBounding(genome, housing, 1.0f); + + @SuppressWarnings("rawtypes") + List list = housing.getWorld().getEntitiesWithinAABB(EntityLiving.class, bounding); + if (list.size() > 0) + return false; + + return true; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceReqRes.java b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceReqRes.java new file mode 100755 index 000000000..4f2ee818e --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/JubilanceReqRes.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.core.utils.StackUtils; + +public class JubilanceReqRes implements IJubilanceProvider { + + private final ItemStack blockRequired; + + public JubilanceReqRes(ItemStack blockRequired) { + this.blockRequired = blockRequired; + } + + @Override + public boolean isJubilant(IAlleleBeeSpecies species, IBeeGenome genome, IBeeHousing housing) { + + if (blockRequired == null) + return true; + + Block block = housing.getWorld().getBlock(housing.getXCoord(), housing.getYCoord() - 1, housing.getZCoord()); + int meta = housing.getWorld().getBlockMetadata(housing.getXCoord(), housing.getYCoord() - 1, housing.getZCoord()); + if (StackUtils.equals(block, blockRequired) && meta == blockRequired.getItemDamage()) + return true; + else + return false; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/MutationEMC.java b/forestry_common/apiculture/forestry/apiculture/genetics/MutationEMC.java new file mode 100755 index 000000000..fa3ddaddc --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/MutationEMC.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.lang.reflect.Field; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Vect; + +public class MutationEMC extends MutationReqRes { + + int emcRequired = 0; + Class condenserClass; + Field emcField; + + public MutationEMC(IAllele allele0, IAllele allele1, IAllele[] template, int chance, ItemStack blockRequired, Class condenserClass, Field emcField, + int emcRequired) { + super(allele0, allele1, template, chance, blockRequired); + + this.condenserClass = condenserClass; + this.emcField = emcField; + this.emcRequired = emcRequired; + } + + @Override + public float getChance(IBeeHousing housing, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1) { + float chance = super.getChance(housing, allele0, allele1, genome0, genome1); + + // If we don't have any chance, return at once. + if (chance <= 0) + return 0; + + if (emcRequired <= 0) + return chance; + + World world = housing.getWorld(); + + Vect[] possibleTargets = new Vect[] { new Vect(housing.getXCoord() + 1, housing.getYCoord(), housing.getZCoord()), + new Vect(housing.getXCoord() - 1, housing.getYCoord(), housing.getZCoord()), + new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord() + 1), + new Vect(housing.getXCoord(), housing.getYCoord(), housing.getZCoord() - 1) }; + + for (Vect target : possibleTargets) { + if (!world.blockExists(target.x, target.y, target.z)) + continue; + + TileEntity entity = world.getTileEntity(target.x, target.y, target.z); + if (entity == null) + continue; + + if (!condenserClass.isInstance(entity)) { + Proxies.log.warning("Did not find a relay at " + target.toString()); + continue; + } + + int emc = 0; + try { + emc = emcField.getInt(entity); + } catch (Exception ex) { + Proxies.log.warning("Failed to fetch EMC information."); + } + + if (emc < emcRequired * 80) + continue; + + boolean removedEMC = false; + try { + emcField.set(entity, emc - (emcRequired * 80)); + removedEMC = true; + } catch (Exception ex) { + Proxies.log.warning("Failed to set EMC information."); + } + + if (removedEMC) + return chance; + + } + + return 0; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/MutationReqRes.java b/forestry_common/apiculture/forestry/apiculture/genetics/MutationReqRes.java new file mode 100755 index 000000000..19e4aa3ec --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/MutationReqRes.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; +import forestry.core.utils.StackUtils; + +public class MutationReqRes extends BeeMutation { + + private final ItemStack blockRequired; + + public MutationReqRes(IAllele allele0, IAllele allele1, IAllele[] template, int chance, ItemStack blockRequired) { + super(allele0, allele1, template, chance); + this.blockRequired = blockRequired; + } + + @Override + public float getChance(IBeeHousing housing, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1) { + float chance = super.getChance(housing, allele0, allele1, genome0, genome1); + + // If we have no chance anyway, we don't need to check. + if (chance <= 0) + return 0; + + World world = housing.getWorld(); + if (blockRequired == null) + return chance; + + Block block = world.getBlock(housing.getXCoord(), housing.getYCoord() - 1, housing.getZCoord()); + int meta = world.getBlockMetadata(housing.getXCoord(), housing.getYCoord() - 1, housing.getZCoord()); + if (StackUtils.equals(block, blockRequired) && meta == blockRequired.getItemDamage()) + return chance; + else + return 0; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/genetics/MutationTimeLimited.java b/forestry_common/apiculture/forestry/apiculture/genetics/MutationTimeLimited.java new file mode 100755 index 000000000..909e65c7a --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/genetics/MutationTimeLimited.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.genetics; + +import java.util.Calendar; + +import forestry.api.apiculture.IBeeHousing; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; + +public class MutationTimeLimited extends BeeMutation { + + /** + * Fed up with Date and Calendar and their shinenigans + */ + public static class DayMonth { + + public int day; + public int month; + + public DayMonth() { + this.day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH); + this.month = Calendar.getInstance().get(Calendar.MONTH) + 1; + } + + public DayMonth(int day, int month) { + this.day = day; + this.month = month; + } + + public boolean between(DayMonth start, DayMonth end) { + if (equals(start) || equals(end)) + return true; + if (start.month > end.month) + return after(start) || before(end); + return after(start) && before(end); + } + + public boolean before(DayMonth other) { + + if (other.month > this.month) + return true; + + if (other.month < this.month) + return false; + + return this.day < other.day; + } + + public boolean after(DayMonth other) { + + if (other.month < this.month) + return true; + + if (other.month > this.month) + return false; + + return this.day > other.day; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 89 * hash + this.day; + hash = 89 * hash + this.month; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final DayMonth other = (DayMonth) obj; + if (this.day != other.day) + return false; + if (this.month != other.month) + return false; + return true; + } + + @Override + public String toString() { + return day + "." + month; + } + } + DayMonth start; + DayMonth end; + + public MutationTimeLimited(IAllele allele0, IAllele allele1, IAllele[] template, int chance, DayMonth start) { + this(allele0, allele1, template, chance, start, null); + } + + public MutationTimeLimited(IAllele allele0, IAllele allele1, IAllele[] template, int chance, DayMonth start, DayMonth end) { + super(allele0, allele1, template, chance); + this.start = start; + this.end = end; + } + + @Override + public float getChance(IBeeHousing housing, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1) { + float chance = super.getChance(housing, allele0, allele1, genome0, genome1); + + if (chance == 0) + return 0; + + if (start == null && end == null) + return chance; + + DayMonth now = new DayMonth(); + + // If we are equal to start day, return chance. + if (Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == start.day && Calendar.getInstance().get(Calendar.MONTH) + 1 == start.month) + return chance; + + // Still here but not time span? No mutation! + if (end == null) + return 0; + + // Equal to end date, return chance. + if (Calendar.getInstance().get(Calendar.DAY_OF_MONTH) == end.day && Calendar.getInstance().get(Calendar.MONTH) + 1 == end.month) + return chance; + + // Still a chance we are in between + if (now.between(start, end)) + return chance; + + // Now we finally failed. + return 0; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlveary.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlveary.java new file mode 100755 index 000000000..1d126c935 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlveary.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.apiculture.gadgets.TileAlvearyPlain; +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotCustom; + +public class ContainerAlveary extends ContainerForestry { + + private TileAlvearyPlain tile; + + public ContainerAlveary(InventoryPlayer player, TileAlvearyPlain tile) { + super(tile); + + this.tile = tile; + tile.sendNetworkUpdate(); + + // Queen/Princess + this.addSlot(new SlotCustom(tile, TileAlvearyPlain.SLOT_QUEEN, 29, 39, new Object[] { ForestryItem.beePrincessGE, ForestryItem.beeQueenGE })); + + // Drone + this.addSlot(new SlotCustom(tile, TileAlvearyPlain.SLOT_DRONE, 29, 65, new Object[] { ForestryItem.beeDroneGE })); + + // Product Inventory + this.addSlot(new SlotClosed(tile, 2, 116, 52)); + this.addSlot(new SlotClosed(tile, 3, 137, 39)); + this.addSlot(new SlotClosed(tile, 4, 137, 65)); + this.addSlot(new SlotClosed(tile, 5, 116, 78)); + this.addSlot(new SlotClosed(tile, 6, 95, 65)); + this.addSlot(new SlotClosed(tile, 7, 95, 39)); + this.addSlot(new SlotClosed(tile, 8, 116, 26)); + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 108 + i * 18)); + // Player hotbar + for (int i = 0; i < 9; i++) + addSlot(new Slot(player, i, 8 + i * 18, 166)); + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearyHygroregulator.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearyHygroregulator.java new file mode 100755 index 000000000..fb17e4366 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearyHygroregulator.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +import forestry.apiculture.gadgets.TileAlvearyHygroregulator; +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotLiquidContainer; + +public class ContainerAlvearyHygroregulator extends ContainerLiquidTanks { + + TileAlvearyHygroregulator tile; + + public ContainerAlvearyHygroregulator(IInventory inventory, TileAlvearyHygroregulator tile) { + super(inventory, tile); + + this.tile = tile; + this.addSlot(new SlotLiquidContainer(tile, 0, 56, 38)); + + for (int i = 0; i < 3; ++i) + for (int var4 = 0; var4 < 9; ++var4) + this.addSlot(new Slot(inventory, var4 + i * 9 + 9, 8 + var4 * 18, 84 + i * 18)); + + for (int i = 0; i < 9; ++i) + this.addSlot(new Slot(inventory, i, 8 + i * 18, 142)); + + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySieve.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySieve.java new file mode 100755 index 000000000..b5dfdb6d0 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySieve.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +import forestry.apiculture.gadgets.TileAlvearySieve; +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotCustom; + +public class ContainerAlvearySieve extends ContainerForestry { + + TileAlvearySieve tile; + + public ContainerAlvearySieve(InventoryPlayer player, TileAlvearySieve tile) { + super(tile.getInternalInventory()); + + this.tile = tile; + IInventory inventory = tile.getInternalInventory(); + + addSlot(new SlotCustom(inventory, 0, 94, 52, new Object[0]).setCrafter(tile)); + addSlot(new SlotCustom(inventory, 1, 115, 39, new Object[0]).setCrafter(tile)); + addSlot(new SlotCustom(inventory, 2, 73, 39, new Object[0]).setCrafter(tile)); + addSlot(new SlotCustom(inventory, 3, 94, 26, new Object[0]).setCrafter(tile)); + + addSlot(new SlotCustom(inventory, TileAlvearySieve.SLOT_SIEVE, 43, 39, ForestryItem.craftingMaterial.getItemStack(1, 3)).setCrafter(tile)); + + // Player inventory + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 9; j++) { + addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 87 + i * 18)); + } + } + // Player hotbar + for (int i = 0; i < 9; i++) { + addSlot(new Slot(player, i, 8 + i * 18, 145)); + } + + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return tile.isUseableByPlayer(entityplayer); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySwarmer.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySwarmer.java new file mode 100755 index 000000000..5ff95040f --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerAlvearySwarmer.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +import forestry.api.apiculture.BeeManager; +import forestry.apiculture.gadgets.TileAlvearySwarmer; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotCustom; + +public class ContainerAlvearySwarmer extends ContainerForestry { + + public ContainerAlvearySwarmer(InventoryPlayer player, TileAlvearySwarmer tile) { + super(tile); + + this.addSlot(new SlotCustom(tile, 0, 79, 52, getInducerItems())); + this.addSlot(new SlotCustom(tile, 1, 100, 39, getInducerItems())); + this.addSlot(new SlotCustom(tile, 2, 58, 39, getInducerItems())); + this.addSlot(new SlotCustom(tile, 3, 79, 26, getInducerItems())); + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 87 + i * 18)); + // Player hotbar + for (int i = 0; i < 9; i++) + addSlot(new Slot(player, i, 8 + i * 18, 145)); + + } + + private Object[] getInducerItems() { + return BeeManager.inducers.keySet().toArray(new Object[0]); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerApiary.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerApiary.java new file mode 100755 index 000000000..0b5b65ba5 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerApiary.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +import forestry.api.apiculture.IHiveFrame; +import forestry.apiculture.gadgets.TileBeehouse; +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.utils.Utils; + +public class ContainerApiary extends ContainerForestry { + + private final TileBeehouse tile; + + public ContainerApiary(InventoryPlayer player, TileBeehouse tile, boolean hasFrames) { + super(tile.getInternalInventory()); + + this.tile = tile; + tile.sendNetworkUpdate(); + IInventory inventory = tile.getInternalInventory(); + + // Queen/Princess + this.addSlot(new SlotCustom(inventory, TileBeehouse.SLOT_QUEEN, 29, 39, ForestryItem.beePrincessGE, ForestryItem.beeQueenGE)); + + // Drone + this.addSlot(new SlotCustom(inventory, TileBeehouse.SLOT_DRONE, 29, 65, ForestryItem.beeDroneGE)); + + // Frames + if (hasFrames) { + this.addSlot(new SlotCustom(inventory, TileBeehouse.SLOT_FRAMES_1, 66, 23, IHiveFrame.class)); + this.addSlot(new SlotCustom(inventory, TileBeehouse.SLOT_FRAMES_1 + 1, 66, 52, IHiveFrame.class)); + this.addSlot(new SlotCustom(inventory, TileBeehouse.SLOT_FRAMES_1 + 2, 66, 81, IHiveFrame.class)); + } + + // Product Inventory + this.addSlot(new SlotClosed(inventory, 2, 116, 52)); + this.addSlot(new SlotClosed(inventory, 3, 137, 39)); + this.addSlot(new SlotClosed(inventory, 4, 137, 65)); + this.addSlot(new SlotClosed(inventory, 5, 116, 78)); + this.addSlot(new SlotClosed(inventory, 6, 95, 65)); + this.addSlot(new SlotClosed(inventory, 7, 95, 39)); + this.addSlot(new SlotClosed(inventory, 8, 116, 26)); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) { + for (int l1 = 0; l1 < 9; l1++) { + addSlot(new Slot(player, l1 + i1 * 9 + 9, 8 + l1 * 18, 108 + i1 * 18)); + } + } + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) { + addSlot(new Slot(player, j1, 8 + j1 * 18, 166)); + } + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + for (int i = 0; i < crafters.size(); i++) { + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return Utils.isUseableByPlayer(entityplayer, tile, tile.getWorld(), tile.xCoord, tile.yCoord, tile.zCoord); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerBeealyzer.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerBeealyzer.java new file mode 100755 index 000000000..3c0461082 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerBeealyzer.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +import forestry.apiculture.items.ItemBeeGE; +import forestry.apiculture.items.ItemBeealyzer.BeealyzerInventory; +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.proxy.Proxies; + +public class ContainerBeealyzer extends ContainerItemInventory { + + BeealyzerInventory inventory; + + public ContainerBeealyzer(InventoryPlayer inventoryplayer, BeealyzerInventory inventory) { + super(inventory, inventoryplayer.player); + + this.inventory = inventory; + + // Energy + this.addSlot(new SlotCustom(inventory, BeealyzerInventory.SLOT_ENERGY, 172, 8, new Object[] { ForestryItem.honeydew, ForestryItem.honeyDrop })); + + // Bee to analyze + this.addSlot(new SlotCustom(inventory, BeealyzerInventory.SLOT_SPECIMEN, 172, 26, new Object[] { ItemBeeGE.class })); + + // Analyzed bee + this.addSlot(new SlotCustom(inventory, BeealyzerInventory.SLOT_ANALYZE_1, 172, 57, new Object[] { ItemBeeGE.class })); + this.addSlot(new SlotCustom(inventory, BeealyzerInventory.SLOT_ANALYZE_2, 172, 75, new Object[] { ItemBeeGE.class })); + this.addSlot(new SlotCustom(inventory, BeealyzerInventory.SLOT_ANALYZE_3, 172, 93, new Object[] { ItemBeeGE.class })); + this.addSlot(new SlotCustom(inventory, BeealyzerInventory.SLOT_ANALYZE_4, 172, 111, new Object[] { ItemBeeGE.class })); + this.addSlot(new SlotCustom(inventory, BeealyzerInventory.SLOT_ANALYZE_5, 172, 129, new Object[] { ItemBeeGE.class })); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSecuredSlot(inventoryplayer, l1 + i1 * 9 + 9, 18 + l1 * 18, 156 + i1 * 18); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSecuredSlot(inventoryplayer, j1, 18 + j1 * 18, 214); + + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(entityplayer.worldObj)) + return; + + // Last slot is the energy slot, so we don't save that one. + for (int i = 0; i < inventory.getSizeInventory(); i++) { + if (i == BeealyzerInventory.SLOT_ENERGY) + continue; + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + Proxies.common.dropItemPlayer(entityplayer, stack); + inventory.setInventorySlotContents(i, null); + } + + inventory.onGuiSaved(entityplayer); + + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + return true; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerHabitatLocator.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerHabitatLocator.java new file mode 100755 index 000000000..9c7e31854 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerHabitatLocator.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +import forestry.apiculture.items.ItemBeeGE; +import forestry.apiculture.items.ItemBiomefinder; +import forestry.apiculture.items.ItemBiomefinder.BiomefinderInventory; +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.proxy.Proxies; + +public class ContainerHabitatLocator extends ContainerItemInventory { + + public BiomefinderInventory inventory; + + public ContainerHabitatLocator(InventoryPlayer inventoryplayer, BiomefinderInventory inventory) { + super(inventory, inventoryplayer.player); + + this.inventory = inventory; + + // Energy + this.addSlot(new SlotCustom(inventory, 2, 152, 8, new Object[] { ForestryItem.honeydew, ForestryItem.honeyDrop })); + + // Bee to analyze + this.addSlot(new SlotCustom(inventory, 0, 152, 32, new Object[] { ItemBeeGE.class })); + // Analyzed bee + this.addSlot(new SlotCustom(inventory, 1, 152, 75, new Object[] { ItemBeeGE.class })); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSecuredSlot(inventoryplayer, l1 + i1 * 9 + 9, 8 + l1 * 18, 102 + i1 * 18); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSecuredSlot(inventoryplayer, j1, 8 + j1 * 18, 160); + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(entityplayer.worldObj)) + return; + + ((ItemBiomefinder) ForestryItem.biomeFinder.item()).startBiomeSearch(entityplayer.worldObj, entityplayer, inventory.biomesToSearch); + + for (int i = 0; i < inventory.getSizeInventory() - 1; i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + Proxies.common.dropItemPlayer(entityplayer, stack); + inventory.setInventorySlotContents(i, null); + } + + inventory.onGuiSaved(entityplayer); + + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + return false; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/ContainerImprinter.java b/forestry_common/apiculture/forestry/apiculture/gui/ContainerImprinter.java new file mode 100755 index 000000000..5d6a9b30d --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/ContainerImprinter.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.apiculture.items.ItemBeeGE; +import forestry.apiculture.items.ItemImprinter.ImprinterInventory; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.IGuiSelectable; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; + +public class ContainerImprinter extends ContainerForestry implements IGuiSelectable { + + public ImprinterInventory inventory; + private boolean isNetSynched = false; + + public ContainerImprinter(InventoryPlayer inventoryplayer, ImprinterInventory inventory) { + super(inventory); + + this.inventory = inventory; + // Input + this.addSlot(new SlotCustom(inventory, 0, 152, 12, new Object[] { ItemBeeGE.class })); + // Output + this.addSlot(new SlotCustom(inventory, 1, 152, 72, new Object[] { ItemBeeGE.class })); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSlot(new Slot(inventoryplayer, l1 + i1 * 9 + 9, 8 + l1 * 18, 103 + i1 * 18)); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSlot(new Slot(inventoryplayer, j1, 8 + j1 * 18, 161)); + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(entityplayer.worldObj)) + return; + + // Drop everything still in there. + for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + Proxies.common.dropItemPlayer(entityplayer, stack); + inventory.setInventorySlotContents(i, null); + } + + } + + public void advanceSelection(int index, World world) { + PacketPayload payload = new PacketPayload(2, 0, 0); + payload.intPayload[0] = index; + payload.intPayload[1] = 0; + sendSelectionChange(payload); + } + + public void regressSelection(int index, World world) { + PacketPayload payload = new PacketPayload(2, 0, 0); + payload.intPayload[0] = index; + payload.intPayload[1] = 1; + sendSelectionChange(payload); + } + + private void sendSelectionChange(PacketPayload payload) { + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + isNetSynched = false; + } + + @Override + public void setSelection(PacketUpdate packet) { + inventory.setPrimaryIndex(packet.payload.intPayload[0]); + inventory.setSecondaryIndex(packet.payload.intPayload[1]); + } + + public void updateContainer(World world) { + if (!isNetSynched && !Proxies.common.isSimulating(world)) { + isNetSynched = true; + Proxies.net.sendToServer(new PacketUpdate(PacketIds.IMPRINT_SELECTION_GET)); + } + } + + @Override + public void handleSelectionChange(EntityPlayer player, PacketUpdate packet) { + + if (packet.payload.intPayload[1] == 0) { + if (packet.payload.intPayload[0] == 0) + inventory.advancePrimary(); + else + inventory.advanceSecondary(); + + } else if (packet.payload.intPayload[0] == 0) + inventory.regressPrimary(); + else + inventory.regressSecondary(); + } + + public void sendSelection(EntityPlayer player) { + PacketPayload payload = new PacketPayload(2, 0, 0); + payload.intPayload[0] = inventory.getPrimaryIndex(); + payload.intPayload[1] = inventory.getSecondaryIndex(); + Proxies.net.sendToPlayer(new PacketUpdate(PacketIds.GUI_SELECTION, payload), player); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiAlveary.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlveary.java new file mode 100755 index 000000000..783a60811 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlveary.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.apiculture.gadgets.TileAlvearyPlain; +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Utils; + +public class GuiAlveary extends GuiForestry { + + public GuiAlveary(InventoryPlayer inventory, TileAlvearyPlain tile) { + super(Defaults.TEXTURE_PATH_GUI + "/alveary.png", new ContainerAlveary(inventory, tile), tile); + + ySize = 190; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String title = StringUtil.localize("tile." + tile.getInventoryName()); + this.fontRendererObj.drawString(title, getCenteredOffset(title), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + TileAlvearyPlain machine = tile; + drawHealthMeter(guiLeft + 20, guiTop + 37, machine.getHealthScaled(46), Utils.rateTankLevel(machine.getHealthScaled(100))); + } + + private void drawHealthMeter(int x, int y, int height, EnumTankLevel rated) { + int i = 176; + int k = 0; + switch (rated) { + case EMPTY: + break; + case LOW: + i += 4; + break; + case MEDIUM: + i += 8; + break; + case HIGH: + i += 12; + break; + case MAXIMUM: + i += 16; + break; + } + + this.drawTexturedModalRect(x, y + 46 - height, i, k + 46 - height, 4, height); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearyHygroregulator.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearyHygroregulator.java new file mode 100755 index 000000000..8219bda5c --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearyHygroregulator.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.apiculture.gadgets.TileAlvearyHygroregulator; +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; + +public class GuiAlvearyHygroregulator extends GuiForestry { + + public GuiAlvearyHygroregulator(InventoryPlayer inventory, TileAlvearyHygroregulator tile) { + super(Defaults.TEXTURE_PATH_GUI + "/hygroregulator.png", new ContainerAlvearyHygroregulator(inventory, tile)); + + widgetManager.add(new TankWidget(this.widgetManager, 104, 17, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.alveary.5"); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySieve.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySieve.java new file mode 100755 index 000000000..d7217a92b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySieve.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.apiculture.gadgets.TileAlvearySieve; +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; + +public class GuiAlvearySieve extends GuiForestry { + + public GuiAlvearySieve(InventoryPlayer inventory, TileAlvearySieve tile) { + super(Defaults.TEXTURE_PATH_GUI + "/sieve.png", new ContainerAlvearySieve(inventory, tile)); + } + + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySwarmer.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySwarmer.java new file mode 100755 index 000000000..f8a5e6099 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiAlvearySwarmer.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.apiculture.gadgets.TileAlvearySwarmer; +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; + +public class GuiAlvearySwarmer extends GuiForestry { + + public GuiAlvearySwarmer(InventoryPlayer inventory, TileAlvearySwarmer tile) { + super(Defaults.TEXTURE_PATH_GUI + "/swarmer.png", new ContainerAlvearySwarmer(inventory, tile)); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiApiary.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiApiary.java new file mode 100755 index 000000000..af2708dbe --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiApiary.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.apiculture.gadgets.TileApiary; +import forestry.apiculture.gadgets.TileBeehouse; +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Utils; + +public class GuiApiary extends GuiForestry { + + public GuiApiary(InventoryPlayer inventory, TileApiary tile) { + super(Defaults.TEXTURE_PATH_GUI + "/apiary.png", new ContainerApiary(inventory, tile, true), tile); + + ySize = 190; + } + + public GuiApiary(InventoryPlayer inventory, TileBeehouse tile) { + super(Defaults.TEXTURE_PATH_GUI + "/alveary.png", new ContainerApiary(inventory, tile, false), tile); + + ySize = 190; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + TileBeehouse machine = tile; + drawHealthMeter(guiLeft + 20, guiTop + 37, machine.getHealthScaled(46), Utils.rateTankLevel(machine.getHealthScaled(100))); + } + + private void drawHealthMeter(int x, int y, int height, EnumTankLevel rated) { + int i = 176; + int k = 0; + switch (rated) { + case EMPTY: + break; + case LOW: + i += 4; + break; + case MEDIUM: + i += 8; + break; + case HIGH: + i += 12; + break; + case MAXIMUM: + i += 16; + break; + } + + this.drawTexturedModalRect(x, y + 46 - height, i, k + 46 - height, 4, height); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiBeealyzer.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiBeealyzer.java new file mode 100755 index 000000000..91da3e27c --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiBeealyzer.java @@ -0,0 +1,321 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import java.util.ArrayList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IAlleleBeeEffect; +import forestry.api.apiculture.IBee; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAlleleFlowers; +import forestry.api.genetics.IAlleleInteger; +import forestry.apiculture.items.ItemBeeGE; +import forestry.apiculture.items.ItemBeealyzer.BeealyzerInventory; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.AlleleArea; +import forestry.core.genetics.AlleleBoolean; +import forestry.core.genetics.AlleleTolerance; +import forestry.core.genetics.ClimateHelper; +import forestry.core.gui.GuiAlyzer; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Vect; +import forestry.plugins.PluginApiculture; + +public class GuiBeealyzer extends GuiAlyzer { + + private ItemStack[] tempProductList; + + public GuiBeealyzer(EntityPlayer player, BeealyzerInventory inventory) { + super(AlleleManager.alleleRegistry.getSpeciesRoot("rootBees"), player, + new ContainerBeealyzer(player.inventory, inventory), inventory, 1, inventory.getSizeInventory()); + + xSize = 196; + ySize = 238; + + ArrayList beeList = new ArrayList(); + ((ItemBeeGE) ForestryItem.beeDroneGE.item()).addCreativeItems(beeList, false); + for (ItemStack beeStack : beeList) + iconStacks.put(PluginApiculture.beeInterface.getMember(beeStack).getIdent(), beeStack); + + breedingTracker = PluginApiculture.beeInterface.getBreedingTracker(player.worldObj, player.getGameProfile().getId()); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + int page = 0; + IBee bee = null; + EnumBeeType beeType = EnumBeeType.DRONE; + for (int k = 1; k < BeealyzerInventory.SLOT_ANALYZE_5 + 1; k++) { + if (k == BeealyzerInventory.SLOT_ENERGY) + continue; + + if (inventory.getStackInSlot(k) == null) + continue; + bee = PluginApiculture.beeInterface.getMember(inventory.getStackInSlot(k)); + beeType = PluginApiculture.beeInterface.getType(inventory.getStackInSlot(k)); + if (bee == null || !bee.isAnalyzed()) + continue; + + page = k; + break; + } + + switch (page) { + case 1: + drawAnalyticsPage1(bee, beeType); + break; + case 2: + drawAnalyticsPage2(bee, beeType); + break; + case 3: + drawAnalyticsPage3(bee, beeType); + break; + case 4: + drawAnalyticsPage4(bee); + break; + case 6: + drawAnalyticsPageClassification(bee); + break; + default: + drawAnalyticsOverview(); + } + + } + + private void drawAnalyticsOverview() { + + startPage(); + + newLine(); + String title = StringUtil.localize("gui.beealyzer").toUpperCase(); + drawCenteredLine(title, 8, 158); + newLine(); + + fontRendererObj.drawSplitString(StringUtil.localize("gui.beealyzer.help"), (int) ((guiLeft + COLUMN_0 + 4) * (1 / factor)), + (int) ((guiTop + 42) * (1 / factor)), (int) (158 * (1 / factor)), fontColor.get("gui.screen")); + newLine(); + newLine(); + newLine(); + newLine(); + + drawLine(StringUtil.localize("gui.beealyzer.overview") + ":", COLUMN_0 + 4); + newLine(); + drawLine("I : " + StringUtil.localize("gui.general"), COLUMN_0 + 4); + newLine(); + drawLine("II : " + StringUtil.localize("gui.environment"), COLUMN_0 + 4); + newLine(); + drawLine("III: " + StringUtil.localize("gui.produce"), COLUMN_0 + 4); + newLine(); + drawLine("IV : " + StringUtil.localize("gui.evolution"), COLUMN_0 + 4); + + newLine(); + + String mode = breedingTracker.getModeName(); + if (mode != null && !mode.isEmpty()) { + newLine(); + String rules = StringUtil.localize("gui.beealyzer.behaviour") + ": " + StringUtil.capitalize(mode); + drawLine(rules, 8 + getCenteredOffset(title, 158), fontColor.get("gui.beealyzer.binomial")); + } + + endPage(); + + } + + private void drawAnalyticsPage1(IBee bee, EnumBeeType type) { + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.active"), COLUMN_1); + drawLine(StringUtil.localize("gui.inactive"), COLUMN_2); + + newLine(); + newLine(); + + drawSpeciesRow(StringUtil.localize("gui.species"), bee, EnumBeeChromosome.SPECIES); + + drawRow(StringUtil.localize("gui.lifespan"), bee.getGenome().getActiveAllele(EnumBeeChromosome.LIFESPAN.ordinal()).getName(), + bee.getGenome().getInactiveAllele(EnumBeeChromosome.LIFESPAN.ordinal()).getName(), bee, + EnumBeeChromosome.LIFESPAN); + + drawRow(StringUtil.localize("gui.speed"), bee.getGenome().getActiveAllele(EnumBeeChromosome.SPEED.ordinal()).getName(), + bee.getGenome().getInactiveAllele(EnumBeeChromosome.SPEED.ordinal()).getName(), bee, EnumBeeChromosome.SPEED); + + drawRow(StringUtil.localize("gui.pollination"), bee.getGenome().getActiveAllele(EnumBeeChromosome.FLOWERING.ordinal()).getName(), + bee.getGenome().getInactiveAllele(EnumBeeChromosome.FLOWERING.ordinal()).getName(), bee, + EnumBeeChromosome.FLOWERING); + + drawRow(StringUtil.localize("gui.flowers"), StringUtil.localize(bee.getGenome().getFlowerProvider().getDescription()), + StringUtil.localize(((IAlleleFlowers) bee.getGenome().getInactiveAllele(EnumBeeChromosome.FLOWER_PROVIDER.ordinal())).getProvider() + .getDescription()), bee, EnumBeeChromosome.FLOWER_PROVIDER); + + drawLine(StringUtil.localize("gui.fertility"), COLUMN_0); + drawFertilityInfo(bee.getGenome().getFertility(), COLUMN_1, getColorCoding(bee.getGenome().getActiveAllele(EnumBeeChromosome.FERTILITY.ordinal()) + .isDominant()), 0); + drawFertilityInfo(((IAlleleInteger) bee.getGenome().getInactiveAllele(EnumBeeChromosome.FERTILITY.ordinal())).getValue(), COLUMN_2, getColorCoding(bee + .getGenome().getInactiveAllele(EnumBeeChromosome.FERTILITY.ordinal()).isDominant()), 0); + + newLine(); + + int[] areaAr = bee.getGenome().getTerritory(); + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]); + drawRow(StringUtil.localize("gui.area"), area.toString(), ((AlleleArea) bee.getGenome().getInactiveAllele(EnumBeeChromosome.TERRITORY.ordinal())) + .getArea().toString(), bee, EnumBeeChromosome.TERRITORY); + + drawRow(StringUtil.localize("gui.effect"), StringUtil.localize(bee.getGenome().getEffect().getName()), + StringUtil.localize(((IAlleleBeeEffect) bee.getGenome().getInactiveAllele(EnumBeeChromosome.EFFECT.ordinal())).getName()), bee, + EnumBeeChromosome.EFFECT); + + newLine(); + + endPage(); + } + + private void drawAnalyticsPage2(IBee bee, EnumBeeType type) { + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.active"), COLUMN_1); + drawLine(StringUtil.localize("gui.inactive"), COLUMN_2); + + newLine(); + newLine(); + + drawRow(StringUtil.localize("gui.climate"), ClimateHelper.toDisplay(bee.getGenome().getPrimary().getTemperature()), + ClimateHelper.toDisplay(bee.getGenome().getSecondary().getTemperature()), bee, EnumBeeChromosome.SPECIES); + + drawLine(StringUtil.localize("gui.temptol"), COLUMN_0); + drawToleranceInfo(bee.getGenome().getToleranceTemp(), COLUMN_1, + getColorCoding(bee.getGenome().getActiveAllele(EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()).isDominant())); + drawToleranceInfo(((AlleleTolerance) bee.getGenome().getInactiveAllele(EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal())).getValue(), COLUMN_2, + getColorCoding(bee.getGenome().getInactiveAllele(EnumBeeChromosome.TEMPERATURE_TOLERANCE.ordinal()).isDominant())); + + newLine(); + + drawRow(StringUtil.localize("gui.humidity"), ClimateHelper.toDisplay(bee.getGenome().getPrimary().getHumidity()), + ClimateHelper.toDisplay(bee.getGenome().getSecondary().getHumidity()), bee, EnumBeeChromosome.SPECIES); + + drawLine(StringUtil.localize("gui.humidtol"), COLUMN_0); + drawToleranceInfo(bee.getGenome().getToleranceHumid(), COLUMN_1, + getColorCoding(bee.getGenome().getActiveAllele(EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()).isDominant())); + drawToleranceInfo(((AlleleTolerance) bee.getGenome().getInactiveAllele(EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal())).getValue(), COLUMN_2, + getColorCoding(bee.getGenome().getInactiveAllele(EnumBeeChromosome.HUMIDITY_TOLERANCE.ordinal()).isDominant())); + + newLine(); + newLine(); + + String yes = StringUtil.localize("yes"); + String no = StringUtil.localize("no"); + + String diurnal0, diurnal1, nocturnal0, nocturnal1; + if(bee.getGenome().getNocturnal()) { + nocturnal0 = diurnal0 = yes; + } else { + nocturnal0 = bee.getGenome().getPrimary().isNocturnal() ? yes : no; + diurnal0 = !bee.getGenome().getPrimary().isNocturnal() ? yes : no; + } + if(((AlleleBoolean) bee.getGenome().getInactiveAllele(EnumBeeChromosome.NOCTURNAL.ordinal())).getValue()) { + nocturnal1 = diurnal1 = yes; + } else { + nocturnal1 = bee.getGenome().getSecondary().isNocturnal() ? yes : no; + diurnal1 = !bee.getGenome().getSecondary().isNocturnal() ? yes : no; + } + + drawLine(StringUtil.localize("gui.diurnal"), COLUMN_0); + drawLine(diurnal0, COLUMN_1, getColorCoding(false)); + drawLine(diurnal1, COLUMN_2, getColorCoding(false)); + newLine(); + + drawLine(StringUtil.localize("gui.nocturnal"), COLUMN_0); + drawLine(nocturnal0, COLUMN_1, getColorCoding(false)); + drawLine(nocturnal1, COLUMN_2, getColorCoding(false)); + newLine(); + + String primary = StringUtil.readableBoolean(bee.getGenome().getTolerantFlyer(), yes, no); + String secondary = StringUtil.readableBoolean(((AlleleBoolean) bee.getGenome().getInactiveAllele(EnumBeeChromosome.TOLERANT_FLYER.ordinal())).getValue(), yes, + no); + + drawRow(StringUtil.localize("gui.flyer"), primary, secondary, bee, EnumBeeChromosome.TOLERANT_FLYER); + + primary = StringUtil.readableBoolean(bee.getGenome().getCaveDwelling(), yes, no); + secondary = StringUtil.readableBoolean(((AlleleBoolean) bee.getGenome().getInactiveAllele(EnumBeeChromosome.CAVE_DWELLING.ordinal())).getValue(), yes, + no); + + drawRow(StringUtil.localize("gui.cave"), primary, secondary, bee, EnumBeeChromosome.CAVE_DWELLING); + + newLine(); + + String displayText; + if (type == EnumBeeType.PRINCESS || type == EnumBeeType.QUEEN) { + displayText = "bees.stock.pristine"; + if (!bee.isNatural()) + displayText = "bees.stock.ignoble"; + displayText = StringUtil.localize(displayText); + // int offset = (int)(((158 - fontRendererObj.getStringWidth(origin)) / 2)*(1/factor)); + drawCenteredLine(displayText, 8, 158, fontColor.get("gui.beealyzer.binomial"));; + } + + if (bee.getGeneration() >= 0) { + newLine(); + + displayText = bee.getGeneration() + " " + StringUtil.localize("gui.beealyzer.generations"); + // offset = (int)(((158 - fontRendererObj.getStringWidth(origin)) / 2)*(1/factor)); + drawCenteredLine(displayText, 8, 158, fontColor.get("gui.beealyzer.binomial")); + } + + endPage(); + } + + private void drawAnalyticsPage3(IBee bee, EnumBeeType type) { + + tempProductList = bee.getProduceList(); + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.beealyzer.produce") + ":", COLUMN_0); + + newLine(); + + int x = COLUMN_0; + for (ItemStack stack : tempProductList) { + itemRender.renderItemIntoGUI(fontRendererObj, mc.renderEngine, stack, (int) ((guiLeft + x) * (1 / factor)), + (int) ((guiTop + getLineY()) * (1 / factor))); + x += 18; + if (x > adjustToFactor(148)) { + x = COLUMN_0; + newLine(); + } + } + + newLine(); + newLine(); + + drawLine(StringUtil.localize("gui.beealyzer.specialty") + ":", COLUMN_0); + newLine(); + + x = COLUMN_0; + for (ItemStack stack : bee.getSpecialtyList()) { + itemRender.renderItemIntoGUI(fontRendererObj, mc.renderEngine, stack, (int) ((guiLeft + x) * (1 / factor)), + (int) ((guiTop + getLineY()) * (1 / factor))); + x += 18; + if (x > adjustToFactor(148)) { + x = COLUMN_0; + newLine(); + } + } + + endPage(); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiHabitatLocator.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiHabitatLocator.java new file mode 100755 index 000000000..c0d46344b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiHabitatLocator.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.IIcon; +import net.minecraft.world.biome.BiomeGenBase; + +import org.lwjgl.opengl.GL11; + +import forestry.apiculture.items.ItemBiomefinder.BiomefinderInventory; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.Widget; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class GuiHabitatLocator extends GuiForestry { + + public class HabitatSlot extends Widget { + + private final int slot; + private final String name; + private final String iconIndex; + public boolean isActive = false; + + public HabitatSlot(int slot, String name) { + super(widgetManager, 0, 0); + this.slot = slot; + this.name = name; + this.iconIndex = "habitats/" + name.toLowerCase(Locale.ENGLISH); + } + + @Override + public String getLegacyTooltip(EntityPlayer player) { + return name; + } + + public IIcon getIcon() { + return TextureManager.getInstance().getDefault(iconIndex); + } + + public void setPosition(int x, int y) { + this.xPos = x; + this.yPos = y; + } + + @Override + public void draw(int startX, int startY) { + + if (getIcon() != null) { + GL11.glDisable(GL11.GL_LIGHTING); + + if (!isActive) + GL11.glColor4f(0.2f, 0.2f, 0.2f, 0.2f); + + Proxies.common.bindTexture(SpriteSheet.ITEMS); + manager.gui.drawTexturedModelRectFromIcon(startX + xPos, startY + yPos, getIcon(), 16, 16); + GL11.glEnable(GL11.GL_LIGHTING); + } + } + + } + + private final HabitatSlot[] habitatSlots = new HabitatSlot[] { new HabitatSlot(0, "Ocean"), // ocean + // + + // beach + new HabitatSlot(1, "Plains"), new HabitatSlot(2, "Desert"), // desert + // + + // desert + // hills + new HabitatSlot(3, "Forest"), // forest, forestHills, river + new HabitatSlot(4, "Jungle"), // jungle, jungleHills + new HabitatSlot(5, "Taiga"), // taiga, taigaHills + new HabitatSlot(6, "Hills"), // extremeHills, extremeHillsEdge + new HabitatSlot(7, "Swampland"), new HabitatSlot(8, "Snow"), // Ice + // plains, + // mountains, + // frozen + // rivers, + // frozen + // oceans + new HabitatSlot(9, "Mushroom"), // Ice plains, mountains, frozen + // rivers, frozen oceans + new HabitatSlot(10, "Hell"), new HabitatSlot(11, "End") }; + private final HashMap biomeToHabitat = new HashMap(); + + private int startX; + private int startY; + + public GuiHabitatLocator(InventoryPlayer inventory, BiomefinderInventory item) { + super(Defaults.TEXTURE_PATH_GUI + "/biomefinder.png", new ContainerHabitatLocator(inventory, item), item); + + xSize = 176; + ySize = 184; + + int x; + int y; + for (HabitatSlot slot : habitatSlots) { + + if (slot.slot > 5) { + x = 18 + (slot.slot - 6) * 20; + y = 50; + } else { + x = 18 + slot.slot * 20; + y = 32; + } + + slot.setPosition(x, y); + this.widgetManager.add(slot); + } + + biomeToHabitat.put(BiomeGenBase.ocean.biomeID, habitatSlots[0]); + biomeToHabitat.put(BiomeGenBase.beach.biomeID, habitatSlots[0]); + biomeToHabitat.put(BiomeGenBase.plains.biomeID, habitatSlots[1]); + biomeToHabitat.put(BiomeGenBase.desert.biomeID, habitatSlots[2]); + // biomeToHabitat.put(BiomeGenBase.desertHills.biomeID, + // habitatSlots[2]); // Removed for TFC compatibility + biomeToHabitat.put(BiomeGenBase.forest.biomeID, habitatSlots[3]); + biomeToHabitat.put(BiomeGenBase.forestHills.biomeID, habitatSlots[3]); + biomeToHabitat.put(BiomeGenBase.river.biomeID, habitatSlots[3]); + biomeToHabitat.put(BiomeGenBase.jungle.biomeID, habitatSlots[4]); + biomeToHabitat.put(BiomeGenBase.jungleHills.biomeID, habitatSlots[4]); + biomeToHabitat.put(BiomeGenBase.taiga.biomeID, habitatSlots[5]); + biomeToHabitat.put(BiomeGenBase.taigaHills.biomeID, habitatSlots[5]); + biomeToHabitat.put(BiomeGenBase.extremeHills.biomeID, habitatSlots[6]); + biomeToHabitat.put(BiomeGenBase.extremeHillsEdge.biomeID, habitatSlots[6]); + biomeToHabitat.put(BiomeGenBase.swampland.biomeID, habitatSlots[7]); + biomeToHabitat.put(BiomeGenBase.frozenOcean.biomeID, habitatSlots[8]); + biomeToHabitat.put(BiomeGenBase.frozenRiver.biomeID, habitatSlots[8]); + biomeToHabitat.put(BiomeGenBase.iceMountains.biomeID, habitatSlots[8]); + biomeToHabitat.put(BiomeGenBase.icePlains.biomeID, habitatSlots[8]); + biomeToHabitat.put(BiomeGenBase.mushroomIsland.biomeID, habitatSlots[9]); + biomeToHabitat.put(BiomeGenBase.mushroomIslandShore.biomeID, habitatSlots[9]); + biomeToHabitat.put(BiomeGenBase.hell.biomeID, habitatSlots[10]); + biomeToHabitat.put(BiomeGenBase.sky.biomeID, habitatSlots[11]); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + String str = StringUtil.localize("gui.habitatlocator").toUpperCase(); + fontRendererObj.drawString(str, startX + 8 + getCenteredOffset(str, 138), startY + 16, fontColor.get("gui.screen")); + + str = "(" + StringUtil.localize("gui.closetosearch") + ")"; + fontRendererObj.drawString(str, startX + 8 + getCenteredOffset(str, 138), startY + 76, fontColor.get("gui.table.header")); + + // Reset habitat slots + for (HabitatSlot slot : habitatSlots) + slot.isActive = false; + + // Set according to valid biomes. + ArrayList biomeids = ((ContainerHabitatLocator) inventorySlots).inventory.biomesToSearch; + for (int biomeid : biomeids) { + if (!biomeToHabitat.containsKey(biomeid)) + continue; + + biomeToHabitat.get(biomeid).isActive = true; + } + + for (HabitatSlot slot : habitatSlots) + slot.draw(startX, startY); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Reset afterwards. + + } + + @Override + public void initGui() { + super.initGui(); + + startX = (this.width - this.xSize) / 2; + startY = (this.height - this.ySize) / 2; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/gui/GuiImprinter.java b/forestry_common/apiculture/forestry/apiculture/gui/GuiImprinter.java new file mode 100755 index 000000000..14d30e5ab --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/gui/GuiImprinter.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.gui; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.apiculture.items.ItemBeeGE; +import forestry.apiculture.items.ItemImprinter.ImprinterInventory; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.GuiForestry; +import forestry.core.proxy.Proxies; +import forestry.plugins.PluginApiculture; + +public class GuiImprinter extends GuiForestry { + + private final ImprinterInventory inventory; + private final ContainerImprinter container; + + private int startX; + private int startY; + + private final HashMap iconStacks = new HashMap(); + + public GuiImprinter(InventoryPlayer inventoryplayer, ImprinterInventory inventory) { + super(Defaults.TEXTURE_PATH_GUI + "/imprinter.png", new ContainerImprinter(inventoryplayer, inventory), inventory); + + this.inventory = inventory; + this.container = (ContainerImprinter) inventorySlots; + + xSize = 176; + ySize = 185; + + ArrayList beeList = new ArrayList(); + ((ItemBeeGE) ForestryItem.beeDroneGE.item()).addCreativeItems(beeList, false); + for (ItemStack beeStack : beeList) + iconStacks.put(PluginApiculture.beeInterface.getMember(beeStack).getIdent(), beeStack); + + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + container.updateContainer(Proxies.common.getRenderWorld()); + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + int offset = (138 - fontRendererObj.getStringWidth("GENOME IMPRINTER")) / 2; + fontRendererObj.drawString("GENOME IMPRINTER", startX + 8 + offset, startY + 16, fontColor.get("gui.screen")); + + IAlleleBeeSpecies primary = inventory.getPrimary(); + drawBeeSpeciesIcon(primary, startX + 12, startY + 32); + fontRendererObj.drawString(primary.getName(), startX + 32, startY + 36, fontColor.get("gui.screen")); + + IAlleleBeeSpecies secondary = inventory.getSecondary(); + drawBeeSpeciesIcon(secondary, startX + 12, startY + 52); + fontRendererObj.drawString(secondary.getName(), startX + 32, startY + 56, fontColor.get("gui.screen")); + + String youCheater = "(You Cheater!)"; + offset = (138 - fontRendererObj.getStringWidth(youCheater)) / 2; + fontRendererObj.drawString(youCheater, startX + 8 + offset, startY + 76, fontColor.get("gui.screen")); + + } + + private void drawBeeSpeciesIcon(IAlleleBeeSpecies bee, int x, int y) { + + /* + * GL11.glDisable(GL11.GL_LIGHTING); mc.renderEngine.func_98187_b(Defaults.TEXTURE_BEES); + * + * for (int i = 0; i < ForestryItem.beeDroneGE.getRenderPasses(0); ++i) { + * + * int iconIndex = ForestryItem.beeDroneGE.getIconIndex(iconStacks.get(bee.getUID()), i); int color = ((ItemGE) + * ForestryItem.beeDroneGE).getColorFromItemStack(iconStacks.get(bee.getUID()), i); float colorR = (color >> 16 & 255) / 255.0F; float colorG = (color + * >> 8 & 255) / 255.0F; float colorB = (color & 255) / 255.0F; + * + * GL11.glColor4f(colorR, colorG, colorB, 1.0F); drawTexturedModalRect(x, y, iconIndex % 16 * 16, iconIndex / 16 * 16, 16, 16); + * + * } GL11.glEnable(GL11.GL_LIGHTING); + */ + + } + + private int getHabitatSlotAtPosition(int i, int j) { + int[] xPos = new int[] { 12, 12 }; + int[] yPos = new int[] { 32, 52 }; + + for (int l = 0; l < xPos.length; l++) + if (i >= xPos[l] && i <= xPos[l] + 16 && j >= yPos[l] && j <= yPos[l] + 16) + return l; + + return -1; + } + + @Override + protected void mouseClicked(int i, int j, int k) { + super.mouseClicked(i, j, k); + + int cornerX = (width - xSize) / 2; + int cornerY = (height - ySize) / 2; + + int slot = 0; + if ((slot = getHabitatSlotAtPosition(i - cornerX, j - cornerY)) < 0) + return; + + if (k == 0) + container.advanceSelection(slot, Proxies.common.getRenderWorld()); + else + container.regressSelection(slot, Proxies.common.getRenderWorld()); + } + + @Override + public void initGui() { + super.initGui(); + + startX = (this.width - this.xSize) / 2; + startY = (this.height - this.ySize) / 2; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemAlvearyBlock.java b/forestry_common/apiculture/forestry/apiculture/items/ItemAlvearyBlock.java new file mode 100755 index 000000000..62034381b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemAlvearyBlock.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import net.minecraft.block.Block; + +import forestry.core.gadgets.IStructureBlockItem; +import forestry.core.items.ItemForestryBlock; + +/** + * + * @author CovertJaguar + */ +public class ItemAlvearyBlock extends ItemForestryBlock implements IStructureBlockItem { + + public ItemAlvearyBlock(Block block) { + super(block); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemArmorApiarist.java b/forestry_common/apiculture/forestry/apiculture/items/ItemArmorApiarist.java new file mode 100755 index 000000000..71ef94a36 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemArmorApiarist.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.apiculture.IArmorApiarist; +import forestry.api.core.IArmorNaturalist; +import forestry.api.core.Tabs; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemArmorApiarist extends ItemArmor implements IArmorApiarist, IArmorNaturalist { + + public ItemArmorApiarist(int slot) { + super(ArmorMaterial.CLOTH, 0, slot); + this.setMaxDamage(100); + setCreativeTab(Tabs.tabApiculture); + } + + @Override + public String getArmorTexture(ItemStack stack, Entity entity, int slot, String type) { + if (ForestryItem.apiaristLegs.isItemEqual(stack)) + return Defaults.ID + ":" + Defaults.TEXTURE_APIARIST_ARMOR_SECONDARY; + else + return Defaults.ID + ":" + Defaults.TEXTURE_APIARIST_ARMOR_PRIMARY; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + itemIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "")); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int par1, int par2) { + return itemIcon; + } + + @Override + public boolean requiresMultipleRenderPasses() { + return false; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int renderPass) { + return 0xffffff; + } + + @Override + public boolean hasColor(ItemStack itemstack) { + return false; + } + + @Override + public boolean protectPlayer(EntityPlayer player, ItemStack armor, String cause, boolean doProtect) { + return true; + } + + @Override + public boolean canSeePollination(EntityPlayer player, ItemStack armor, boolean doSee) { + return armorType == 0; + } + + public static boolean wearsHelmet(EntityPlayer player, String cause, boolean protect) { + ItemStack armorItem = player.inventory.armorInventory[3]; + return armorItem != null && armorItem.getItem() instanceof IArmorApiarist + && ((IArmorApiarist) armorItem.getItem()).protectPlayer(player, armorItem, cause, protect); + } + + public static boolean wearsChest(EntityPlayer player, String cause, boolean protect) { + ItemStack armorItem = player.inventory.armorInventory[2]; + return armorItem != null && armorItem.getItem() instanceof IArmorApiarist + && ((IArmorApiarist) armorItem.getItem()).protectPlayer(player, armorItem, cause, protect); + } + + public static boolean wearsLegs(EntityPlayer player, String cause, boolean protect) { + ItemStack armorItem = player.inventory.armorInventory[1]; + return armorItem != null && armorItem.getItem() instanceof IArmorApiarist + && ((IArmorApiarist) armorItem.getItem()).protectPlayer(player, armorItem, cause, protect); + } + + public static boolean wearsBoots(EntityPlayer player, String cause, boolean protect) { + ItemStack armorItem = player.inventory.armorInventory[0]; + return armorItem != null && armorItem.getItem() instanceof IArmorApiarist + && ((IArmorApiarist) armorItem.getItem()).protectPlayer(player, armorItem, cause, protect); + } + + public static int wearsItems(EntityPlayer player, String cause, boolean protect) { + int count = 0; + + if (wearsHelmet(player, cause, protect)) + count++; + if (wearsChest(player, cause, protect)) + count++; + if (wearsLegs(player, cause, protect)) + count++; + if (wearsBoots(player, cause, protect)) + count++; + + return count; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemBeeGE.java b/forestry_common/apiculture/forestry/apiculture/items/ItemBeeGE.java new file mode 100755 index 000000000..48482b72d --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemBeeGE.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBee; +import forestry.api.core.Tabs; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IIndividual; +import forestry.apiculture.genetics.Bee; +import forestry.core.config.Config; +import forestry.core.genetics.ItemGE; +import forestry.core.utils.StringUtil; +import forestry.plugins.PluginApiculture; + +public class ItemBeeGE extends ItemGE { + + EnumBeeType type; + + public ItemBeeGE(EnumBeeType type) { + super(); + this.type = type; + setCreativeTab(Tabs.tabApiculture); + if (type != EnumBeeType.DRONE) + setMaxStackSize(1); + } + + @Override + protected IIndividual getIndividual(ItemStack itemstack) { + return new Bee(itemstack.getTagCompound()); + } + + @Override + protected int getDefaultPrimaryColour() { + return 0xffffff; + } + + @Override + protected int getDefaultSecondaryColour() { + return 0xffdc16; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + + if (itemstack.getTagCompound() == null) + return StringUtil.localize(type.getName()); + + IBee individual = new Bee(itemstack.getTagCompound()); + return individual.getDisplayName() + StringUtil.localize(type.getName() + ".adj.add") + " " + StringUtil.localize(type.getName()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + if(!itemstack.hasTagCompound()) + return; + + if(type != EnumBeeType.DRONE) { + IBee individual = new Bee(itemstack.getTagCompound()); + if (individual.isNatural()) + list.add("\u00A7e\u00A7o" + StringUtil.localize("bees.stock.pristine")); + else + list.add("\u00A7e" + StringUtil.localize("bees.stock.ignoble")); + } + + super.addInformation(itemstack, player, list, flag); + } + + @SuppressWarnings("rawtypes") + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + if (type == EnumBeeType.QUEEN) + return; + + addCreativeItems(itemList, true); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void addCreativeItems(List itemList, boolean hideSecrets) { + + for (IIndividual individual : PluginApiculture.beeInterface.getIndividualTemplates()) { + // Don't show secret bees unless ordered to. + if (hideSecrets && individual.isSecret() && !Config.isDebug) + continue; + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + ItemStack someStack = new ItemStack(this); + individual.writeToNBT(nbttagcompound); + someStack.setTagCompound(nbttagcompound); + itemList.add(someStack); + } + } + + /* RENDERING */ + @Override + public int getColorFromItemStack(ItemStack itemstack, int renderPass) { + if (!itemstack.hasTagCompound()) + return super.getColorFromItemStack(itemstack, renderPass); + + return getColourFromSpecies(PluginApiculture.beeInterface.getMember(itemstack).getGenome().getPrimary(), renderPass); + } + + @Override + public int getColourFromSpecies(IAlleleSpecies species, int renderPass) { + + if (species != null && species instanceof IAlleleBeeSpecies) + return ((IAlleleBeeSpecies) species).getIconColour(renderPass); + else + return 0xffffff; + + } + + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getRenderPasses(int metadata) { + return 3; + } + + /* ICONS */ + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + for (IAllele allele : AlleleManager.alleleRegistry.getRegisteredAlleles().values()) + if (allele instanceof IAlleleBeeSpecies) + ((IAlleleBeeSpecies) allele).getIconProvider().registerIcons(register); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(ItemStack itemstack, int renderPass) { + return getIconFromSpecies(PluginApiculture.beeInterface.getMember(itemstack).getGenome().getPrimary(), renderPass); + } + + @SideOnly(Side.CLIENT) + public IIcon getIconFromSpecies(IAlleleBeeSpecies species, int renderPass) { + if (species == null) + species = (IAlleleBeeSpecies) PluginApiculture.beeInterface.getDefaultTemplate()[EnumBeeChromosome.SPECIES.ordinal()]; + + return species.getIcon(type, renderPass); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemBeealyzer.java b/forestry_common/apiculture/forestry/apiculture/items/ItemBeealyzer.java new file mode 100755 index 000000000..8980f1365 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemBeealyzer.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; + +import forestry.api.apiculture.IBee; +import forestry.api.core.ForestryAPI; +import forestry.api.core.Tabs; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.IHintSource; +import forestry.core.items.ItemInventoried; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ItemInventory; +import forestry.plugins.PluginApiculture; + +public class ItemBeealyzer extends ItemInventoried { + + public static class BeealyzerInventory extends ItemInventory implements IErrorSource, IHintSource { + + public static final int SLOT_SPECIMEN = 0; + public static final int SLOT_ANALYZE_1 = 1; + public static final int SLOT_ANALYZE_2 = 2; + public static final int SLOT_ANALYZE_3 = 3; + public static final int SLOT_ANALYZE_4 = 4; + public static final int SLOT_ANALYZE_5 = 6; + public static final int SLOT_ENERGY = 5; + + EntityPlayer player; + + public BeealyzerInventory(EntityPlayer player) { + super(ItemBeealyzer.class, 7); + this.player = player; + } + + public BeealyzerInventory(EntityPlayer player, ItemStack itemStack) { + super(ItemBeealyzer.class, 7, itemStack); + this.player = player; + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = new NBTTagList(); + for (int i = SLOT_ENERGY; i < SLOT_ENERGY + 1; i++) + if (inventoryStacks[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + inventoryStacks[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("Items", nbttaglist); + + } + + private boolean isEnergy(ItemStack itemstack) { + if (itemstack == null || itemstack.stackSize <= 0) + return false; + + return ForestryItem.honeyDrop.isItemEqual(itemstack) || ForestryItem.honeydew.isItemEqual(itemstack); + } + + private void tryAnalyze() { + + // Analyzed slot occupied, abort + if (inventoryStacks[SLOT_ANALYZE_1] != null || inventoryStacks[SLOT_ANALYZE_2] != null || inventoryStacks[SLOT_ANALYZE_3] != null + || inventoryStacks[SLOT_ANALYZE_4] != null || inventoryStacks[SLOT_ANALYZE_5] != null) + return; + + // Source slot to analyze empty + if (getStackInSlot(SLOT_SPECIMEN) == null) + return; + + IBee bee = PluginApiculture.beeInterface.getMember(getStackInSlot(SLOT_SPECIMEN)); + // No bee, abort + if (bee == null) + return; + + // Analyze if necessary + if (!bee.isAnalyzed()) { + + // Requires energy + if (!isEnergy(getStackInSlot(SLOT_ENERGY))) + return; + + bee.analyze(); + if(player != null) { + PluginApiculture.beeInterface.getBreedingTracker(player.worldObj, player.getGameProfile().getId()).registerSpecies(bee.getGenome().getPrimary()); + PluginApiculture.beeInterface.getBreedingTracker(player.worldObj, player.getGameProfile().getId()).registerSpecies(bee.getGenome().getSecondary()); + } + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + bee.writeToNBT(nbttagcompound); + getStackInSlot(SLOT_SPECIMEN).setTagCompound(nbttagcompound); + + // Decrease energy + decrStackSize(SLOT_ENERGY, 1); + } + + setInventorySlotContents(SLOT_ANALYZE_1, getStackInSlot(SLOT_SPECIMEN)); + setInventorySlotContents(SLOT_SPECIMEN, null); + } + + @Override + public void markDirty() { + // if (!Proxies.common.isSimulating(player.worldObj)) + // return; + tryAnalyze(); + } + + // / IHINTSOURCE + @Override + public boolean hasHints() { + return Config.hints.get("beealyzer") != null && Config.hints.get("beealyzer").length > 0; + } + + @Override + public String[] getHints() { + return Config.hints.get("beealyzer"); + } + + // / IERRORSOURCE + @Override + public boolean throwsErrors() { + return true; + } + + @Override + public EnumErrorCode getErrorState() { + if (PluginApiculture.beeInterface.isMember(inventoryStacks[SLOT_SPECIMEN]) && !isEnergy(getStackInSlot(SLOT_ENERGY))) + return EnumErrorCode.NOHONEY; + + return EnumErrorCode.OK; + } + } + + public ItemBeealyzer() { + super(); + setMaxStackSize(1); + setCreativeTab(Tabs.tabApiculture); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) + entityplayer.openGui(ForestryAPI.instance, GuiId.BeealyzerGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + + return itemstack; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemBiomefinder.java b/forestry_common/apiculture/forestry/apiculture/items/ItemBiomefinder.java new file mode 100755 index 000000000..e24ba02d2 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemBiomefinder.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import java.util.ArrayList; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.apiculture.IBee; +import forestry.api.core.ForestryAPI; +import forestry.api.core.Tabs; +import forestry.apiculture.render.TextureBiomefinder; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.IHintSource; +import forestry.core.items.ItemInventoried; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ItemInventory; +import forestry.core.utils.Vect; +import forestry.plugins.PluginApiculture; + +public class ItemBiomefinder extends ItemInventoried { + + public static class BiomefinderInventory extends ItemInventory implements IErrorSource, IHintSource { + + public ArrayList biomesToSearch = new ArrayList(); + + private final short energySlot = 2; + private final short specimenSlot = 0; + private final short analyzeSlot = 1; + + public BiomefinderInventory() { + super(ItemBiomefinder.class, 3); + } + + public BiomefinderInventory(ItemStack itemstack) { + super(ItemBiomefinder.class, 3, itemstack); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = new NBTTagList(); + for (int i = 2; i < inventoryStacks.length; i++) + if (inventoryStacks[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + inventoryStacks[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("Items", nbttaglist); + + } + + private boolean isEnergy(ItemStack itemstack) { + if (itemstack == null || itemstack.stackSize <= 0) + return false; + + return ForestryItem.honeyDrop.isItemEqual(itemstack) || ForestryItem.honeydew.isItemEqual(itemstack); + } + + private void tryAnalyze() { + + // Analyzed slot occupied, abort + if (inventoryStacks[analyzeSlot] != null) + return; + + // Source slot to analyze empty + if (getStackInSlot(specimenSlot) == null) + return; + + IBee bee = PluginApiculture.beeInterface.getMember(getStackInSlot(specimenSlot)); + // No bee, abort + if (bee == null) + return; + + // Requires energy + if (!isEnergy(getStackInSlot(energySlot))) + return; + + biomesToSearch = bee.getSuitableBiomeIds(); + + // Decrease energy + decrStackSize(energySlot, 1); + + setInventorySlotContents(analyzeSlot, getStackInSlot(specimenSlot)); + setInventorySlotContents(specimenSlot, null); + } + + @Override + public void markDirty() { + tryAnalyze(); + } + + // / IHINTSOURCE + @Override + public boolean hasHints() { + return Config.hints.get("habitatlocator") != null && Config.hints.get("habitatlocator").length > 0; + } + + @Override + public String[] getHints() { + return Config.hints.get("habitatlocator"); + } + + // / IERRORSOURCE + @Override + public boolean throwsErrors() { + return true; + } + + @Override + public EnumErrorCode getErrorState() { + if (PluginApiculture.beeInterface.isMember(inventoryStacks[specimenSlot]) && !isEnergy(getStackInSlot(energySlot))) + return EnumErrorCode.NOHONEY; + + return EnumErrorCode.OK; + } + + } + + public ItemBiomefinder() { + super(); + setMaxStackSize(1); + setCreativeTab(Tabs.tabApiculture); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + + if (Proxies.common.isSimulating(world)) + entityplayer.openGui(ForestryAPI.instance, GuiId.HabitatLocatorGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + + return itemstack; + } + + public void startBiomeSearch(World world, EntityPlayer player, ArrayList biomesToSearch) { + + ArrayList excludedBiomes = new ArrayList(); + excludedBiomes.add(BiomeGenBase.ocean.biomeID); + excludedBiomes.add(BiomeGenBase.frozenOcean.biomeID); + excludedBiomes.add(BiomeGenBase.beach.biomeID); + biomesToSearch.removeAll(excludedBiomes); + + // If we are in a valid biome, we point to ourself. + BiomeGenBase biome = world.getBiomeGenForCoords((int) player.posX, (int) player.posZ); + if (biomesToSearch.contains(biome.biomeID)) { + Proxies.common.setBiomefinderCoordinates(player, new ChunkCoordinates((int) player.posX, (int) player.posY, (int) player.posZ)); + return; + } + + if (Proxies.common.isSimulating(world) && biomesToSearch.size() > 0) { + ChunkCoordinates target = findNearestBiome(player, biomesToSearch); + Proxies.common.setBiomefinderCoordinates(player, target); + } + + } + + private ChunkCoordinates findNearestBiome(EntityPlayer player, ArrayList biomesToSearch) { + + int loadChunkDistance = 25; + ChunkCoordinates coordinates = null; + Vect pos = new Vect((int) player.posX, (int) player.posY, (int) player.posZ); + for (int i = 0; i < 100; i++) { + // Test direction +X + if ((coordinates = getChunkCoordinates(pos.add(new Vect(10 * i, 0, 0)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + // Test direction +X+Z + if ((coordinates = getChunkCoordinates(pos.add(new Vect(10 * i, 0, 10 * i)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + // Test direction +X-Z + if ((coordinates = getChunkCoordinates(pos.add(new Vect(10 * i, 0, -10 * i)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + + // Test direction -X + if ((coordinates = getChunkCoordinates(pos.add(new Vect(-10 * i, 0, 0)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + // Test direction -X+Z + if ((coordinates = getChunkCoordinates(pos.add(new Vect(-10 * i, 0, 10 * i)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + // Test direction -X-Z + if ((coordinates = getChunkCoordinates(pos.add(new Vect(-10 * i, 0, -10 * i)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + + // Test direction +Z + if ((coordinates = getChunkCoordinates(pos.add(new Vect(0, 0, 10 * i)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + // Test direction -Z + if ((coordinates = getChunkCoordinates(pos.add(new Vect(0, 0, -10 * i)), player.worldObj, biomesToSearch, i < loadChunkDistance)) != null) + return coordinates; + } + return coordinates; + } + + private ChunkCoordinates getChunkCoordinates(Vect pos, World world, ArrayList biomesToSearch, boolean loadChunks) { + + BiomeGenBase biome = world.getBiomeGenForCoords(pos.x, pos.z); + + if (biomesToSearch.contains(biome.biomeID)) + return new ChunkCoordinates(pos.x, pos.y, pos.z); + + return null; + } + + /* TEXTURES */ + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + if(register instanceof TextureMap) { + TextureAtlasSprite texture = new TextureBiomefinder(); + ((TextureMap)register).setTextureEntry("forestry:biomefinder", texture); + itemIcon = texture; + } + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemCandleBlock.java b/forestry_common/apiculture/forestry/apiculture/items/ItemCandleBlock.java new file mode 100755 index 000000000..f54bdb40d --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemCandleBlock.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.apiculture.gadgets.BlockCandle; +import forestry.core.items.ItemForestryBlock; + +public class ItemCandleBlock extends ItemForestryBlock { + + public ItemCandleBlock(Block block) { + super(block); + } + + @Override + @SideOnly(Side.CLIENT) + public int getColorFromItemStack(ItemStack stack, int pass) { + int value = 0xffffff; + if (pass == 1 && stack.hasTagCompound()) { + NBTTagCompound tag = stack.getTagCompound(); + if (tag.hasKey("colour")) { + value = tag.getInteger("colour"); + } + } + return value; + } + + @Override + public String getUnlocalizedName(ItemStack itemStack) { + String value = "tile.candle"; + if (itemStack.hasTagCompound() && itemStack.getTagCompound().hasKey(BlockCandle.colourTagName)) { + value = value + ".dyed"; + } + + if (BlockCandle.isLit(itemStack)) { + value = value + ".lit"; + } + else { + value = value + ".stump"; + } + return value; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIconFromDamageForRenderPass(int meta, int pass) { + return ((BlockCandle)this.getBlock()).getTextureFromPassAndMeta((meta != 0) ? 8 : 0, pass); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getRenderPasses(int metadata) { + return 2; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemHiveFrame.java b/forestry_common/apiculture/forestry/apiculture/items/ItemHiveFrame.java new file mode 100755 index 000000000..b2f5c2300 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemHiveFrame.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import net.minecraft.item.ItemStack; + +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IHiveFrame; +import forestry.api.core.Tabs; +import forestry.core.items.ItemForestry; + +public class ItemHiveFrame extends ItemForestry implements IHiveFrame { + + private final float geneticDecay; + + public ItemHiveFrame(int maxDamage, float geneticDecay) { + super(); + setMaxStackSize(1); + setMaxDamage(maxDamage); + this.geneticDecay = geneticDecay; + setCreativeTab(Tabs.tabApiculture); + } + + @Override + public ItemStack frameUsed(IBeeHousing housing, ItemStack frame, IBee queen, int wear) { + frame.setItemDamage(frame.getItemDamage() + wear); + if (frame.getItemDamage() >= frame.getMaxDamage()) + return null; + else + return frame; + } + + @Override + public float getTerritoryModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getMutationModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return 1.0f; + } + + @Override + public float getLifespanModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier) { + return 1.0f; + } + + @Override + public float getProductionModifier(IBeeGenome genome, float currentModifier) { + return currentModifier < 10f ? 2.0f : 1f; + } + + @Override + public float getFloweringModifier(IBeeGenome genome, float currentModifier) { + return 1.0f; + } + + @Override + public float getGeneticDecay(IBeeGenome genome, float currentModifier) { + return this.geneticDecay; + } + + @Override + public boolean isSealed() { + return false; + } + + @Override + public boolean isSelfLighted() { + return false; + } + + @Override + public boolean isSunlightSimulated() { + return false; + } + + @Override + public boolean isHellish() { + return false; + } + + @Override + public boolean isBookEnchantable(ItemStack itemstack1, ItemStack itemstack2) { + return false; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemHoneycomb.java b/forestry_common/apiculture/forestry/apiculture/items/ItemHoneycomb.java new file mode 100755 index 000000000..1c6ed9e25 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemHoneycomb.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.Tabs; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.items.ItemForestry; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemHoneycomb extends ItemForestry { + + private static class CombInfo { + + public String name; + public int primaryColor; + public int secondaryColor; + public boolean isSecret = false; + + public CombInfo(String name, int primaryColor, int secondaryColor) { + this.name = name; + this.primaryColor = primaryColor; + this.secondaryColor = secondaryColor; + } + + public CombInfo setIsSecret() { + this.isSecret = true; + return this; + } + } + public CombInfo[] combs = new CombInfo[] { new CombInfo("honey", 0xe8d56a, 0xffa12b), // 0 + new CombInfo("cocoa", 0x674016, 0xffb62b).setIsSecret(), // 1 + new CombInfo("simmering", 0x981919, 0xffb62b), // 2 + new CombInfo("stringy", 0xc8be67, 0xbda93e), // 3 + new CombInfo("frozen", 0xf9ffff, 0xa0ffff), // 4 + new CombInfo("dripping", 0xdc7613, 0xffff00), // 5 + new CombInfo("silky", 0x508907, 0xddff00), // 6 + new CombInfo("parched", 0xdcbe13, 0xffff00), // 7 + new CombInfo("mysterious", 0x161616, 0xe099ff).setIsSecret(), // 8 + new CombInfo("irradiated", 0xeafff3, 0xeeff00).setIsSecret(), // 9 + new CombInfo("powdery", 0xe4e4e4, 0xffffff).setIsSecret(), // 10 + new CombInfo("reddened", 0x4b0000, 0x6200e7).setIsSecret(), // 11 + new CombInfo("darkened", 0x353535, 0x33ebcb).setIsSecret(), // 12 + new CombInfo("omega", 0x191919, 0x6dcff6).setIsSecret(), // 13 + new CombInfo("wheaten", 0xfeff8f, 0xffffff).setIsSecret(), // 14 + new CombInfo("mossy", 0x2a3313, 0x7e9939), // 15 + new CombInfo("mellow", 0x886000, 0xfff960) // 16 + // new CombInfo("", 0xd7bee5, 0xfd58ab), // kindof pinkish + }; + + public ItemHoneycomb() { + super(); + setMaxDamage(0); + setHasSubtypes(true); + setCreativeTab(Tabs.tabApiculture); + } + + @Override + public boolean isDamageable() { + return false; + } + + @Override + public boolean isRepairable() { + return false; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (itemstack.getItemDamage() < 0 || itemstack.getItemDamage() >= combs.length) + return null; + + return StringUtil.localize("item.comb." + combs[itemstack.getItemDamage()].name); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + icons = new IIcon[2]; + icons[0] = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".0"); + icons[1] = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".1"); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int i, int j) { + if (j > 0) + return icons[0]; + else + return icons[1]; + } + + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int j) { + if (j == 0) + return combs[itemstack.getItemDamage()].primaryColor; + else + return combs[itemstack.getItemDamage()].secondaryColor; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + for (int i = 0; i < combs.length; i++) { + if (!combs[i].isSecret || Config.isDebug) + itemList.add(new ItemStack(this, 1, i)); + } + } + + public int getCombTypeCount() { + return combs.length; + } + + public int getRandomCombType(Random random, boolean includeSecret) { + List validCombs = new ArrayList(getCombTypeCount()); + for (int i = 0; i < combs.length; i++) { + if (!combs[i].isSecret || includeSecret) + validCombs.add(i); + } + + if (validCombs.isEmpty()) + return 0; + else + return validCombs.get(random.nextInt(validCombs.size())); + } + + public static ItemStack getRandomComb(int qty, Random random, boolean includeSecret) { + return ForestryItem.beeComb.getItemStack(qty, ((ItemHoneycomb) ForestryItem.beeComb.item()).getRandomCombType(random, includeSecret)); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemImprinter.java b/forestry_common/apiculture/forestry/apiculture/items/ItemImprinter.java new file mode 100755 index 000000000..6b5f81fa4 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemImprinter.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IBee; +import forestry.api.core.ForestryAPI; +import forestry.api.core.Tabs; +import forestry.apiculture.genetics.Bee; +import forestry.core.items.ItemForestry; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.plugins.PluginApiculture; + +public class ItemImprinter extends ItemForestry { + + public static class ImprinterInventory implements IInventory { + + private final ItemStack[] inventoryStacks = new ItemStack[2]; + private final short specimenSlot = 0; + private final short imprintedSlot = 1; + + private int primaryIndex = 0; + private int secondaryIndex = 0; + + EntityPlayer player; + + public ImprinterInventory(EntityPlayer player) { + this.player = player; + } + + public void advancePrimary() { + if (primaryIndex < PluginApiculture.beeInterface.getIndividualTemplates().size() - 1) + primaryIndex++; + else + primaryIndex = 0; + } + + public void advanceSecondary() { + if (secondaryIndex < PluginApiculture.beeInterface.getIndividualTemplates().size() - 1) + secondaryIndex++; + else + secondaryIndex = 0; + } + + public void regressPrimary() { + if (primaryIndex > 0) + primaryIndex--; + else + primaryIndex = PluginApiculture.beeInterface.getIndividualTemplates().size() - 1; + } + + public void regressSecondary() { + if (secondaryIndex > 0) + secondaryIndex--; + else + secondaryIndex = PluginApiculture.beeInterface.getIndividualTemplates().size() - 1; + } + + public IAlleleBeeSpecies getPrimary() { + return PluginApiculture.beeInterface.getIndividualTemplates().get(primaryIndex).getGenome().getPrimary(); + } + + public IAlleleBeeSpecies getSecondary() { + return PluginApiculture.beeInterface.getIndividualTemplates().get(secondaryIndex).getGenome().getPrimary(); + } + + public IBee getSelectedBee() { + return new Bee(PluginApiculture.beeInterface.templateAsGenome( + PluginApiculture.beeInterface.getGenomeTemplates().get(PluginApiculture.beeInterface.getIndividualTemplates().get(primaryIndex).getIdent()), + PluginApiculture.beeInterface.getGenomeTemplates().get(PluginApiculture.beeInterface.getIndividualTemplates().get(secondaryIndex).getIdent()))); + } + + public int getPrimaryIndex() { + return primaryIndex; + } + + public int getSecondaryIndex() { + return secondaryIndex; + } + + public void setPrimaryIndex(int index) { + primaryIndex = index; + } + + public void setSecondaryIndex(int index) { + secondaryIndex = index; + } + + private void tryImprint() { + + if (inventoryStacks[specimenSlot] == null) + return; + + // Only imprint bees + if (!PluginApiculture.beeInterface.isMember(inventoryStacks[specimenSlot])) + return; + + // Needs space + if (inventoryStacks[imprintedSlot] != null) + return; + + IBee imprint = getSelectedBee(); + if (imprint == null) + return; + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + imprint.writeToNBT(nbttagcompound); + inventoryStacks[specimenSlot].setTagCompound(nbttagcompound); + + inventoryStacks[imprintedSlot] = inventoryStacks[specimenSlot]; + inventoryStacks[specimenSlot] = null; + } + + @Override + public ItemStack decrStackSize(int i, int j) { + if (inventoryStacks[i] == null) + return null; + + ItemStack product; + if (inventoryStacks[i].stackSize <= j) { + product = inventoryStacks[i]; + inventoryStacks[i] = null; + return product; + } else { + product = inventoryStacks[i].splitStack(j); + if (inventoryStacks[i].stackSize == 0) + inventoryStacks[i] = null; + + return product; + } + } + + @Override + public void markDirty() { + if (!Proxies.common.isSimulating(player.worldObj)) + return; + tryImprint(); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventoryStacks[i] = itemstack; + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventoryStacks[i]; + } + + @Override + public int getSizeInventory() { + return inventoryStacks.length; + } + + @Override + public String getInventoryName() { + return "Imprinter"; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + if (inventoryStacks[slot] == null) + return null; + ItemStack toReturn = inventoryStacks[slot]; + inventoryStacks[slot] = null; + return toReturn; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return true; + } + + } + + public ItemImprinter() { + super(); + setCreativeTab(Tabs.tabApiculture); + setMaxStackSize(1); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) + entityplayer.openGui(ForestryAPI.instance, GuiId.ImprinterGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + + return itemstack; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/items/ItemWaxCast.java b/forestry_common/apiculture/forestry/apiculture/items/ItemWaxCast.java new file mode 100755 index 000000000..782192e42 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/items/ItemWaxCast.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.items; + +import net.minecraft.item.ItemStack; + +import forestry.core.interfaces.ICraftingPlan; +import forestry.core.items.ItemForestry; + +public class ItemWaxCast extends ItemForestry implements ICraftingPlan { + + public ItemWaxCast() { + super(); + setMaxStackSize(1); + setMaxDamage(10); + setNoRepair(); + } + + @Override + public ItemStack planUsed(ItemStack plan, ItemStack result) { + plan.setItemDamage(plan.getItemDamage() + result.stackSize); + if (plan.getItemDamage() >= plan.getMaxDamage()) + return null; + else + return plan; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/proxy/ClientProxyApiculture.java b/forestry_common/apiculture/forestry/apiculture/proxy/ClientProxyApiculture.java new file mode 100755 index 000000000..e461221b2 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/proxy/ClientProxyApiculture.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.proxy; + +import net.minecraft.client.particle.EntityFX; +import net.minecraft.world.World; + +import cpw.mods.fml.client.registry.RenderingRegistry; + +import net.minecraftforge.client.MinecraftForgeClient; + +import forestry.apiculture.entities.EntityBee; +import forestry.apiculture.render.BeeItemRenderer; +import forestry.apiculture.render.EntityBeeFX; +import forestry.apiculture.render.ParticleRenderer; +import forestry.apiculture.render.RenderBee; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.render.RenderAnalyzer; +import forestry.core.render.TextureManager; +import forestry.core.utils.Localization; +import forestry.plugins.PluginApiculture; + +public class ClientProxyApiculture extends ProxyApiculture { + + @Override + public void initializeRendering() { + if(PluginApiculture.fancyRenderedBees) { + RenderingRegistry.registerEntityRenderingHandler(EntityBee.class, new RenderBee()); + + MinecraftForgeClient.registerItemRenderer(ForestryItem.beeDroneGE.item(), new BeeItemRenderer()); + MinecraftForgeClient.registerItemRenderer(ForestryItem.beePrincessGE.item(), new BeeItemRenderer()); + MinecraftForgeClient.registerItemRenderer(ForestryItem.beeQueenGE.item(), new BeeItemRenderer()); + } + } + + @Override + public void addBeeHiveFX(String icon, World world, double xCoord, double yCoord, double zCoord, int color, int areaX, int areaY, int areaZ) { + if (!Config.enableParticleFX) + return; + + EntityFX fx; + + if (world.rand.nextBoolean()) { + fx = new EntityBeeFX(world, xCoord + 0.5D, yCoord + 0.75D, zCoord + 0.5D, 0.0f, 0.0f, 0.0f, color); + } else { + double spawnX = xCoord + world.rand.nextInt(areaX * 2) - areaX; + double spawnY = yCoord + world.rand.nextInt(areaY); + double spawnZ = zCoord + world.rand.nextInt(areaZ * 2) - areaZ; + + fx = new EntityBeeFX(world, spawnX, spawnY, spawnZ, 0.0f, 0.0f, 0.0f, color); + } + + fx.setParticleIcon(TextureManager.getInstance().getDefault(icon)); + ParticleRenderer.getInstance().addEffect(fx); + } + + @Override + public void addBeeSwarmFX(String icon, World world, double xCoord, double yCoord, double zCoord, int color) { + if (!Config.enableParticleFX) + return; + + EntityFX fx; + + if (world.rand.nextBoolean()) + fx = new EntityBeeFX(world, xCoord, yCoord, zCoord, 0.0f, 0.0f, 0.0f, color); + else { + + double spawnX = xCoord + world.rand.nextInt(4) - 2; + double spawnY = yCoord + world.rand.nextInt(4) - 2; + double spawnZ = zCoord + world.rand.nextInt(4) - 2; + + fx = new EntityBeeFX(world, spawnX, spawnY, spawnZ, 0.0f, 0.0f, 0.0f, color); + } + + fx.setParticleIcon(TextureManager.getInstance().getDefault(icon)); + ParticleRenderer.getInstance().addEffect(fx); + } + + @Override + public IBlockRenderer getRendererAnalyzer(String gfxBase) { + return new RenderAnalyzer(gfxBase); + } + + @Override + public void addLocalizations() { + Localization.instance.addLocalization("/lang/forestry/apiculture/"); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/proxy/ProxyApiculture.java b/forestry_common/apiculture/forestry/apiculture/proxy/ProxyApiculture.java new file mode 100755 index 000000000..74c627824 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/proxy/ProxyApiculture.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.proxy; + +import net.minecraft.world.World; + +import forestry.core.interfaces.IBlockRenderer; + +public class ProxyApiculture { + public void addBeeHiveFX(String texture, World world, double xCoord, double yCoord, double zCoord, int color, int areaX, int areaY, int areaZ) { + } + + public void addBeeSwarmFX(String texture, World world, double xCoord, double yCoord, double zCoord, int color) { + } + + public IBlockRenderer getRendererAnalyzer(String string) { + return null; + } + + public void addLocalizations() { + } + + public void initializeRendering() { + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/BeeItemRenderer.java b/forestry_common/apiculture/forestry/apiculture/render/BeeItemRenderer.java new file mode 100755 index 000000000..7c4fdf166 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/BeeItemRenderer.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.client.IItemRenderer; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import forestry.api.apiculture.IBee; +import forestry.apiculture.entities.EntityBee; +import forestry.core.proxy.Proxies; +import forestry.plugins.PluginApiculture; + +public class BeeItemRenderer implements IItemRenderer { + + ModelBee model; + EntityBee entity; + + private static float getWingYaw(IBee bee) { + float wingYaw = 1f; + + if(bee.isAlive()) { + long systemTime = System.currentTimeMillis(); + long flapping = systemTime + bee.getIdent().hashCode(); + float flap = (float) (flapping % 1000) / 1000; // 0 to 1 + + wingYaw = getIrregularWingYaw(flapping, flap); + + } + + return wingYaw; + } + + public static float getIrregularWingYaw(long flapping, float flap) { + long irregular = flapping / 1000; + float wingYaw = 1f; + + if(irregular % 11 == 0) { + wingYaw = 0.75f; + } else { + if(irregular % 7 == 0 || irregular % 19 == 0) { + flap *= 8; + flap = flap % 1; + } + wingYaw = getRegularWingYaw(flap); + } + + return wingYaw; + } + + public static float getRegularWingYaw(float flap) { + return flap < 0.5 ? 0.75f + flap : 1.75f - flap; + } + + private IBee initBee(ItemStack item, boolean scaled) { + IBee bee = PluginApiculture.beeInterface.getMember(item); + if(bee == null) + bee = PluginApiculture.beeInterface.templateAsIndividual(PluginApiculture.beeInterface.getDefaultTemplate()); + + if(entity == null) { + entity = new EntityBee(Proxies.common.getClientInstance().theWorld); + } + entity.setSpecies(bee.getGenome().getPrimary()); + entity.setType(PluginApiculture.beeInterface.getType(item)); + /* + if(scaled) + entity.setScale(butterfly.getSize()); + else + entity.setScale(EntityButterfly.DEFAULT_BUTTERFLY_SCALE); + */ + + return bee; + } + + /*private void renderBeeHalo() { + + IIcon background = TextureManager.getInstance().getDefault("habitats/desert"); + float xPos = 1.0f; float yPos = 1.0f; + float width = 1f; float height = 1f; + + Proxies.common.bindTexture(SpriteSheet.ITEMS); + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV((double)(xPos + 0), (double)(yPos + height), 0f, (double)background.getMinU(), (double)background.getMaxV()); + tessellator.addVertexWithUV((double)(xPos + width), (double)(yPos + height), 0f, (double)background.getMaxU(), (double)background.getMaxV()); + tessellator.addVertexWithUV((double)(xPos + width), (double)(yPos + 0), 0f, (double)background.getMaxU(), (double)background.getMinV()); + tessellator.addVertexWithUV((double)(xPos + 0), (double)(yPos + 0), 0f, (double)background.getMinU(), (double)background.getMinV()); + tessellator.draw(); + }*/ + + private void renderBeeItem(IBee bee, float translateX, float translateY, float translateZ) { + float yaw = 1; + float pitch = 1; + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL11.GL_COLOR_MATERIAL); + + GL11.glPushMatrix(); + + GL11.glScalef(2.0f, 2.0f, 2.0f); + GL11.glTranslatef(translateX, translateY, translateZ); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glRotatef(-135.0F, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(-((float) Math.atan(pitch / 40.0F)) * 20.0F, 1.0F, 0.0F, 0.0F); + + entity.renderYawOffset = (float) Math.atan(yaw / 40.0F) * 20.0F; + entity.rotationYaw = (float) Math.atan(yaw / 40.0F) * 40.0F; + entity.rotationPitch = -((float) Math.atan(pitch / 40.0F)) * 20.0F; + entity.rotationYawHead = entity.rotationYaw; + + RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, getWingYaw(bee)); + + GL11.glPopMatrix(); + + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + GL11.glDisable(GL11.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + GL11.glPopAttrib(); + + } + + private void renderBeeInInventory(IBee bee) { + + /* + GL11.glPushMatrix(); + //GL11.glTranslatef(-0.3f, -2.5f, 0f); + GL11.glScalef(-1.0f, 1.0f, 1.0f); + //GL11.glScalef((float)Math.PI / 2, 1.0f, 1.0f); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glRotatef(-135.0F, 0.0F, 1.0F, 0.0F); + //GL11.glRotatef(-((float) Math.atan((double) (1 / 40.0F))) * 20.0F, 1.0F, 0.0F, 0.0F); + renderBeeHalo(); + GL11.glPopMatrix(); + */ + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL11.GL_COLOR_MATERIAL); + RenderHelper.enableStandardItemLighting(); + + GL11.glPushMatrix(); + + GL11.glTranslatef(-0.3f, -2.5f, 0f); + GL11.glScalef(-3.0f, 3.0f, 3.0f); + GL11.glRotatef(32.0F, 0.0F, 1.0F, 0.0F); + GL11.glScalef(1.6f, 1f, 1f); + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + entity.renderYawOffset = 0; + entity.rotationYaw = 0; + entity.rotationPitch = 0; + entity.rotationYawHead = entity.rotationYaw; + + RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, getWingYaw(bee)); + + GL11.glPopMatrix(); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + GL11.glDisable(GL11.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + GL11.glPopAttrib(); + } + + @Override + public boolean handleRenderType(ItemStack item, ItemRenderType type) { + switch (type) { + case ENTITY: + return true; + case EQUIPPED: + return true; + case INVENTORY: + return true; + default: + return false; + } + } + + @Override + public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) { + switch(helper) { + case ENTITY_BOBBING: + case ENTITY_ROTATION: + return false; + default: + return true; + } + } + + @Override + public void renderItem(ItemRenderType type, ItemStack item, Object... data) { + + switch (type) { + case ENTITY: + renderBeeItem(initBee(item, true), 0f, 0f, 0f); + break; + case EQUIPPED: + renderBeeItem(initBee(item, true), 1.0f, 0f, 0.5f); + break; + case INVENTORY: + renderBeeInInventory(initBee(item, false)); + break; + default: + } + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/BlockCandleRenderer.java b/forestry_common/apiculture/forestry/apiculture/render/BlockCandleRenderer.java new file mode 100755 index 000000000..a4af055d1 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/BlockCandleRenderer.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; + +import forestry.apiculture.gadgets.BlockCandle; +import forestry.apiculture.gadgets.TileCandle; +import forestry.core.ForestryClient; + +public class BlockCandleRenderer implements ISimpleBlockRenderingHandler { + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + /*BlockCandle bc = (BlockCandle)block; + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + IIcon iconA = (bc.isLit(meta)) ? bc. + this.renderTorchAtAngle(block, -0.5D, -0.5D, -0.5D, 0.0D, 0.0D, 0); + tessellator.draw();*/ + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + if (block.getRenderType() == ForestryClient.candleRenderId) { + this.renderBlockCandle(world, x, y, z, (BlockCandle)block, modelId, renderer); + } + return true; + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + return false; + } + + @Override + public int getRenderId() { + return ForestryClient.candleRenderId; + } + + public boolean renderBlockCandle(IBlockAccess world, int x, int y, int z, BlockCandle block, int modelId, RenderBlocks renderer) { + int meta = world.getBlockMetadata(x, y, z); + IIcon iconA = block.getTextureFromPassAndMeta(meta, 0); + IIcon iconB = block.getTextureFromPassAndMeta(meta, 1); + meta = meta & 0x7; + TileCandle tc = (TileCandle)world.getTileEntity(x, y, z); + int colour = tc.getColour(); + Tessellator tessellator = Tessellator.instance; + tessellator.setBrightness(world.getLightBrightnessForSkyBlocks(x, y, z, block.getLightValue(world, x, y, z))); + tessellator.setColorOpaque_F(1.0F, 1.0F, 1.0F); + double d0 = 0.4000000059604645D; + double d1 = 0.5D - d0; + double d2 = 0.20000000298023224D; + + if (meta == 1) + { + this.renderCandleAtAngle(iconA, x - d1, y + d2, z, -d0, 0.0D, 0xffffff); + this.renderCandleAtAngle(iconB, x - d1, y + d2, z, -d0, 0.0D, colour); + } + else if (meta == 2) + { + this.renderCandleAtAngle(iconA, x + d1, y + d2, z, d0, 0.0D, 0xffffff); + this.renderCandleAtAngle(iconB, x + d1, y + d2, z, d0, 0.0D, colour); + } + else if (meta == 3) + { + this.renderCandleAtAngle(iconA, x, y + d2, z - d1, 0.0D, -d0, 0xffffff); + this.renderCandleAtAngle(iconB, x, y + d2, z - d1, 0.0D, -d0, colour); + } + else if (meta == 4) + { + this.renderCandleAtAngle(iconA, x, y + d2, z + d1, 0.0D, d0, 0xffffff); + this.renderCandleAtAngle(iconB, x, y + d2, z + d1, 0.0D, d0, colour); + } + else + { + this.renderCandleAtAngle(iconA, x, y, z, 0.0D, 0.0D, 0xffffff); + this.renderCandleAtAngle(iconB, x, y, z, 0.0D, 0.0D, colour); + } + + return true; + } + + public void renderCandleAtAngle(IIcon icon, double x, double y, double z, double par8, double par10, int colour) + { + Tessellator tessellator = Tessellator.instance; + double minU = icon.getMinU(); + double minV = icon.getMinV(); + double maxU = icon.getMaxU(); + double maxV = icon.getMaxV(); + double textureLightTopU = icon.getInterpolatedU(7.0D); + double d10 = icon.getInterpolatedV(6.0D); + double textureLightBottomU = icon.getInterpolatedU(9.0D); + double d12 = icon.getInterpolatedV(8.0D); + //double d13 = (double)icon.getInterpolatedV(7.0D); + double d14 = icon.getInterpolatedV(13.0D); + //double textureLightBottomV = (double)icon.getInterpolatedV(8.0D); + double d16 = icon.getInterpolatedV(15.0D); + x += 0.5D; + z += 0.5D; + double d17 = x - 0.5D; + double d18 = x + 0.5D; + double d19 = z - 0.5D; + double d20 = z + 0.5D; + double d21 = 0.0625D; + double d22 = 0.625D; + tessellator.setColorOpaque_I(colour); + // top quad + tessellator.addVertexWithUV(x + par8 * (1.0D - d22) - d21, y + d22, z + par10 * (1.0D - d22) - d21, textureLightTopU, d10); + tessellator.addVertexWithUV(x + par8 * (1.0D - d22) - d21, y + d22, z + par10 * (1.0D - d22) + d21, textureLightTopU, d12); + tessellator.addVertexWithUV(x + par8 * (1.0D - d22) + d21, y + d22, z + par10 * (1.0D - d22) + d21, textureLightBottomU, d12); + tessellator.addVertexWithUV(x + par8 * (1.0D - d22) + d21, y + d22, z + par10 * (1.0D - d22) - d21, textureLightBottomU, d10); + // -x quad + tessellator.addVertexWithUV(x - d21, y + 1d, d19, minU, minV); + tessellator.addVertexWithUV(x - d21 + par8, y, d19 + par10, minU, maxV); + tessellator.addVertexWithUV(x - d21 + par8, y, d20 + par10, maxU, maxV); + tessellator.addVertexWithUV(x - d21, y + 1d, d20, maxU, minV); + // +x quad + tessellator.addVertexWithUV(x + d21, y + 1.0D, d20, minU, minV); + tessellator.addVertexWithUV(x + par8 + d21, y, d20 + par10, minU, maxV); + tessellator.addVertexWithUV(x + par8 + d21, y, d19 + par10, maxU, maxV); + tessellator.addVertexWithUV(x + d21, y + 1.0D, d19, maxU, minV); + // -z quad + tessellator.addVertexWithUV(d18, y + 1.0D, z - d21, minU, minV); + tessellator.addVertexWithUV(d18 + par8, y, z - d21 + par10, minU, maxV); + tessellator.addVertexWithUV(d17 + par8, y, z - d21 + par10, maxU, maxV); + tessellator.addVertexWithUV(d17, y + 1.0D, z - d21, maxU, minV); + // +z quad + tessellator.addVertexWithUV(d17, y + 1.0D, z + d21, minU, minV); + tessellator.addVertexWithUV(d17 + par8, y, z + d21 + par10, minU, maxV); + tessellator.addVertexWithUV(d18 + par8, y, z + d21 + par10, maxU, maxV); + tessellator.addVertexWithUV(d18, y + 1.0D, z + d21, maxU, minV); + // bottom quad + tessellator.addVertexWithUV(x + d21 + par8, y, z - d21 + par10, textureLightBottomU, d14); + tessellator.addVertexWithUV(x + d21 + par8, y, z + d21 + par10, textureLightBottomU, d16); + tessellator.addVertexWithUV(x - d21 + par8, y, z + d21 + par10, textureLightTopU, d16); + tessellator.addVertexWithUV(x - d21 + par8, y, z - d21 + par10, textureLightTopU, d14); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/EntityBeeFX.java b/forestry_common/apiculture/forestry/apiculture/render/EntityBeeFX.java new file mode 100755 index 000000000..e83e5da90 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/EntityBeeFX.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.world.World; + +public class EntityBeeFX extends EntityFX { + public EntityBeeFX(World world, double x, double y, double z, float motionScaleX, float motionScaleY, float motionScaleZ, int color) { + super(world, x, y, z, 0.0D, 0.0D, 0.0D); + + particleRed = (color >> 16 & 255) / 255.0F; + particleGreen = (color >> 8 & 255) / 255.0F; + particleBlue = (color & 255) / 255.0F; + + this.setSize(0.1F, 0.1F); + this.particleScale *= 0.2F; + this.particleMaxAge = (int) (20.0D / (Math.random() * 0.8D + 0.2D)); + this.noClip = true; + + this.motionX *= 0.119999999552965164D; + this.motionY *= 0.119999999552965164D; + this.motionZ *= 0.119999999552965164D; + } + + /** + * Called to update the entity's position/logic. + */ + @Override + public void onUpdate() { + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + this.moveEntity(this.motionX, this.motionY, this.motionZ); + this.motionX *= 1.08D; + this.motionY *= 1.08D; + this.motionZ *= 1.08D; + + if (this.particleMaxAge-- <= 0) + this.setDead(); + } + + @Override + public void renderParticle(Tessellator tessellator, float f, float f1, float f2, float f3, float f4, float f5) { + float minU = 0; + float maxU = 1; + float minV = 0; + float maxV = 1; + + if (this.particleIcon != null) { + minU = particleIcon.getMinU(); + maxU = particleIcon.getMaxU(); + minV = particleIcon.getMinV(); + maxV = particleIcon.getMaxV(); + } + + float f10 = 0.1F * particleScale; + float f11 = (float) ((prevPosX + (posX - prevPosX) * f) - interpPosX); + float f12 = (float) ((prevPosY + (posY - prevPosY) * f) - interpPosY); + float f13 = (float) ((prevPosZ + (posZ - prevPosZ) * f) - interpPosZ); + + tessellator.setColorRGBA_F(particleRed, particleGreen, particleBlue, 1.0F); + tessellator.addVertexWithUV(f11 - f1 * f10 - f4 * f10, f12 - f2 * f10, f13 - f3 * f10 - f5 * f10, maxU, maxV); + tessellator.addVertexWithUV((f11 - f1 * f10) + f4 * f10, f12 + f2 * f10, (f13 - f3 * f10) + f5 * f10, maxU, minV); + tessellator.addVertexWithUV(f11 + f1 * f10 + f4 * f10, f12 + f2 * f10, f13 + f3 * f10 + f5 * f10, minU, minV); + tessellator.addVertexWithUV((f11 + f1 * f10) - f4 * f10, f12 - f2 * f10, (f13 + f3 * f10) - f5 * f10, minU, maxV); + } + + @Override + public int getBrightnessForRender(float partialTicks) { + return 0x0000f0; + } + + @Override + public int getFXLayer() { + return 2; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/ModelAnalyzer.java b/forestry_common/apiculture/forestry/apiculture/render/ModelAnalyzer.java new file mode 100755 index 000000000..78b65f92b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/ModelAnalyzer.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.util.ResourceLocation; + +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryResource; + +public class ModelAnalyzer extends ModelBase { + + private final ModelRenderer pedestal; + private final ModelRenderer cover; + private final ModelRenderer tower1; + private final ModelRenderer tower2; + + private final ResourceLocation[] textures; + + public ModelAnalyzer(String gfxBase) { + + textures = new ResourceLocation[] { + new ForestryResource(gfxBase + "pedestal.png"), + new ForestryResource(gfxBase + "tower1.png"), + new ForestryResource(gfxBase + "tower2.png"), + }; + + pedestal = new ModelRenderer(this, 0, 0); + pedestal.addBox(-8F, -8F, -8F, 16, 1, 16); + pedestal.setRotationPoint(8, 8, 8); + + cover = new ModelRenderer(this, 0, 0); + cover.addBox(-8F, -8F, -8F, 16, 1, 16); + cover.setRotationPoint(8, 8, 8); + + tower1 = new ModelRenderer(this, 0, 0); + tower1.addBox(-8, -7, -7, 2, 14, 14); + tower1.setRotationPoint(8, 8, 8); + + tower2 = new ModelRenderer(this, 0, 0); + tower2.addBox(6, -7, -7, 2, 14, 14); + tower2.setRotationPoint(8, 8, 8); + + } + + public void render(ForgeDirection orientation, float posX, float posY, float posZ) { + + GL11.glPushMatrix(); + GL11.glDisable(GL11.GL_LIGHTING); + + GL11.glTranslatef(posX, posY, posZ); + float[] angle = { 0, 0, 0 }; + + if (orientation == null) + orientation = ForgeDirection.WEST; + switch (orientation) { + case EAST: + angle[1] = (float) Math.PI / 2; + break; + case WEST: + angle[1] = -(float) Math.PI / 2; + break; + case SOUTH: + break; + case NORTH: + default: + angle[1] = (float) Math.PI; + break; + } + + float factor = (float) (1.0 / 16.0); + + Proxies.common.bindTexture(textures[0]); + + pedestal.rotateAngleX = angle[0]; + pedestal.rotateAngleY = angle[1]; + pedestal.rotateAngleZ = angle[2]; + pedestal.render(factor); + + cover.rotateAngleX = angle[0]; + cover.rotateAngleY = angle[1]; + cover.rotateAngleZ = (float) Math.PI; + cover.render(factor); + + tower1.rotateAngleX = angle[0]; + tower1.rotateAngleY = angle[1]; + tower1.rotateAngleZ = angle[2]; + Proxies.common.bindTexture(textures[1]); + tower1.render(factor); + + tower2.rotateAngleX = angle[0]; + tower2.rotateAngleY = angle[1]; + tower2.rotateAngleZ = angle[2]; + Proxies.common.bindTexture(textures[2]); + tower2.render(factor); + + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glPopMatrix(); + + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/ModelBee.java b/forestry_common/apiculture/forestry/apiculture/render/ModelBee.java new file mode 100755 index 000000000..86a71450f --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/ModelBee.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.util.MathHelper; + +import org.lwjgl.opengl.GL11; + +import forestry.api.apiculture.EnumBeeType; + +public class ModelBee extends ModelBase { + + //fields + ModelRenderer snout; + ModelRenderer torsoWing; + ModelRenderer rump; + ModelRenderer tail; + ModelRenderer tailEnd; + ModelRenderer bridge; + ModelRenderer eyeRight; + ModelRenderer eyeLeft; + ModelRenderer wingLeft; + ModelRenderer wingRight; + ModelRenderer crownQueen; + ModelRenderer crownPrincess; + + EnumBeeType type = EnumBeeType.DRONE; + + public ModelBee() { + textureWidth = 64; + textureHeight = 32; + + snout = new ModelRenderer(this, 18, 11); + snout.addBox(0F, 0F, 0F, 1, 2, 1); + snout.setRotationPoint(0F, 1F, -2F); + snout.setTextureSize(64, 32); + snout.mirror = true; + setRotation(snout, 0F, 0F, 0F); + torsoWing = new ModelRenderer(this, 28, 14); + torsoWing.addBox(0F, 0F, 0F, 3, 3, 1); + torsoWing.setRotationPoint(-1F, 0F, -1F); + torsoWing.setTextureSize(64, 32); + torsoWing.mirror = true; + setRotation(torsoWing, 0F, 0F, 0F); + rump = new ModelRenderer(this, 10, 14); + rump.addBox(-1F, -1F, 0F, 3, 3, 3); + rump.setRotationPoint(0F, 1F, 1F); + rump.setTextureSize(64, 32); + rump.mirror = true; + setRotation(rump, 0F, 0F, 0F); + tail = new ModelRenderer(this, 4, 14); + tail.addBox(0F, 0F, 0F, 2, 2, 1); + tail.setRotationPoint(-0.5F, 0.5333334F, 4F); + tail.setTextureSize(64, 32); + tail.mirror = true; + setRotation(tail, 0F, 0F, 0F); + tailEnd = new ModelRenderer(this, 0, 14); + tailEnd.addBox(0F, 0F, 0F, 1, 1, 1); + tailEnd.setRotationPoint(0F, 1F, 5F); + tailEnd.setTextureSize(64, 32); + tailEnd.mirror = true; + setRotation(tailEnd, 0F, 0F, 0F); + bridge = new ModelRenderer(this, 22, 14); + bridge.addBox(0F, 0F, 0F, 2, 2, 1); + bridge.setRotationPoint(-0.5F, 0.5F, 0F); + bridge.setTextureSize(64, 32); + bridge.mirror = true; + setRotation(bridge, 0F, 0F, 0F); + eyeRight = new ModelRenderer(this, 22, 9); + eyeRight.addBox(0F, 0F, 0F, 1, 1, 1); + eyeRight.setRotationPoint(-1F, 0F, -2F); + eyeRight.setTextureSize(64, 32); + eyeRight.mirror = true; + setRotation(eyeRight, 0F, 0F, 0F); + eyeLeft = new ModelRenderer(this, 18, 9); + eyeLeft.addBox(0F, 0F, 0F, 1, 1, 1); + eyeLeft.setRotationPoint(1F, 0F, -2F); + eyeLeft.setTextureSize(64, 32); + eyeLeft.mirror = true; + setRotation(eyeLeft, 0F, 0F, 0F); + wingLeft = new ModelRenderer(this, 0, 0); + wingLeft.addBox(0F, 0F, 0F, 3, 1, 6); + wingLeft.setRotationPoint(1F, -0.1F, -0.5F); + wingLeft.setTextureSize(64, 32); + wingLeft.mirror = true; + setRotation(wingLeft, 0F, 0.1396263F, 0F); + wingRight = new ModelRenderer(this, 0, 7); + wingRight.addBox(-3F, 0F, 0F, 3, 1, 6); + wingRight.setRotationPoint(0F, -0.1F, -0.5F); + wingRight.setTextureSize(64, 32); + wingRight.mirror = true; + setRotation(wingRight, 0F, -0.1396263F, 0F); + + crownQueen = new ModelRenderer(this, 0, 17); + crownQueen.addBox(0F, 0F, 0F, 2, 1, 2); + crownQueen.setRotationPoint(-0.5F, -1.5F, -1.5F); + crownQueen.setTextureSize(64, 32); + crownQueen.mirror = true; + setRotation(crownQueen, 0F, 0F, 0F); + + crownPrincess = new ModelRenderer(this, 0, 20); + crownPrincess.addBox(0F, 0F, 0F, 2, 1, 2); + crownPrincess.setRotationPoint(-0.5F, -1.5F, -1.5F); + crownPrincess.setTextureSize(64, 32); + crownPrincess.mirror = true; + setRotation(crownPrincess, 0F, 0F, 0F); + + } + + public void setType(EnumBeeType type) { + this.type = type; + } + + public void render(Entity entity, float f, float f1, float swing, float f3, float f4, float f5) { + super.render(entity, f, f1, swing, f3, f4, f5); + //setRotationAngles(f, f1, f2, f3, f4, f5, entity); + + wingRight.rotateAngleZ = MathHelper.cos(swing * 1.3F) * (float)Math.PI * 0.25F; + wingLeft.rotateAngleZ = -wingRight.rotateAngleZ; + + GL11.glPushMatrix(); + float scale = 0.75f; + GL11.glScalef(scale, scale, scale); + GL11.glTranslatef(0.0F, (12.0f / scale) * f5, 0.0F); + + snout.render(f5); + torsoWing.render(f5); + rump.render(f5); + tail.render(f5); + tailEnd.render(f5); + bridge.render(f5); + eyeRight.render(f5); + eyeLeft.render(f5); + wingLeft.render(f5); + wingRight.render(f5); + + if(type == EnumBeeType.PRINCESS) + crownPrincess.render(f5); + else if(type == EnumBeeType.QUEEN) + crownQueen.render(f5); + + GL11.glPopMatrix(); + } + + private void setRotation(ModelRenderer model, float x, float y, float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) { + super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/ParticleRenderer.java b/forestry_common/apiculture/forestry/apiculture/render/ParticleRenderer.java new file mode 100755 index 000000000..e6f0d882c --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/ParticleRenderer.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.EntityLivingBase; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import cpw.mods.fml.common.gameevent.TickEvent.Phase; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.WorldEvent; + +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class ParticleRenderer { + private static final String name = "forestry-particles"; + + // singleton getter >> + + public static synchronized ParticleRenderer getInstance() { + if (instance == null) instance = new ParticleRenderer(); + + return instance; + } + + private static ParticleRenderer instance = null; + + // << singleton getter + + + public synchronized void addEffect(EntityFX particle) { + if (lazyAdd) { + newParticles.add(particle); + } else { + particles.add(particle); + } + } + + + // forge + fml handlers >> + + @SubscribeEvent + public void onRenderWorldLast(RenderWorldLastEvent event) { + render(event.partialTicks); + } + + @SubscribeEvent + public void onWorldUnload(WorldEvent.Unload event) { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + synchronized (this) { + particles.clear(); + } + } + } + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase == Phase.END) { + update(); + } + } + + // << forge + fml handlers + + private ParticleRenderer() { + MinecraftForge.EVENT_BUS.register(this); + FMLCommonHandler.instance().bus().register(this); + } + + private synchronized void update() { + Minecraft.getMinecraft().mcProfiler.startSection(name+"-update"); + + lazyAdd = true; + + for (Iterator it = particles.iterator(); it.hasNext(); ) { + EntityFX particle = it.next(); + + particle.onUpdate(); + + if (particle.isDead) { + it.remove(); + } + } + + lazyAdd = false; + particles.addAll(newParticles); + newParticles.clear(); + + Minecraft.getMinecraft().mcProfiler.endSection(); + } + + private synchronized void render(float partialTicks) { + Minecraft.getMinecraft().mcProfiler.startSection(name+"-render"); + + float rotationX = ActiveRenderInfo.rotationX; + float rotationZ = ActiveRenderInfo.rotationZ; + float rotationYZ = ActiveRenderInfo.rotationYZ; + float rotationXY = ActiveRenderInfo.rotationXY; + float rotationXZ = ActiveRenderInfo.rotationXZ; + + EntityLivingBase player = Minecraft.getMinecraft().renderViewEntity; + EntityFX.interpPosX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks; + EntityFX.interpPosY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks; + EntityFX.interpPosZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks; + + // bind the texture + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationItemsTexture); + + // save the old gl state + GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); + + // gl states/settings for drawing + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F); + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + + for (EntityFX particle : particles) { + tessellator.setBrightness(particle.getBrightnessForRender(partialTicks)); + + particle.renderParticle(tessellator, partialTicks, rotationX, rotationXZ, rotationZ, rotationYZ, rotationXY); + } + + tessellator.draw(); + + // restore previous gl state + GL11.glPopAttrib(); + + Minecraft.getMinecraft().mcProfiler.endSection(); + } + + private boolean lazyAdd = false; + private final List particles = new ArrayList(); + private final List newParticles = new ArrayList(); +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/RenderBee.java b/forestry_common/apiculture/forestry/apiculture/render/RenderBee.java new file mode 100755 index 000000000..798178e0e --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/RenderBee.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; + +import forestry.apiculture.entities.EntityBee; + +public class RenderBee extends RenderLiving { + + ModelBee beeModel; + + public RenderBee() { + super(new ModelBee(), 0.15f); + beeModel = (ModelBee)mainModel; + } + + public void renderBee(EntityBee entity, double posX, double posY, double posZ, float par8, float par9) { + beeModel.setType(entity.getType()); + this.doRender(entity, posX, posY, posZ, par8, par9); + } + + @Override + public void doRender(Entity entity, double posX, double posY, double posZ, float par8, float par9) { + renderBee((EntityBee) entity, posX, posY, posZ, par8, par9); + } + + @Override + protected ResourceLocation getEntityTexture(Entity entity) { + return ((EntityBee)entity).getTexture(); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/render/TextureBiomefinder.java b/forestry_common/apiculture/forestry/apiculture/render/TextureBiomefinder.java new file mode 100755 index 000000000..69e397d78 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/render/TextureBiomefinder.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.render; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; + +public class TextureBiomefinder extends TextureAtlasSprite { + + private static TextureBiomefinder instance; + public static TextureBiomefinder getInstance() { return instance; } + + private ChunkCoordinates targetBiome; + + public double currentAngle; + public double angleDelta; + + public TextureBiomefinder() { + super("biomefinder"); + instance = this; + } + + public void setTargetCoordinates(ChunkCoordinates coordinates) { + this.targetBiome = coordinates; + } + + @Override + public void updateAnimation() { + Minecraft minecraft = Minecraft.getMinecraft(); + + if (minecraft.theWorld != null && minecraft.thePlayer != null) + updateCompass(minecraft.theWorld, minecraft.thePlayer.posX, minecraft.thePlayer.posZ, minecraft.thePlayer.rotationYaw, false, true); + else + updateCompass((World)null, 0.0d, 0.0d, 0.0d, true, true); + } + + public void updateCompass(World world, double playerX, double playerZ, double playerYaw, boolean par8, boolean hasSpin) { + + double targetAngle = 0.0d; + + if(world == null || targetBiome == null) { + // No target has the locator spinning wildly. + targetAngle = Math.random() * Math.PI * 2.0d; + } else { + double xPart = targetBiome.posX - playerX; + double yPart = targetBiome.posZ - playerZ; + targetAngle = (playerYaw - 90.0f) * Math.PI / 180.0d - Math.atan2(yPart, xPart); + } + + if(!hasSpin) { + currentAngle = targetAngle; + } else { + double angleChange; + + for (angleChange = targetAngle - currentAngle; angleChange < -Math.PI; angleChange += (Math.PI * 2D)) + ; + + while (angleChange >= Math.PI) + angleChange -= (Math.PI * 2D); + + if (angleChange < -1.0D) + angleChange = -1.0D; + + if (angleChange > 1.0D) + angleChange = 1.0D; + + this.angleDelta += angleChange * 0.1D; + this.angleDelta *= 0.8D; + this.currentAngle += this.angleDelta; + } + + int i; + + for (i = (int)((this.currentAngle / (Math.PI * 2D) + 1.0d) * this.framesTextureData.size()) % this.framesTextureData.size(); i < 0; i = (i + this.framesTextureData.size()) % this.framesTextureData.size()) + ; + + if (i != this.frameCounter) { + this.frameCounter = i; + TextureUtil.uploadTextureMipmap((int[][])this.framesTextureData.get(this.frameCounter), this.width, this.height, this.originX, this.originY, false, false); + } + + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/trigger/TriggerNoFrames.java b/forestry_common/apiculture/forestry/apiculture/trigger/TriggerNoFrames.java new file mode 100755 index 000000000..7af0d63e3 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/trigger/TriggerNoFrames.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.trigger; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.apiculture.gadgets.TileApiary; +import forestry.core.triggers.Trigger; + +public class TriggerNoFrames extends Trigger { + + public TriggerNoFrames() { + super("noFrames"); + } + + /** + * Return true if the tile given in parameter activates the trigger, given the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof TileApiary)) + return false; + + for (int i = TileApiary.SLOT_FRAMES_1; i < TileApiary.SLOT_FRAMES_1 + TileApiary.SLOT_FRAMES_COUNT; i++) + if (((TileApiary) tile).getStackInSlot(i) == null) + continue; + else + return false; + + return true; + + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/ComponentVillageBeeHouse.java b/forestry_common/apiculture/forestry/apiculture/worldgen/ComponentVillageBeeHouse.java new file mode 100755 index 000000000..52e2cf883 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/ComponentVillageBeeHouse.java @@ -0,0 +1,378 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.StructureComponent; +import net.minecraft.world.gen.structure.StructureVillagePieces; + +import net.minecraftforge.common.ChestGenHooks; + +import forestry.api.apiculture.BeeManager; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.FlowerManager; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.EnumTolerance; +import forestry.apiculture.gadgets.TileBeehouse; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.ClimateHelper; +import forestry.core.utils.StackUtils; +import forestry.plugins.PluginApiculture; + +public class ComponentVillageBeeHouse extends StructureVillagePieces.House1 { + + protected ItemStack[] buildingBlocks = new ItemStack[] { new ItemStack(ForestryBlock.planks1, 1, 15), new ItemStack(Blocks.log, 1, 0), }; + protected int averageGroundLevel = -1; + protected boolean isInDesert = false; + protected boolean hasChest = false; + + public ComponentVillageBeeHouse() { + // Populate buildingblocks with some defaults so it doesn't explode. + buildingBlocks[0] = new ItemStack(ForestryBlock.planks1); + buildingBlocks[1] = new ItemStack(ForestryBlock.log1); + } + + public ComponentVillageBeeHouse(StructureVillagePieces.Start startPiece, int componentType, Random random, StructureBoundingBox boundingBox, int coordBaseMode) { + super(startPiece, componentType, random, boundingBox, coordBaseMode); + + isInDesert = startPiece.inDesert; + + buildingBlocks[0] = new ItemStack(ForestryBlock.planks1, 1, random.nextInt(16)); + + Block woodBlock; + switch (random.nextInt(4)) { + case 1: + woodBlock = ForestryBlock.log2; + break; + case 2: + woodBlock = ForestryBlock.log3; + break; + case 3: + woodBlock = ForestryBlock.log4; + break; + default: + woodBlock = ForestryBlock.log1; + break; + } + + buildingBlocks[1] = new ItemStack(woodBlock, 1, random.nextInt(4)); + } + + /*@Override + protected void func_143012_a(NBTTagCompound par1nbtTagCompound) { + super.func_143012_a(par1nbtTagCompound); + par1nbtTagCompound.setBoolean("Chest", this.hasChest); + } + + @Override + protected void func_143011_b(NBTTagCompound par1nbtTagCompound) { + super.func_143011_b(par1nbtTagCompound); + this.hasChest = par1nbtTagCompound.getBoolean("Chest"); + }*/ + + @SuppressWarnings("rawtypes") + public static ComponentVillageBeeHouse buildComponent(StructureVillagePieces.Start startPiece, List par1List, Random random, int par3, int par4, int par5, + int par6, int par7) { + StructureBoundingBox bbox = StructureBoundingBox.getComponentToAddBoundingBox(par3, par4, par5, 0, 0, 0, 9, 9, 6, par6); + return canVillageGoDeeper(bbox) && StructureComponent.findIntersecting(par1List, bbox) == null ? new ComponentVillageBeeHouse(startPiece, par7, random, + bbox, par6) : null; + } + + @Override + public boolean addComponentParts(World world, Random random, StructureBoundingBox structBoundingBox) { + + if (this.averageGroundLevel < 0) { + this.averageGroundLevel = this.getAverageGroundLevel(world, structBoundingBox); + if (this.averageGroundLevel < 0) + return true; + + this.boundingBox.offset(0, this.averageGroundLevel - this.boundingBox.maxY + 8 - 1, 0); + } + + this.fillWithBlocks(world, structBoundingBox, 1, 1, 1, 7, 4, 4, Blocks.air, Blocks.air, false); + this.fillWithBlocks(world, structBoundingBox, 2, 1, 6, 8, 4, 10, Blocks.air, Blocks.air, false); + + // Garden + buildGarden(world, structBoundingBox); + + // Garden fence + this.fillWithBlocks(world, structBoundingBox, 1, 1, 6, 1, 1, 10, Blocks.fence, Blocks.fence, false); + this.fillWithBlocks(world, structBoundingBox, 8, 1, 6, 8, 1, 10, Blocks.fence, Blocks.fence, false); + this.fillWithBlocks(world, structBoundingBox, 2, 1, 10, 7, 1, 10, Blocks.fence, Blocks.fence, false); + + // Flowers + plantFlowerGarden(world, structBoundingBox, 2, 1, 5, 7, 1, 9); + + // Apiaries + buildApiaries(world, structBoundingBox, 3, 1, 4, 6, 1, 8); + + // Floor + this.fillWithBlocks(world, structBoundingBox, 1, 0, 1, 7, 0, 4, Blocks.planks, Blocks.planks, false); + + this.fillWithBlocks(world, structBoundingBox, 0, 0, 0, 0, 3, 5, Blocks.cobblestone, Blocks.cobblestone, false); + this.fillWithBlocks(world, structBoundingBox, 8, 0, 0, 8, 3, 5, Blocks.cobblestone, Blocks.cobblestone, false); + this.fillWithBlocks(world, structBoundingBox, 1, 0, 0, 7, 1, 0, Blocks.cobblestone, Blocks.cobblestone, false); + this.fillWithBlocks(world, structBoundingBox, 1, 0, 5, 7, 1, 5, Blocks.cobblestone, Blocks.cobblestone, false); + + this.fillBoxWith(world, structBoundingBox, 1, 2, 0, 7, 3, 0, buildingBlocks[0], false); + this.fillBoxWith(world, structBoundingBox, 1, 2, 5, 7, 3, 5, buildingBlocks[0], false); + this.fillBoxWith(world, structBoundingBox, 0, 4, 1, 8, 4, 1, buildingBlocks[0], false); + this.fillBoxWith(world, structBoundingBox, 0, 4, 4, 8, 4, 4, buildingBlocks[0], false); + this.fillBoxWith(world, structBoundingBox, 0, 5, 2, 8, 5, 3, buildingBlocks[0], false); + + this.placeBlockAtCurrentPosition(world, buildingBlocks[0], 0, 4, 2, structBoundingBox); + this.placeBlockAtCurrentPosition(world, buildingBlocks[0], 0, 4, 3, structBoundingBox); + this.placeBlockAtCurrentPosition(world, buildingBlocks[0], 8, 4, 2, structBoundingBox); + this.placeBlockAtCurrentPosition(world, buildingBlocks[0], 8, 4, 3, structBoundingBox); + + buildRoof(world, structBoundingBox); + + this.placeBlockAtCurrentPosition(world, buildingBlocks[1], 0, 2, 1, structBoundingBox); + this.placeBlockAtCurrentPosition(world, buildingBlocks[1], 0, 2, 4, structBoundingBox); + this.placeBlockAtCurrentPosition(world, buildingBlocks[1], 8, 2, 1, structBoundingBox); + this.placeBlockAtCurrentPosition(world, buildingBlocks[1], 8, 2, 4, structBoundingBox); + + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 0, 2, 2, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 0, 2, 3, structBoundingBox); + + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 8, 2, 2, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 8, 2, 3, structBoundingBox); + + // Windows garden side + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 2, 2, 5, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 3, 2, 5, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 4, 2, 5, structBoundingBox); + + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 5, 2, 0, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.glass_pane, 0, 6, 2, 5, structBoundingBox); + + // Table/Bench + if (random.nextInt(10) < 1) { + this.placeBlockAtCurrentPosition(world, new ItemStack(ForestryBlock.core, 1, Defaults.DEFINITION_ESCRITOIRE_META), 1, 1, 3, structBoundingBox); + } + else { + this.placeBlockAtCurrentPosition(world, buildingBlocks[0], 1, 1, 3, structBoundingBox); + } + + this.placeBlockAtCurrentPosition(world, Blocks.air, 0, 2, 1, 0, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.air, 0, 2, 2, 0, structBoundingBox); + this.placeDoorAtCurrentPosition(world, structBoundingBox, random, 2, 1, 0, this.getMetadataWithOffset(Blocks.wooden_door, 1)); + + if (isAirBlockAtCurrentPosition(world, 2, 0, -1, structBoundingBox) + && !isAirBlockAtCurrentPosition(world, 2, -1, -1, structBoundingBox)) + this.placeBlockAtCurrentPosition(world, Blocks.stone_stairs, + this.getMetadataWithOffset(Blocks.stone_stairs, 3), 2, 0, -1, structBoundingBox); + + this.placeBlockAtCurrentPosition(world, Blocks.air, 0, 6, 1, 5, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.air, 0, 6, 2, 5, structBoundingBox); + + // Candles / Lighting + this.placeBlockAtCurrentPosition(world, Blocks.torch, 0, 2, 3, 4, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.torch, 0, 6, 3, 4, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.torch, 0, 2, 3, 1, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.torch, 0, 6, 3, 1, structBoundingBox); + + this.placeDoorAtCurrentPosition(world, structBoundingBox, random, 6, 1, 5, this.getMetadataWithOffset(Blocks.wooden_door, 1)); + + for (int i = 0; i < 5; ++i) + for (int j = 0; j < 9; ++j) { + this.clearCurrentPositionBlocksUpwards(world, j, 7, i, structBoundingBox); + this.func_151554_b(world, Blocks.cobblestone, 0, j, -1, i, structBoundingBox); + } + + this.generateStructureChestContents(world, structBoundingBox, random, 7, 1, 4, + ChestGenHooks.getItems(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, random), + random.nextInt(4) + random.nextInt(4) + 5); + + spawnVillagers(world, boundingBox, 7, 1, 1, 2); + + return true; + } + + private void buildRoof(World world, StructureBoundingBox structBoundingBox) { + int rotatedMetaDoor = this.getMetadataWithOffset(Blocks.oak_stairs, 3); + int rotatedMetaGarden = this.getMetadataWithOffset(Blocks.oak_stairs, 2); + + for (int i = -1; i <= 2; ++i) + for (int j = 0; j <= 8; ++j) { + this.placeBlockAtCurrentPosition(world, Blocks.oak_stairs, rotatedMetaDoor, j, 4 + i, i, structBoundingBox); + this.placeBlockAtCurrentPosition(world, Blocks.oak_stairs, rotatedMetaGarden, j, 4 + i, 5 - i, structBoundingBox); + } + } + + protected void buildGarden(World world, StructureBoundingBox box) { + + Block ground = Blocks.dirt; + if (isInDesert) + ground = Blocks.sand; + + for (int i = 1; i <= 8; i++) + for (int j = 6; j <= 10; j++) + func_151554_b(world, ground, 0, i, 0, j, box); + } + + protected void plantFlowerGarden(World world, StructureBoundingBox box, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + + if (isInDesert) { + placeBlockAtCurrentPosition(world, Blocks.cactus, 0, 4, 1, 7, box); + return; + } + + for (int i = minY; i <= maxY; ++i) + for (int j = minX; j <= maxX; ++j) + for (int k = minZ; k <= maxZ; ++k) + if (world.rand.nextBoolean()) { + int xCoord = this.getXWithOffset(j, k); + int yCoord = this.getYWithOffset(i); + int zCoord = this.getZWithOffset(j, k); + + if (!Blocks.red_flower.canBlockStay(world, xCoord, yCoord, zCoord)) + continue; + + ItemStack flower = FlowerManager.plainFlowers.get(world.rand.nextInt(FlowerManager.plainFlowers.size())); + this.placeBlockAtCurrentPosition(world, flower, j, i, k, box); + } + } + + protected void buildApiaries(World world, StructureBoundingBox box, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + populateApiary(world, box, 3, 1, 8); + populateApiary(world, box, 6, 1, 8); + } + + private void populateApiary(World world, StructureBoundingBox box, int x, int y, int z) { + int xCoord = this.getXWithOffset(x, z); + int yCoord = this.getYWithOffset(y); + int zCoord = this.getZWithOffset(x, z); + + if (box.isVecInside(xCoord, yCoord, zCoord) && world.getBlock(xCoord, yCoord, zCoord) != ForestryBlock.apiculture + && world.blockExists(xCoord, yCoord - 1, zCoord)) { + + world.setBlock(xCoord, yCoord, zCoord, ForestryBlock.apiculture, Defaults.DEFINITION_APIARY_META, + Defaults.FLAG_BLOCK_SYNCH); + ForestryBlock.apiculture.onBlockAdded(world, xCoord, yCoord, zCoord); + + TileEntity tile = world.getTileEntity(xCoord, yCoord, zCoord); + if (tile instanceof TileBeehouse) { + TileBeehouse apiary = ((TileBeehouse) tile); + apiary.initialize(); + apiary.setSlotContents(TileBeehouse.SLOT_QUEEN, + PluginApiculture.beeInterface.getMemberStack(getVillageBee(world, xCoord, yCoord, zCoord), EnumBeeType.PRINCESS.ordinal())); + apiary.setSlotContents(TileBeehouse.SLOT_DRONE, + PluginApiculture.beeInterface.getMemberStack(getVillageBee(world, xCoord, yCoord, zCoord), EnumBeeType.DRONE.ordinal())); + + for (int i = TileBeehouse.SLOT_FRAMES_1; i < TileBeehouse.SLOT_FRAMES_1 + TileBeehouse.SLOT_FRAMES_COUNT; i++) { + float roll = world.rand.nextFloat(); + if (roll < 0.2f) + apiary.setSlotContents(i, ForestryItem.frameUntreated.getItemStack()); + else if (roll < 0.4f) + apiary.setSlotContents(i, ForestryItem.frameImpregnated.getItemStack()); + else if (roll < 0.6) + apiary.setSlotContents(i, ForestryItem.frameProven.getItemStack()); + } + + } + } + } + + private IBee getVillageBee(World world, int xCoord, int yCoord, int zCoord) { + + // Get current biome + BiomeGenBase biome = world.getBiomeGenForCoords(xCoord, zCoord); + + ArrayList candidates; + if (BeeManager.villageBees[1] != null && BeeManager.villageBees[1].size() > 0 && world.rand.nextDouble() < 0.2) + candidates = BeeManager.villageBees[1]; + else + candidates = BeeManager.villageBees[0]; + + // Add bees that can live in this environment + ArrayList valid = new ArrayList(); + for (IBeeGenome genome : candidates) + if (checkBiomeHazard(genome, biome.temperature, biome.rainfall)) + valid.add(genome); + + // No valid ones found, return any of the common ones. + if (valid.isEmpty()) + return PluginApiculture.beeInterface.getBee(world, BeeManager.villageBees[0].get(world.rand.nextInt(BeeManager.villageBees[0].size()))); + + return PluginApiculture.beeInterface.getBee(world, valid.get(world.rand.nextInt(valid.size()))); + } + + private boolean checkBiomeHazard(IBeeGenome genome, float temperature, float humidity) { + + EnumTemperature beeTemperature = genome.getPrimary().getTemperature(); + EnumTolerance temperatureTolerance = genome.getToleranceTemp(); + + ArrayList toleratedTemperatures = ClimateHelper.getToleratedTemperature(beeTemperature, temperatureTolerance); + boolean validTemp = false; + + validTemp = toleratedTemperatures.contains(EnumTemperature.getFromValue(temperature)); + + if (!validTemp) + return false; + + EnumHumidity beeHumidity = genome.getPrimary().getHumidity(); + EnumTolerance humidityTolerance = genome.getToleranceHumid(); + + ArrayList toleratedHumidity = ClimateHelper.getToleratedHumidity(beeHumidity, humidityTolerance); + + boolean validHumidity = false; + + validHumidity = toleratedHumidity.contains(EnumHumidity.getFromValue(humidity)); + + return validHumidity; + } + + protected void fillBoxWith(World world, StructureBoundingBox box, int par3, int par4, int par5, int par6, int par7, int par8, ItemStack buildingBlock, + boolean replace) { + + for (int var14 = par4; var14 <= par7; ++var14) + for (int var15 = par3; var15 <= par6; ++var15) + for (int var16 = par5; var16 <= par8; ++var16) + if (!replace || !isAirBlockAtCurrentPosition(world, var15, var14, var16, box)) + this.placeBlockAtCurrentPosition(world, buildingBlock, var15, var14, var16, box); + } + + protected void placeBlockAtCurrentPosition(World world, ItemStack buildingBlock, int par4, int par5, int par6, StructureBoundingBox par7StructureBoundingBox) { + int var8 = this.getXWithOffset(par4, par6); + int var9 = this.getYWithOffset(par5); + int var10 = this.getZWithOffset(par4, par6); + + if (par7StructureBoundingBox.isVecInside(var8, var9, var10)) + world.setBlock(var8, var9, var10, StackUtils.getBlock(buildingBlock), buildingBlock.getItemDamage(), Defaults.FLAG_BLOCK_SYNCH); + } + + @Override + protected int getVillagerType(int villagerCount) { + if (villagerCount <= 0) + return Defaults.ID_VILLAGER_BEEKEEPER; + else + return Defaults.ID_VILLAGER_LUMBERJACK; + } + + private boolean isAirBlockAtCurrentPosition(World world, int x, int y, int z, StructureBoundingBox box) { + // TODO: replace with isAir + return getBlockAtCurrentPosition(world, x, y, z, box) == Blocks.air; + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/HiveDecorator.java b/forestry_common/apiculture/forestry/apiculture/worldgen/HiveDecorator.java new file mode 100755 index 000000000..edfd09248 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/HiveDecorator.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.world.World; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +import net.minecraftforge.common.util.EnumHelper; +import net.minecraftforge.event.terraingen.PopulateChunkEvent; +import net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType; +import net.minecraftforge.event.terraingen.TerrainGen; + +/** + * + * @author CovertJaguar + */ +public class HiveDecorator { + + public static final EventType EVENT_TYPE = EnumHelper.addEnum(EventType.class, "FORESTRY_HIVES", new Class[0], new Object[0]); + private static HiveDecorator instance; + private final WorldGenHiveForest forest = new WorldGenHiveForest(); + private final WorldGenHiveJungle jungle = new WorldGenHiveJungle(); + private final WorldGenHiveMeadows meadows = new WorldGenHiveMeadows(); + private final WorldGenHiveParched parched = new WorldGenHiveParched(); + private final WorldGenHiveEnd end = new WorldGenHiveEnd(); + private final WorldGenHiveSnow snow = new WorldGenHiveSnow(); + private final WorldGenHiveSwamp swamp = new WorldGenHiveSwamp(); + + public static HiveDecorator instance() { + if (instance == null) { + instance = new HiveDecorator(); + } + return instance; + } + + private HiveDecorator() { + } + + @SubscribeEvent + public void generate(PopulateChunkEvent.Post event) { + if (!TerrainGen.populate(event.chunkProvider, event.world, event.rand, event.chunkX, event.chunkZ, event.hasVillageGenerated, EVENT_TYPE)) { + return; + } + decorateHives(event.world, event.rand, event.chunkX * 16, event.chunkZ * 16); + } + + private void decorateHives(World world, Random rand, int worldX, int worldZ) { + genHive(world, rand, worldX, worldZ, 42, 3, forest); + genHive(world, rand, worldX, worldZ, 62, 4, jungle); + genHive(world, rand, worldX, worldZ, 42, 1, meadows); + genHive(world, rand, worldX, worldZ, 42, 1, parched); + genHive(world, rand, worldX, worldZ, 42, 4, end); + genHive(world, rand, worldX, worldZ, 42, 2, snow); + genHive(world, rand, worldX, worldZ, 42, 2, swamp); + } + + private void genHive(World world, Random rand, int worldX, int worldZ, int height, int attempts, WorldGenHive gen) { + for (int i = 0; i < attempts; i++) { + int randPosX = worldX + rand.nextInt(16); + int randPosY = height + rand.nextInt(50); + int randPosZ = worldZ + rand.nextInt(16); + if (gen.generate(world, rand, randPosX, randPosY, randPosZ)) + return; + } + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHive.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHive.java new file mode 100755 index 000000000..3b80ad7cb --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHive.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import net.minecraftforge.common.IPlantable; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; + +public abstract class WorldGenHive extends WorldGenerator { + + @Override + public abstract boolean generate(World world, Random random, int x, int y, int z); + + protected boolean tryPlaceTreeHive(World world, int x, int y, int z, int meta) { + if (!world.isAirBlock(x, y, z)) + return false; + + Block b = world.getBlock(x, y + 1, z); + if (b == null || !b.isLeaves(world, x, y + 1, z)) + return false; + + if (world.isAirBlock(x, y - 1, z)) { + setHive(world, x, y, z, meta); + return true; + } + return false; + } + + protected boolean tryPlaceGroundHive(World world, int x, int y, int z, int meta, Block... groundBlocks) { + if (!world.isAirBlock(x, y, z)) { + Block block = world.getBlock(x, y, z); + if (block != Blocks.snow_layer && !(block instanceof IPlantable)) + return false; + } + + if (!world.isAirBlock(x, y + 1, z)) + return false; + + if (isAcceptableBlock(world, x, y - 1, z, groundBlocks)) { + setHive(world, x, y, z, meta); + return true; + } + + return false; + } + + private boolean isAcceptableBlock(World world, int x, int y, int z, Block... blocks) { + Block block = world.getBlock(x, y, z); + if (block == null) + return false; + for (Block testBlock : blocks) { + if (block.isReplaceableOreGen(world, x, y, z, testBlock)) + return true; + } + return false; + } + + protected void setHive(World world, int x, int y, int z, int meta) { + boolean placed = world.setBlock(x, y, z, ForestryBlock.beehives, meta, Defaults.FLAG_BLOCK_SYNCH); + if (!placed) + return; + + if (world.getBlock(x, y, z) != ForestryBlock.beehives) + return; + + ForestryBlock.beehives.onBlockAdded(world, x, y, z); + world.markBlockForUpdate(x, y, z); + + postGen(world, x, y, z, meta); + } + + protected void postGen(World world, int x, int y, int z, int meta) { + ForestryBlock.beehives.onBlockPlaced(world, x, y, z, 0, 0.0f, 0.0f, 0.0f, meta); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveEnd.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveEnd.java new file mode 100755 index 000000000..e0c51f334 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveEnd.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +public class WorldGenHiveEnd extends WorldGenHive { + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (biome.biomeID != BiomeGenBase.sky.biomeID) + return false; + + return tryPlaceGroundHive(world, x, y, z, 5, Blocks.end_stone); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveForest.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveForest.java new file mode 100755 index 000000000..f2d6d43b0 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveForest.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public class WorldGenHiveForest extends WorldGenHive { + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (EnumTemperature.getFromValue(biome.temperature) != EnumTemperature.NORMAL || + EnumHumidity.getFromValue(biome.rainfall) != EnumHumidity.NORMAL) + return false; + + return tryPlaceTreeHive(world, x, y, z, 1); + } + +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveJungle.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveJungle.java new file mode 100755 index 000000000..8edd94056 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveJungle.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public class WorldGenHiveJungle extends WorldGenHive { + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (EnumTemperature.getFromValue(biome.temperature) != EnumTemperature.WARM + || EnumHumidity.getFromValue(biome.rainfall) != EnumHumidity.DAMP) + return false; + + return tryPlaceTreeHive(world, x, y, z, 4); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveMeadows.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveMeadows.java new file mode 100755 index 000000000..23623a8b9 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveMeadows.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public class WorldGenHiveMeadows extends WorldGenHive { + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (EnumTemperature.getFromValue(biome.temperature) != EnumTemperature.NORMAL + || EnumHumidity.getFromValue(biome.rainfall) != EnumHumidity.NORMAL) + return false; + + return tryPlaceGroundHive(world, x, y, z, 2, Blocks.dirt, Blocks.grass); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveParched.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveParched.java new file mode 100755 index 000000000..95ac4f354 --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveParched.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public class WorldGenHiveParched extends WorldGenHive { + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (EnumTemperature.getFromValue(biome.temperature) != EnumTemperature.HOT + || EnumHumidity.getFromValue(biome.rainfall) != EnumHumidity.ARID) + return false; + + return tryPlaceGroundHive(world, x, y, z, 3, Blocks.sand, Blocks.sandstone); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSnow.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSnow.java new file mode 100755 index 000000000..ab6eaf09b --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSnow.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.EnumTemperature; + +public class WorldGenHiveSnow extends WorldGenHive { + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (EnumTemperature.getFromValue(biome.temperature) != EnumTemperature.ICY + && EnumTemperature.getFromValue(biome.temperature) != EnumTemperature.COLD) + return false; + + if (tryPlaceGroundHive(world, x, y, z, 6, Blocks.dirt, Blocks.grass)) { + world.setBlock(x, y + 1, z, Blocks.snow_layer, 0, 0); + return true; + } + + return false; + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamer.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamer.java new file mode 100755 index 000000000..dc35f009e --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamer.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import forestry.apiculture.gadgets.TileSwarm; + +/** + * + * @author CovertJaguar + */ +public class WorldGenHiveSwamer extends WorldGenHive { + + private ItemStack[] bees; + + public WorldGenHiveSwamer(ItemStack[] bees) { + this.bees = bees; + } + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + if (world.blockExists(x, y, z) && world.isAirBlock(x, y, z) && (!world.isAirBlock(x, y - 1, z) || !world.isAirBlock(x, y + 1, z))) { + setHive(world, x, y, z, 8); + return true; + } + + return false; + } + + @Override + protected void postGen(World world, int x, int y, int z, int meta) { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile instanceof TileSwarm) + ((TileSwarm) tile).setContained(bees); + } +} diff --git a/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamp.java b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamp.java new file mode 100755 index 000000000..f7fbb286f --- /dev/null +++ b/forestry_common/apiculture/forestry/apiculture/worldgen/WorldGenHiveSwamp.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.apiculture.worldgen; + +import java.util.Random; + +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public class WorldGenHiveSwamp extends WorldGenHive { + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (EnumTemperature.getFromValue(biome.temperature) != EnumTemperature.NORMAL + || EnumHumidity.getFromValue(biome.rainfall) != EnumHumidity.DAMP) + return false; + + return tryPlaceGroundHive(world, x, y, z, 7, Blocks.dirt, Blocks.grass); + } +} diff --git a/forestry_common/apiculture/forestry/plugins/PluginApiculture.java b/forestry_common/apiculture/forestry/plugins/PluginApiculture.java new file mode 100755 index 000000000..792727b8a --- /dev/null +++ b/forestry_common/apiculture/forestry/plugins/PluginApiculture.java @@ -0,0 +1,1218 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.command.ICommand; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.Potion; +import net.minecraft.util.IIcon; +import net.minecraft.util.WeightedRandomChestContent; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.common.registry.GameData; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.common.registry.VillagerRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.common.ChestGenHooks; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.oredict.OreDictionary; + +import forestry.api.apiculture.BeeManager; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.FlowerManager; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeRoot; +import forestry.api.apiculture.IHiveDrop; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.PluginInfo; +import forestry.api.core.Tabs; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IClassification.EnumClassLevel; +import forestry.api.recipes.RecipeManagers; +import forestry.apiculture.CommandBeekeepingMode; +import forestry.apiculture.CommandGiveBee; +import forestry.apiculture.FlowerProviderCacti; +import forestry.apiculture.FlowerProviderEnd; +import forestry.apiculture.FlowerProviderGourd; +import forestry.apiculture.FlowerProviderJungle; +import forestry.apiculture.FlowerProviderMushroom; +import forestry.apiculture.FlowerProviderNetherwart; +import forestry.apiculture.FlowerProviderVanilla; +import forestry.apiculture.FlowerProviderWheat; +import forestry.apiculture.GuiHandlerApiculture; +import forestry.apiculture.PacketHandlerApiculture; +import forestry.apiculture.SaveEventHandlerApiculture; +import forestry.apiculture.VillageHandlerApiculture; +import forestry.apiculture.gadgets.BlockAlveary; +import forestry.apiculture.gadgets.BlockBeehives; +import forestry.apiculture.gadgets.BlockCandle; +import forestry.apiculture.gadgets.BlockStump; +import forestry.apiculture.gadgets.StructureLogicAlveary; +import forestry.apiculture.gadgets.TileAlvearyFan; +import forestry.apiculture.gadgets.TileAlvearyHeater; +import forestry.apiculture.gadgets.TileAlvearyHygroregulator; +import forestry.apiculture.gadgets.TileAlvearyPlain; +import forestry.apiculture.gadgets.TileAlvearySieve; +import forestry.apiculture.gadgets.TileAlvearyStabiliser; +import forestry.apiculture.gadgets.TileAlvearySwarmer; +import forestry.apiculture.gadgets.TileApiaristChest; +import forestry.apiculture.gadgets.TileApiary; +import forestry.apiculture.gadgets.TileBeehouse; +import forestry.apiculture.gadgets.TileCandle; +import forestry.apiculture.gadgets.TileSwarm; +import forestry.apiculture.genetics.AlleleBeeSpecies; +import forestry.apiculture.genetics.AlleleEffectAggressive; +import forestry.apiculture.genetics.AlleleEffectCreeper; +import forestry.apiculture.genetics.AlleleEffectExploration; +import forestry.apiculture.genetics.AlleleEffectGlacial; +import forestry.apiculture.genetics.AlleleEffectHeroic; +import forestry.apiculture.genetics.AlleleEffectIgnition; +import forestry.apiculture.genetics.AlleleEffectMiasmic; +import forestry.apiculture.genetics.AlleleEffectMisanthrope; +import forestry.apiculture.genetics.AlleleEffectNone; +import forestry.apiculture.genetics.AlleleEffectPotion; +import forestry.apiculture.genetics.AlleleEffectRadioactive; +import forestry.apiculture.genetics.AlleleEffectRepulsion; +import forestry.apiculture.genetics.AlleleEffectResurrection; +import forestry.apiculture.genetics.AlleleEffectSnowing; +import forestry.apiculture.genetics.AlleleFlowers; +import forestry.apiculture.genetics.Bee; +import forestry.apiculture.genetics.BeeHelper; +import forestry.apiculture.genetics.BeeMutation; +import forestry.apiculture.genetics.BeeTemplates; +import forestry.apiculture.genetics.BeekeepingMode; +import forestry.apiculture.genetics.BranchBees; +import forestry.apiculture.genetics.HiveDrop; +import forestry.apiculture.genetics.JubilanceNone; +import forestry.apiculture.genetics.JubilanceProviderHermit; +import forestry.apiculture.genetics.MutationTimeLimited; +import forestry.apiculture.items.ItemAlvearyBlock; +import forestry.apiculture.items.ItemArmorApiarist; +import forestry.apiculture.items.ItemBeeGE; +import forestry.apiculture.items.ItemBeealyzer; +import forestry.apiculture.items.ItemCandleBlock; +import forestry.apiculture.items.ItemHiveFrame; +import forestry.apiculture.items.ItemHoneycomb; +import forestry.apiculture.items.ItemImprinter; +import forestry.apiculture.items.ItemWaxCast; +import forestry.apiculture.proxy.ProxyApiculture; +import forestry.apiculture.trigger.TriggerNoFrames; +import forestry.apiculture.worldgen.HiveDecorator; +import forestry.core.GameMode; +import forestry.core.config.Config; +import forestry.core.config.Configuration; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.config.Property; +import forestry.core.gadgets.BlockBase; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.genetics.Allele; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.items.ItemCrated; +import forestry.core.items.ItemForestry; +import forestry.core.items.ItemForestryBlock; +import forestry.core.items.ItemOverlay; +import forestry.core.items.ItemOverlay.OverlayInfo; +import forestry.core.proxy.Proxies; +import forestry.core.render.EntitySnowFX; +import forestry.core.triggers.Trigger; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.ShapedRecipeCustom; + +@PluginInfo(pluginID = "Apiculture", name = "Apiculture", author = "SirSengir", url = Defaults.URL, description = "Adds bees, beekeeping and bee products. Affects world generation.") +public class PluginApiculture extends NativePlugin { + + @SidedProxy(clientSide = "forestry.apiculture.proxy.ClientProxyApiculture", serverSide = "forestry.apiculture.proxy.ProxyApiculture") + public static ProxyApiculture proxy; + private static final String CONFIG_CATEGORY = "apiculture"; + private Configuration apicultureConfig; + public static String beekeepingMode = "NORMAL"; + public static int beeCycleTicks = 550; + public static boolean apiarySideSensitive = false; + public static boolean fancyRenderedBees = false; + public static Trigger triggerNoFrames; + private ArrayList forestDrops; + private ArrayList meadowsDrops; + private ArrayList desertDrops; + private ArrayList jungleDrops; + private ArrayList endDrops; + private ArrayList snowDrops; + private ArrayList swampDrops; + private ArrayList swarmDrops; + /** + * See {@link IBeeRoot} for details + */ + public static IBeeRoot beeInterface; + public static MachineDefinition definitionApiary; + public static MachineDefinition definitionChest; + public static MachineDefinition definitionBeehouse; + + @Override + public boolean isAvailable() { + return !Config.disableApiculture; + } + + @SuppressWarnings("unchecked") + @Override + public void preInit() { + super.preInit(); + + MinecraftForge.EVENT_BUS.register(this); + + proxy.addLocalizations(); + + createHiveDropArrays(); + + ForestryBlock.apiculture = new BlockBase(Material.iron); + ForestryBlock.apiculture.setBlockName("for.apiculture").setCreativeTab(Tabs.tabApiculture); + Proxies.common.registerBlock(ForestryBlock.apiculture, ItemForestryBlock.class); + + definitionApiary = ForestryBlock.apiculture.addDefinition(new MachineDefinition(Defaults.DEFINITION_APIARY_META, "forestry.Apiary", TileApiary.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.apiculture, 1, Defaults.DEFINITION_APIARY_META), new Object[] { "XXX", "#C#", "###", 'X', "slabWood", '#', + "plankWood", 'C', ForestryItem.impregnatedCasing })) + .setFaces(0, 1, 2, 2, 4, 4, 0, 7)); + + definitionChest = ForestryBlock.apiculture.addDefinition(new MachineDefinition(Defaults.DEFINITION_APIARISTCHEST_META, "forestry.ApiaristChest", TileApiaristChest.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.apiculture, 1, Defaults.DEFINITION_APIARISTCHEST_META), new Object[] { " # ", "XYX", "XXX", '#', Blocks.glass, 'X', + "beeComb", 'Y', Blocks.chest })).setFaces(0, 1, 2, + 3, 4, 4)); + + definitionBeehouse = ForestryBlock.apiculture.addDefinition(new MachineDefinition(Defaults.DEFINITION_BEEHOUSE_META, "forestry.Beehouse", TileBeehouse.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.apiculture, 1, Defaults.DEFINITION_BEEHOUSE_META), new Object[] { "XXX", "#C#", "###", 'X', "slabWood", '#', + "plankWood", 'C', "beeComb" })) + .setFaces(0, 1, 2, 2, 4, 4, 0, 7)); + + ForestryBlock.beehives = (new BlockBeehives()).setBlockName("beehives"); + Proxies.common.registerBlock(ForestryBlock.beehives, ItemForestryBlock.class); + ForestryBlock.beehives.setHarvestLevel("pickaxe", 1, 0); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 1); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 2); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 3); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 4); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 5); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 6); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 7); + ForestryBlock.beehives.setHarvestLevel("scoop", 0, 8); + + // Init bee interface + AlleleManager.alleleRegistry.registerSpeciesRoot(PluginApiculture.beeInterface = BeeManager.beeInterface = new BeeHelper()); + BeeManager.villageBees = new ArrayList[] { new ArrayList(), new ArrayList() }; + + // Candles + ForestryBlock.candle = new BlockCandle().setBlockName("candle"); + Proxies.common.registerBlock(ForestryBlock.candle, ItemCandleBlock.class); + ForestryBlock.stump = new BlockStump().setBlockName("stump"); + Proxies.common.registerBlock(ForestryBlock.stump, ItemForestryBlock.class); + + // Alveary and Components + ForestryBlock.alveary = new BlockAlveary().setBlockName("alveary"); + Proxies.common.registerBlock(ForestryBlock.alveary, ItemAlvearyBlock.class); + ForestryBlock.alveary.setHarvestLevel("axe", 0); + + // Add triggers + triggerNoFrames = new TriggerNoFrames(); + + // Create bee alleles + createAlleles(); + + // Register village components with the Structure registry. + VillageHandlerApiculture.registerVillageComponents(); + } + + @Override + public void doInit() { + super.doInit(); + + apicultureConfig = new Configuration(); + + Property property = apicultureConfig.get("apiary.sidesensitive", CONFIG_CATEGORY, apiarySideSensitive); + property.Comment = "set to false if apiaries should output all items regardless of side a pipe is attached to"; + apiarySideSensitive = Boolean.parseBoolean(property.Value); + + property = apicultureConfig.get("render.bees.fancy", CONFIG_CATEGORY, fancyRenderedBees); + property.Comment = "set to true to enable a fancy butterfly-like renderer for bees. (experimental!)"; + fancyRenderedBees = Boolean.parseBoolean(property.Value); + + property = apicultureConfig.get("beekeeping.mode", CONFIG_CATEGORY, "NORMAL"); + property.Comment = "change beekeeping modes here. possible values EASY, NORMAL, HARD, HARDCORE, INSANE. mods may add additional modes."; + beekeepingMode = property.Value.trim(); + Proxies.log.finer("Beekeeping mode read from config: " + beekeepingMode); + + property = apicultureConfig.get("beekeeping.flowers.custom", CONFIG_CATEGORY, ""); + property.Comment = "add additional flower blocks for apiaries here in the format id:meta. separate blocks using ';'. will be treated like vanilla flowers. not recommended for flowers implemented as tile entities."; + parseAdditionalFlowers(property.Value, FlowerManager.plainFlowers); + + property = apicultureConfig.get("species.blacklist", CONFIG_CATEGORY, ""); + property.Comment = "add species to blacklist identified by their uid and seperated with ';'."; + parseBeeBlacklist(property.Value); + + apicultureConfig.save(); + + createMutations(); + registerBeehiveDrops(); + + PluginApiculture.beeInterface.registerBeekeepingMode(BeekeepingMode.easy); + PluginApiculture.beeInterface.registerBeekeepingMode(BeekeepingMode.normal); + PluginApiculture.beeInterface.registerBeekeepingMode(BeekeepingMode.hard); + PluginApiculture.beeInterface.registerBeekeepingMode(BeekeepingMode.hardcore); + PluginApiculture.beeInterface.registerBeekeepingMode(BeekeepingMode.insane); + + // Inducers for swarmer + BeeManager.inducers.put(ForestryItem.royalJelly.getItemStack(), 10); + + registerTemplates(); + + definitionApiary.register(); + definitionBeehouse.register(); + definitionChest.register(); + GameRegistry.registerTileEntity(TileAlvearyPlain.class, "forestry.Alveary"); + GameRegistry.registerTileEntity(TileSwarm.class, "forestry.Swarm"); + GameRegistry.registerTileEntity(TileAlvearySwarmer.class, "forestry.AlvearySwarmer"); + GameRegistry.registerTileEntity(TileAlvearyHeater.class, "forestry.AlvearyHeater"); + GameRegistry.registerTileEntity(TileAlvearyFan.class, "forestry.AlvearyFan"); + GameRegistry.registerTileEntity(TileAlvearyHygroregulator.class, "forestry.AlvearyHygro"); + GameRegistry.registerTileEntity(TileAlvearyStabiliser.class, "forestry.AlvearyStabiliser"); + GameRegistry.registerTileEntity(TileAlvearySieve.class, "forestry.AlvearySieve"); + GameRegistry.registerTileEntity(TileCandle.class, "forestry.Candle"); + + BeeManager.villageBees[0].add(beeInterface.templateAsGenome(BeeTemplates.getForestTemplate())); + BeeManager.villageBees[0].add(beeInterface.templateAsGenome(BeeTemplates.getMeadowsTemplate())); + BeeManager.villageBees[0].add(beeInterface.templateAsGenome(BeeTemplates.getModestTemplate())); + BeeManager.villageBees[0].add(beeInterface.templateAsGenome(BeeTemplates.getMarshyTemplate())); + BeeManager.villageBees[0].add(beeInterface.templateAsGenome(BeeTemplates.getWintryTemplate())); + BeeManager.villageBees[0].add(beeInterface.templateAsGenome(BeeTemplates.getTropicalTemplate())); + + BeeManager.villageBees[1].add(beeInterface.templateAsGenome(BeeTemplates.getForestRainResistTemplate())); + BeeManager.villageBees[1].add(beeInterface.templateAsGenome(BeeTemplates.getCommonTemplate())); + BeeManager.villageBees[1].add(beeInterface.templateAsGenome(BeeTemplates.getValiantTemplate())); + + // Register villager stuff + VillageHandlerApiculture villageHandler = new VillageHandlerApiculture(); + VillagerRegistry.instance().registerVillageCreationHandler(villageHandler); + VillagerRegistry.instance().registerVillagerId(Defaults.ID_VILLAGER_BEEKEEPER); + Proxies.render.registerVillagerSkin(Defaults.ID_VILLAGER_BEEKEEPER, Defaults.TEXTURE_SKIN_BEEKPEEPER); + VillagerRegistry.instance().registerVillageTradeHandler(Defaults.ID_VILLAGER_BEEKEEPER, villageHandler); + + // Register world gen + if (Config.generateBeehives) + MinecraftForge.EVENT_BUS.register(HiveDecorator.instance()); + + proxy.initializeRendering(); + } + + @Override + public void postInit() { + super.postInit(); + registerDungeonLoot(); + + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerApiculture(); + } + + @Override + public IPacketHandler getPacketHandler() { + return new PacketHandlerApiculture(); + } + + @Override + protected void registerItems() { + + // / BEES + ForestryItem.beeQueenGE.registerItem((new ItemBeeGE(EnumBeeType.QUEEN)), "beeQueenGE"); + ForestryItem.beeDroneGE.registerItem((new ItemBeeGE(EnumBeeType.DRONE)), "beeDroneGE"); + ForestryItem.beePrincessGE.registerItem((new ItemBeeGE(EnumBeeType.PRINCESS)), "beePrincessGE"); + ForestryItem.beeLarvaeGE.registerItem((new ItemBeeGE(EnumBeeType.LARVAE)), "beeLarvaeGE"); + + ForestryItem.beealyzer.registerItem((new ItemBeealyzer()), "beealyzer"); + // Disabling Habitat Locator, because it's b0rked and seems to flubber up other icons. + /*ForestryItem.biomeFinder = new ItemBiomefinder(Config.getOrCreateItemIdProperty("biomeFinder", Defaults.ID_ITEM_BIOME_FINDER)) + .setUnlocalizedName("biomeFinder");*/ + ForestryItem.imprinter.registerItem((new ItemImprinter()), "imprinter"); + + // / COMB FRAMES + ForestryItem.frameUntreated.registerItem(new ItemHiveFrame(80, 0.9f), "frameUntreated"); + ForestryItem.frameImpregnated.registerItem(new ItemHiveFrame(240, 0.4f), "frameImpregnated"); + ForestryItem.frameProven.registerItem(new ItemHiveFrame(720, 0.3f), "frameProven"); + + // / BEE RESOURCES + ForestryItem.honeyDrop.registerItem(new ItemOverlay(Tabs.tabApiculture, + new OverlayInfo("honey", 0xecb42d, 0xe8c814), new OverlayInfo("charged", 0x800505, 0x9c0707).setIsSecret(), + new OverlayInfo("omega", 0x191919, 0x4a8ca7).setIsSecret()), "honeyDrop"); + OreDictionary.registerOre("dropHoney", ForestryItem.honeyDrop.getItemStack()); + + ForestryItem.pollen.registerItem(new ItemOverlay(Tabs.tabApiculture, + new OverlayInfo("normal", 0xa28a25, 0xa28a25), + new OverlayInfo("crystalline", 0xffffff, 0xc5feff)), + "pollen"); + OreDictionary.registerOre("itemPollen", ForestryItem.pollen.getItemStack()); + + ForestryItem.propolis.registerItem(new ItemOverlay(Tabs.tabApiculture, + new OverlayInfo("normal", 0xc5b24e), new OverlayInfo("sticky", 0xc68e57), new OverlayInfo("pulsating", 0x2ccdb1).setIsSecret(), + new OverlayInfo("silky", 0xddff00)), + "propolis"); + + ForestryItem.honeydew.registerItem(new ItemForestry().setCreativeTab(Tabs.tabApiculture), "honeydew"); + OreDictionary.registerOre("dropHoneydew", ForestryItem.honeydew.getItemStack()); + + ForestryItem.royalJelly.registerItem(new ItemForestry().setCreativeTab(Tabs.tabApiculture), "royalJelly"); + OreDictionary.registerOre("dropRoyalJelly", ForestryItem.royalJelly.getItemStack()); + + ForestryItem.waxCast.registerItem(new ItemWaxCast().setCreativeTab(Tabs.tabApiculture), "waxCast"); + + // / BEE COMBS + ForestryItem.beeComb.registerItem(new ItemHoneycomb(), "beeCombs"); + OreDictionary.registerOre("beeComb", ForestryItem.beeComb.getItemStack(1, Defaults.WILDCARD)); + + // / APIARIST'S CLOTHES + ForestryItem.apiaristHat.registerItem(new ItemArmorApiarist(0), "apiaristHelmet"); + ForestryItem.apiaristChest.registerItem(new ItemArmorApiarist(1), "apiaristChest"); + ForestryItem.apiaristLegs.registerItem(new ItemArmorApiarist(2), "apiaristLegs"); + ForestryItem.apiaristBoots.registerItem(new ItemArmorApiarist(3), "apiaristBoots"); + + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerCrates() { + ForestryItem.cratedBeeswax.registerItem(new ItemCrated(ForestryItem.beeswax.getItemStack()), "cratedBeeswax"); + ForestryItem.cratedPollen.registerItem(new ItemCrated(ForestryItem.pollen.getItemStack()), "cratedPollen"); + ForestryItem.cratedPropolis.registerItem(new ItemCrated(ForestryItem.propolis.getItemStack()), "cratedPropolis"); + ForestryItem.cratedHoneydew.registerItem(new ItemCrated(ForestryItem.honeydew.getItemStack()), "cratedHoneydew"); + ForestryItem.cratedRoyalJelly.registerItem(new ItemCrated(ForestryItem.royalJelly.getItemStack()), "cratedRoyalJelly"); + + ForestryItem.cratedHoneycombs.registerItem(new ItemCrated(ForestryItem.beeComb.getItemStack(1, 0)), "cratedHoneycombs"); + ForestryItem.cratedCocoaComb.registerItem(new ItemCrated(ForestryItem.beeComb.getItemStack(1, 1)), "cratedCocoaComb"); + ForestryItem.cratedSimmeringCombs.registerItem(new ItemCrated(ForestryItem.beeComb.getItemStack(1, 2)), "cratedSimmeringCombs"); + ForestryItem.cratedStringyCombs.registerItem(new ItemCrated(ForestryItem.beeComb.getItemStack(1, 3)), "cratedStringyCombs"); + ForestryItem.cratedFrozenCombs.registerItem(new ItemCrated(ForestryItem.beeComb.getItemStack(1, 4)), "cratedFrozenCombs"); + ForestryItem.cratedDrippingCombs.registerItem(new ItemCrated(ForestryItem.beeComb.getItemStack(1, 5)), "cratedDrippingCombs"); + + ForestryItem.cratedRefractoryWax.registerItem(new ItemCrated(ForestryItem.refractoryWax.getItemStack()), "cratedRefractoryWax"); + + } + + @Override + protected void registerRecipes() { + + // / APIARIST'S ARMOR + Proxies.common.addRecipe(ForestryItem.apiaristHat.getItemStack(), new Object[] { "###", "# #", '#', + ForestryItem.craftingMaterial.getItemStack(1, 3) }); + Proxies.common.addRecipe(ForestryItem.apiaristChest.getItemStack(), new Object[] { "# #", "###", "###", '#', + ForestryItem.craftingMaterial.getItemStack(1, 3) }); + Proxies.common.addRecipe(ForestryItem.apiaristLegs.getItemStack(), new Object[] { "###", "# #", "# #", '#', + ForestryItem.craftingMaterial.getItemStack(1, 3) }); + Proxies.common.addRecipe(ForestryItem.apiaristBoots.getItemStack(), new Object[] { "# #", "# #", '#', + ForestryItem.craftingMaterial.getItemStack(1, 3) }); + + // / HABITAT LOCATOR + //Proxies.common.addRecipe(ForestryItem.biomeFinder.getItemStack(), + // new Object[] { " X ", "X#X", " X ", '#', Items.redstone, 'X', "ingotBronze" }); + + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(3), + "###", "YXY", + '#', ForestryItem.waxCapsule, + 'X', Items.bone, + 'Y', ForestryItem.pollen); + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(3), + "###", "YXY", + '#', ForestryItem.canEmpty, + 'X', Items.bone, + 'Y', ForestryItem.pollen); + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(), + "###", "YXY", "###", + '#', ForestryItem.honeyDrop, + 'Y', ForestryItem.fertilizerCompound, + 'X', ForestryItem.waxCapsule); + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(), + "###", "YXY", "###", + '#', ForestryItem.honeyDrop, + 'Y', ForestryItem.fertilizerCompound, + 'X', ForestryItem.canEmpty); + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(), + "###", "YXY", "###", + '#', ForestryItem.honeyDrop, + 'Y', ForestryItem.pollen, + 'X', ForestryItem.waxCapsule); + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(), + "###", "YXY", "###", + '#', ForestryItem.honeyDrop, + 'Y', ForestryItem.pollen, + 'X', ForestryItem.canEmpty); + + // Bees + Proxies.common.addRecipe(ForestryItem.scoop.getItemStack(1), + "#X#", "###", " # ", + '#', "stickWood", + 'X', Blocks.wool); + Proxies.common.addRecipe(new ItemStack(Items.slime_ball), + "#X#", "#X#", "#X#", + '#', ForestryItem.propolis, + 'X', ForestryItem.pollen); + Proxies.common.addRecipe(new ItemStack(Items.speckled_melon), + "#X#", "#Y#", "#X#", + '#', ForestryItem.honeyDrop, + 'X', ForestryItem.honeydew, + 'Y', Items.melon); + Proxies.common.addRecipe(ForestryItem.frameUntreated.getItemStack(), + "###", "#S#", "###", + '#', "stickWood", + 'S', Items.string); + Proxies.common.addRecipe(ForestryItem.frameImpregnated.getItemStack(), + "###", "#S#", "###", + '#', ForestryItem.stickImpregnated, + 'S', Items.string); + + // FOOD STUFF + if (ForestryItem.honeyedSlice != null) + Proxies.common.addRecipe(ForestryItem.honeyedSlice.getItemStack(4), + "###", "#X#", "###", + '#', ForestryItem.honeyDrop, + 'X', Items.bread); + if (ForestryItem.honeyPot != null) + Proxies.common.addRecipe(ForestryItem.honeyPot.getItemStack(1), + "# #", " X ", "# #", + '#', ForestryItem.honeyDrop, + 'X', ForestryItem.waxCapsule); + if (ForestryItem.ambrosia != null) + Proxies.common.addRecipe(ForestryItem.ambrosia.getItemStack(), + "#Y#", "XXX", "###", + '#', ForestryItem.honeydew, + 'X', ForestryItem.royalJelly, + 'Y', ForestryItem.waxCapsule); + + // / CAPSULES + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.capsule"), "###", '#', ForestryItem.beeswax); + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.refractory"), "###", '#', ForestryItem.refractoryWax); + + // / BITUMINOUS PEAT + Proxies.common.addRecipe(ForestryItem.bituminousPeat.getItemStack(), + new Object[] { " # ", "XYX", " # ", '#', "dustAsh", 'X', ForestryItem.peat, 'Y', + ForestryItem.propolis }); + // / TORCHES + Proxies.common.addRecipe(new ItemStack(Blocks.torch, 3), + new Object[] { " # ", " # ", " Y ", '#', ForestryItem.beeswax, 'Y', "stickWood" }); + Proxies.common.addRecipe(ForestryItem.craftingMaterial.getItemStack(1, 1), new Object[] { "# #", " # ", "# #", '#', + ForestryItem.propolis.getItemStack(1, 2) }); + + // / CANDLES + RecipeManagers.carpenterManager.addRecipe(30, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 600), null, new ItemStack(ForestryBlock.candle, 24), new Object[] { + " X ", "###", "###", '#', ForestryItem.beeswax, 'X', Items.string }); + RecipeManagers.carpenterManager.addRecipe(10, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 200), null, new ItemStack(ForestryBlock.candle, 6), new Object[] { + "#X#", '#', ForestryItem.beeswax, 'X', ForestryItem.craftingMaterial.getItemStack(1, 2) }); + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.candle), new ItemStack(ForestryBlock.candle)); + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.candle, 1, 1), new ItemStack(ForestryBlock.candle, 1, 1)); + + // / WAX CAST + Proxies.common.addRecipe(ForestryItem.waxCast.getItemStack(), + "###", "# #", "###", + '#', ForestryItem.beeswax); + + // / ALVEARY + Proxies.common.addRecipe(new ItemStack(ForestryBlock.alveary), + "###", "#X#", "###", + 'X', ForestryItem.impregnatedCasing, + '#', ForestryItem.craftingMaterial.getItemStack(1, 6)); + // SWARMER + Proxies.common.addRecipe(new ItemStack(ForestryBlock.alveary, 1, 2), + "#G#", " X ", "#G#", + '#', ForestryItem.tubes.getItemStack(1, 5), + 'X', ForestryBlock.alveary, + 'G', Items.gold_ingot); + // FAN + Proxies.common.addRecipe(new ItemStack(ForestryBlock.alveary, 1, 3), + "I I", " X ", "I#I", + '#', ForestryItem.tubes.getItemStack(1, 4), + 'X', ForestryBlock.alveary, + 'I', Items.iron_ingot); + // HEATER + Proxies.common.addRecipe(new ItemStack(ForestryBlock.alveary, 1, 4), + "#I#", " X ", "YYY", + '#', ForestryItem.tubes.getItemStack(1, 4), + 'X', ForestryBlock.alveary, + 'I', Items.iron_ingot, 'Y', Blocks.stone); + // HYGROREGULATOR + Proxies.common.addRecipe(new ItemStack(ForestryBlock.alveary, 1, 5), + "GIG", "GXG", "GIG", + 'X', ForestryBlock.alveary, + 'I', Items.iron_ingot, + 'G', Blocks.glass); + // STABILISER + Proxies.common.addRecipe(new ItemStack(ForestryBlock.alveary, 1, 6), + "G G", "GXG", "G G", + 'X', ForestryBlock.alveary, + 'G', Items.quartz); + // SIEVE + Proxies.common.addRecipe(new ItemStack(ForestryBlock.alveary, 1, TileAlvearySieve.BLOCK_META), + "III", " X ", "WWW", + 'X', ForestryBlock.alveary, + 'I', Items.iron_ingot, + 'W', ForestryItem.craftingMaterial.getItemStack(1, 3)); + + // / SQUEEZER + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.honeyDrop.getItemStack() }, LiquidHelper.getLiquid(Defaults.LIQUID_HONEY, 100), + ForestryItem.propolis.getItemStack(), 5); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.honeydew.getItemStack() }, LiquidHelper.getLiquid(Defaults.LIQUID_HONEY, 100)); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.phosphor.getItemStack(2), new ItemStack(Blocks.sand) }, LiquidHelper.getLiquid(Defaults.LIQUID_LAVA, 2000)); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.phosphor.getItemStack(2), new ItemStack(Blocks.dirt) }, LiquidHelper.getLiquid(Defaults.LIQUID_LAVA, 1600)); + + // / CARPENTER + RecipeManagers.carpenterManager.addRecipe(100, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 2000), null, ForestryItem.beealyzer.getItemStack(), + new Object[] { "X#X", "X#X", "RDR", '#', Blocks.glass_pane, 'X', "ingotTin", 'R', + Items.redstone, 'D', Items.diamond }); + RecipeManagers.carpenterManager.addRecipe( + 50, + LiquidHelper.getLiquid(Defaults.LIQUID_HONEY, 500), + null, + ForestryItem.craftingMaterial.getItemStack(1, 6), + new Object[] { " J ", "###", "WPW", '#', "plankWood", 'J', ForestryItem.royalJelly, + 'W', ForestryItem.beeswax, 'P', ForestryItem.pollen }); + + // / CENTRIFUGE + // Honey combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 0), ForestryItem.beeswax.getItemStack(), ForestryItem.honeyDrop.getItemStack(), 90); + // Cocoa combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 1), ForestryItem.beeswax.getItemStack(), new ItemStack(Items.dye, 1, 3), 50); + // Simmering combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 2), ForestryItem.refractoryWax.getItemStack(), ForestryItem.phosphor.getItemStack(2), 70); + // Stringy combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 3), ForestryItem.propolis.getItemStack(), ForestryItem.honeyDrop.getItemStack(), 40); + // Drippig combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 5), ForestryItem.honeydew.getItemStack(), ForestryItem.honeyDrop.getItemStack(), 40); + // Frozen combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 4), new ItemStack[] { ForestryItem.beeswax.getItemStack(), + ForestryItem.honeyDrop.getItemStack(), new ItemStack(Items.snowball), ForestryItem.pollen.getItemStack(1, 1) }, new int[] { 80, 70, 40, 20 }); + // Silky combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 6), ForestryItem.honeyDrop.getItemStack(), ForestryItem.propolis.getItemStack(1, 3), 80); + // Parched combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 7), ForestryItem.beeswax.getItemStack(), ForestryItem.honeyDrop.getItemStack(), 90); + // Mysterious combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 8), new ItemStack[] { ForestryItem.honeyDrop.getItemStack(), + ForestryItem.propolis.getItemStack(1, 2) }, new int[] { 40, 100 }); + // Irradiated combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 9), new ItemStack[] {}, new int[] {}); + // Powdery combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 10), new ItemStack[] { ForestryItem.honeyDrop.getItemStack(), + ForestryItem.beeswax.getItemStack(), new ItemStack(Items.gunpowder) }, new int[] { 20, 20, 90 }); + // Reddened Combs + RecipeManagers.centrifugeManager.addRecipe(80, ForestryItem.beeComb.getItemStack(1, 11), + new ItemStack[] { ForestryItem.honeyDrop.getItemStack(2, 1) }, new int[] { 100 }); + // Darkened Combs + RecipeManagers.centrifugeManager.addRecipe(80, ForestryItem.beeComb.getItemStack(1, 12), + new ItemStack[] { ForestryItem.honeyDrop.getItemStack(1, 1) }, new int[] { 100 }); + // Omega Combs + RecipeManagers.centrifugeManager.addRecipe(400, ForestryItem.beeComb.getItemStack(1, 13), new ItemStack[] { ForestryItem.honeyDrop.getItemStack(1, 2) }, new int[] { 100 }); + // Wheaten Combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 14), new ItemStack[] { ForestryItem.honeyDrop.getItemStack(), + ForestryItem.beeswax.getItemStack(), new ItemStack(Items.wheat) }, new int[] { 20, 20, 80 }); + // Mossy Combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 15), ForestryItem.beeswax.getItemStack(), ForestryItem.honeyDrop.getItemStack(), 90); + // Mellow Combs + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.beeComb.getItemStack(1, 16), new ItemStack[] { ForestryItem.honeydew.getItemStack(), + ForestryItem.beeswax.getItemStack(), new ItemStack(Items.quartz) }, new int[] { 60, 20, 30 }); + + // Silk + RecipeManagers.centrifugeManager.addRecipe(5, ForestryItem.propolis.getItemStack(1, 3), new ItemStack[] { + ForestryItem.craftingMaterial.getItemStack(1, 2), ForestryItem.propolis.getItemStack() }, new int[] { 60, 10 }); + + // / FERMENTER + RecipeManagers.fermenterManager.addRecipe(ForestryItem.honeydew.getItemStack(), 500, 1.0f, LiquidHelper.getLiquid(Defaults.LIQUID_MEAD, 1), + LiquidHelper.getLiquid(Defaults.LIQUID_HONEY, 1)); + + } + + private void registerBeehiveDrops() { + forestDrops.add(new HiveDrop(BeeTemplates.getForestTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 0) }, 80).setIgnobleShare(0.7f)); + forestDrops.add(new HiveDrop(BeeTemplates.getForestRainResistTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 0) }, 8)); + forestDrops.add(new HiveDrop(BeeTemplates.getValiantTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 0) }, 3)); + + meadowsDrops.add(new HiveDrop(BeeTemplates.getMeadowsTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 0) }, 80).setIgnobleShare(0.7f)); + meadowsDrops.add(new HiveDrop(BeeTemplates.getValiantTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 0) }, 3)); + + desertDrops.add(new HiveDrop(BeeTemplates.getModestTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 7) }, 80).setIgnobleShare(0.7f)); + desertDrops.add(new HiveDrop(BeeTemplates.getValiantTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 7) }, 3)); + + jungleDrops.add(new HiveDrop(BeeTemplates.getTropicalTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 6) }, 80).setIgnobleShare(0.7f)); + jungleDrops.add(new HiveDrop(BeeTemplates.getValiantTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 6) }, 3)); + + endDrops.add(new HiveDrop(BeeTemplates.getEnderTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 8) }, 90)); + + snowDrops.add(new HiveDrop(BeeTemplates.getWintryTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 4) }, 80).setIgnobleShare(0.5f)); + snowDrops.add(new HiveDrop(BeeTemplates.getValiantTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 4) }, 3)); + + swampDrops.add(new HiveDrop(BeeTemplates.getMarshyTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 15) }, 80).setIgnobleShare(0.4f)); + swampDrops.add(new HiveDrop(BeeTemplates.getValiantTemplate(), new ItemStack[] { ForestryItem.beeComb.getItemStack(1, 15) }, 3)); + } + + private void registerDungeonLoot() { + int rarity; + if (Config.dungeonLootRare) + rarity = 5; + else + rarity = 10; + + ChestGenHooks.addItem(ChestGenHooks.DUNGEON_CHEST, new WeightedRandomChestContent(getBeeItemFromTemplate(BeeTemplates.getSteadfastTemplate(), EnumBeeType.DRONE), 1, 1, rarity)); + + ItemStack stack = new ItemStack(ForestryBlock.candle); + NBTTagCompound tag = new NBTTagCompound(); + tag.setInteger(BlockCandle.colourTagName, 0xffffff); + stack.setTagCompound(tag); + + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(stack, 7, 12, 12)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(ForestryItem.scoop.getItemStack(), 1, 1, 8)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(ForestryItem.propolis.getItemStack(), 2, 4, 6)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(ForestryItem.beeComb.getItemStack(), 4, 12, 7)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(ForestryItem.beeComb.getItemStack(1, 4), 2, 10, 7)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(ForestryItem.beeComb.getItemStack(1, 6), 1, 6, 7)); + + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(getBeeItemFromTemplate(BeeTemplates.getForestRainResistTemplate(), EnumBeeType.PRINCESS), 1, 1, 5)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(getBeeItemFromTemplate(BeeTemplates.getCommonTemplate(), EnumBeeType.DRONE), 1, 2, 8)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(getBeeItemFromTemplate(BeeTemplates.getMeadowsTemplate(), EnumBeeType.PRINCESS), 1, 1, 5)); + } + + private ItemStack getBeeItemFromTemplate(IAllele[] template, EnumBeeType beeType) { + IBee bee = new Bee(PluginApiculture.beeInterface.templateAsGenome(template)); + ItemStack beeItem; + switch (beeType) { + default: + case DRONE: + beeItem = ForestryItem.beeDroneGE.getItemStack(); + break; + case PRINCESS: + beeItem = ForestryItem.beePrincessGE.getItemStack(); + break; + } + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + bee.writeToNBT(nbtTagCompound); + beeItem.setTagCompound(nbtTagCompound); + + return beeItem; + } + + @SuppressWarnings("unchecked") + private void createHiveDropArrays() { + + BeeManager.hiveDrops = new ArrayList[8]; + + forestDrops = new ArrayList(); + BeeManager.hiveDrops[0] = forestDrops; + + meadowsDrops = new ArrayList(); + BeeManager.hiveDrops[1] = meadowsDrops; + + desertDrops = new ArrayList(); + BeeManager.hiveDrops[2] = desertDrops; + + jungleDrops = new ArrayList(); + BeeManager.hiveDrops[3] = jungleDrops; + + endDrops = new ArrayList(); + BeeManager.hiveDrops[4] = endDrops; + + snowDrops = new ArrayList(); + BeeManager.hiveDrops[5] = snowDrops; + + swampDrops = new ArrayList(); + BeeManager.hiveDrops[6] = swampDrops; + + swarmDrops = new ArrayList(); + BeeManager.hiveDrops[7] = swarmDrops; + } + + private void createAlleles() { + + IClassification hymnoptera = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.ORDER, "hymnoptera", "Hymnoptera"); + AlleleManager.alleleRegistry.getClassification("class.insecta").addMemberGroup(hymnoptera); + + IClassification apidae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "apidae", "Apidae"); + hymnoptera.addMemberGroup(apidae); + + IClassification honey = new BranchBees("honey", "Apis"); + apidae.addMemberGroup(honey); + IClassification noble = new BranchBees("noble", "Probapis"); + apidae.addMemberGroup(noble); + IClassification industrious = new BranchBees("industrious", "Industrapis"); + apidae.addMemberGroup(industrious); + IClassification heroic = new BranchBees("heroic", "Herapis"); + apidae.addMemberGroup(heroic); + IClassification infernal = new BranchBees("infernal", "Diapis"); + apidae.addMemberGroup(infernal); + IClassification austere = new BranchBees("austere", "Modapis"); + apidae.addMemberGroup(austere); + IClassification end = new BranchBees("end", "Finapis"); + apidae.addMemberGroup(end); + IClassification vengeful = new BranchBees("vengeful", "Punapis"); + apidae.addMemberGroup(vengeful); + IClassification tropical = new BranchBees("tropical", "Caldapis"); + apidae.addMemberGroup(tropical); + IClassification frozen = new BranchBees("frozen", "Coagapis"); + apidae.addMemberGroup(frozen); + IClassification reddened = new BranchBees("reddened", "Rubapis"); + apidae.addMemberGroup(reddened); + IClassification festive = new BranchBees("festive", "Festapis"); + apidae.addMemberGroup(festive); + IClassification agrarian = new BranchBees("agrarian", "Rustapis"); + apidae.addMemberGroup(agrarian); + IClassification boggy = new BranchBees("boggy", "Paludapis"); + apidae.addMemberGroup(boggy); + IClassification monastic = new BranchBees("monastic", "Monapis"); + apidae.addMemberGroup(monastic); + + // / BEES // SPECIES + // Common Branch + Allele.speciesForest = new AlleleBeeSpecies("speciesForest", true, "bees.species.forest", honey, "nigrocincta", 0x19d0ec, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 0), 30); + Allele.speciesMeadows = new AlleleBeeSpecies("speciesMeadows", true, "bees.species.meadows", honey, "florea", 0xef131e, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 0), 30); + Allele.speciesCommon = new AlleleBeeSpecies("speciesCommon", true, "bees.species.common", honey, "cerana", 0xb2b2b2, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 0), 35).setIsSecret(); + Allele.speciesCultivated = new AlleleBeeSpecies("speciesCultivated", true, "bees.species.cultivated", honey, "mellifera", 0x5734ec, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 0), 40).setIsSecret(); + + // Noble Branch + Allele.speciesNoble = new AlleleBeeSpecies("speciesNoble", false, "bees.species.noble", noble, "nobilis", 0xec9a19, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 5), 20).setIsSecret(); + Allele.speciesMajestic = new AlleleBeeSpecies("speciesMajestic", true, "bees.species.majestic", noble, "regalis", 0x7f0000, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 5), 30).setIsSecret(); + Allele.speciesImperial = new AlleleBeeSpecies("speciesImperial", false, "bees.species.imperial", noble, "imperatorius", 0xa3e02f, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 5), 20).addProduct(ForestryItem.royalJelly.getItemStack(), 15).setHasEffect().setIsSecret(); + + // Industrious Branch + Allele.speciesDiligent = new AlleleBeeSpecies("speciesDiligent", false, "bees.species.diligent", industrious, "sedulus", 0xc219ec, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 3), 20).setIsSecret(); + Allele.speciesUnweary = new AlleleBeeSpecies("speciesUnweary", true, "bees.species.unweary", industrious, "assiduus", 0x19ec5a, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 3), 30).setIsSecret(); + Allele.speciesIndustrious = new AlleleBeeSpecies("speciesIndustrious", false, "bees.species.industrious", industrious, "industria", 0xffffff, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 3), 20).addProduct(ForestryItem.pollen.getItemStack(), 15).setHasEffect().setIsSecret(); + + // Heroic Branch + Allele.speciesSteadfast = new AlleleBeeSpecies("speciesSteadfast", false, "bees.species.steadfast", heroic, "legio", 0x4d2b15, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 1), 20).setIsSecret().setHasEffect(); + Allele.speciesValiant = new AlleleBeeSpecies("speciesValiant", true, "bees.species.valiant", heroic, "centurio", 0x626bdd, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 1), 30).addSpecialty(new ItemStack(Items.sugar), 15).setIsSecret(); + Allele.speciesHeroic = new AlleleBeeSpecies("speciesHeroic", false, "bees.species.heroic", heroic, "kraphti", 0xb3d5e4, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 1), 40).setIsSecret().setHasEffect(); + + // Infernal Branch + Allele.speciesSinister = new AlleleBeeSpecies("speciesSinister", false, "bees.species.sinister", infernal, "caecus", 0xb3d5e4, 0x9a2323) + .addProduct(ForestryItem.beeComb.getItemStack(1, 2), 45).setEntityTexture("sinisterBee").setIsSecret().setTemperature(EnumTemperature.HELLISH).setHumidity(EnumHumidity.ARID); + Allele.speciesFiendish = new AlleleBeeSpecies("speciesFiendish", true, "bees.species.fiendish", infernal, "diabolus", 0xd7bee5, 0x9a2323) + .addProduct(ForestryItem.beeComb.getItemStack(1, 2), 55).addProduct(ForestryItem.ash.getItemStack(), 15).setEntityTexture("sinisterBee").setIsSecret() + .setTemperature(EnumTemperature.HELLISH).setHumidity(EnumHumidity.ARID); + Allele.speciesDemonic = new AlleleBeeSpecies("speciesDemonic", false, "bees.species.demonic", infernal, "draco", 0xf4e400, 0x9a2323) + .addProduct(ForestryItem.beeComb.getItemStack(1, 2), 45).addProduct(new ItemStack(Items.glowstone_dust), 15).setEntityTexture("sinisterBee").setHasEffect().setIsSecret() + .setTemperature(EnumTemperature.HELLISH).setHumidity(EnumHumidity.ARID); + + // Austere Branch + Allele.speciesModest = new AlleleBeeSpecies("speciesModest", false, "bees.species.modest", austere, "modicus", 0xc5be86, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 7), 20).setTemperature(EnumTemperature.HOT).setHumidity(EnumHumidity.ARID); + Allele.speciesFrugal = new AlleleBeeSpecies("speciesFrugal", true, "bees.species.frugal", austere, "permodestus", 0xe8dcb1, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 7), 30).setIsSecret().setTemperature(EnumTemperature.HOT).setHumidity(EnumHumidity.ARID); + Allele.speciesAustere = new AlleleBeeSpecies("speciesAustere", false, "bees.species.austere", austere, "correpere", 0xfffac2, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 7), 20).addSpecialty(ForestryItem.beeComb.getItemStack(1, 10), 50).setHasEffect() + .setIsSecret().setTemperature(EnumTemperature.HOT).setHumidity(EnumHumidity.ARID); + + // / Tropical Branch + Allele.speciesTropical = new AlleleBeeSpecies("speciesTropical", false, "bees.species.tropical", tropical, "mendelia", 0x378020, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 6), 20).setEntityTexture("tropicalBee").setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.speciesExotic = new AlleleBeeSpecies("speciesExotic", true, "bees.species.exotic", tropical, "darwini", 0x304903, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 6), 30).setEntityTexture("tropicalBee").setIsSecret().setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.speciesEdenic = new AlleleBeeSpecies("speciesEdenic", false, "bees.species.edenic", tropical, "humboldti", 0x393d0d, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 6), 20).setEntityTexture("tropicalBee").setHasEffect().setIsSecret().setTemperature(EnumTemperature.WARM) + .setHumidity(EnumHumidity.DAMP); + + // End Branch + Allele.speciesEnded = new AlleleBeeSpecies("speciesEnded", false, "bees.species.ender", end, "notchi", 0xe079fa, 0xd9de9e) + .addProduct(ForestryItem.beeComb.getItemStack(1, 8), 30).setEntityTexture("endBee").setIsSecret().setTemperature(EnumTemperature.COLD); + Allele.speciesSpectral = new AlleleBeeSpecies("speciesSpectral", true, "bees.species.spectral", end, "idolum", 0xa98bed, 0xd9de9e) // 0xa98bed + .addProduct(ForestryItem.beeComb.getItemStack(1, 8), 50).setEntityTexture("endBee").setIsSecret().setTemperature(EnumTemperature.COLD); + Allele.speciesPhantasmal = new AlleleBeeSpecies("speciesPhantasmal", false, "bees.species.phantasmal", end, "lemur", 0xcc00fa, 0xd9de9e) // 0x31023a // + // 0x8bc3ed + .addProduct(ForestryItem.beeComb.getItemStack(1, 8), 40).setEntityTexture("endBee").setIsSecret().setHasEffect().setTemperature(EnumTemperature.COLD); + + // Frozen Branch + Allele.speciesWintry = new AlleleBeeSpecies("speciesWintry", false, "bees.species.wintry", frozen, "brumalis", 0xa0ffc8, 0xdaf5f3).addProduct( + ForestryItem.beeComb.getItemStack(1, 4), 30).setEntityTexture("icyBee").setTemperature(EnumTemperature.ICY); + Allele.speciesIcy = new AlleleBeeSpecies("speciesIcy", true, "bees.species.icy", frozen, "coagulis", 0xa0ffff, 0xdaf5f3) + .addProduct(ForestryItem.beeComb.getItemStack(1, 4), 20).setEntityTexture("icyBee").addProduct(ForestryItem.craftingMaterial.getItemStack(1, 5), 20) + .setTemperature(EnumTemperature.ICY).setIsSecret(); + Allele.speciesGlacial = new AlleleBeeSpecies("speciesGlacial", false, "bees.species.glacial", frozen, "glacialis", 0xefffff, 0xdaf5f3) + .addProduct(ForestryItem.beeComb.getItemStack(1, 4), 20).setEntityTexture("icyBee").addProduct(ForestryItem.craftingMaterial.getItemStack(1, 5), 40) + .setTemperature(EnumTemperature.ICY).setHasEffect().setIsSecret(); + + // Vengeful Branch + Allele.speciesVindictive = new AlleleBeeSpecies("speciesVindictive", false, "bees.species.vindictive", vengeful, "ultio", 0xeafff3, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 9), 25).setIsSecret().setIsNotCounted(); + Allele.speciesVengeful = new AlleleBeeSpecies("speciesVengeful", false, "bees.species.vengeful", vengeful, "punire", 0xc2de00, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 9), 40).setIsSecret().setIsNotCounted(); + Allele.speciesAvenging = new AlleleBeeSpecies("speciesAvenging", false, "bees.species.avenging", vengeful, "hostimentum", 0xddff00, 0xffdc16) + .addProduct(ForestryItem.beeComb.getItemStack(1, 9), 40).setIsSecret().setHasEffect().setIsNotCounted(); + + // Reddened Branch (EE) + Allele.speciesDarkened = new AlleleBeeSpecies("speciesDarkened", false, "bees.species.darkened", reddened, "pahimas", 0xd7bee5, 0x260f29) + .addProduct(ForestryItem.beeComb.getItemStack(1, 0), 100).addSpecialty(ForestryItem.beeComb.getItemStack(1, 12), 100) + .setJubilanceProvider(new JubilanceNone()).setIsSecret().setIsNotCounted(); + AlleleManager.alleleRegistry.blacklistAllele(Allele.speciesDarkened.getUID()); + Allele.speciesReddened = new AlleleBeeSpecies("speciesReddened", false, "bees.species.reddened", reddened, "xenophos", 0xf8c1c1, 0x260f29) + .addProduct(ForestryItem.beeComb.getItemStack(1, 0), 100).addSpecialty(ForestryItem.beeComb.getItemStack(1, 11), 100) + .setJubilanceProvider(new JubilanceNone()).setIsSecret().setIsNotCounted(); + AlleleManager.alleleRegistry.blacklistAllele(Allele.speciesReddened.getUID()); + Allele.speciesOmega = new AlleleBeeSpecies("speciesOmega", false, "bees.species.omega", reddened, "slopokis", 0xfeff8f, 0x260f29) + .addProduct(ForestryItem.beeComb.getItemStack(1, 0), 100).addSpecialty(ForestryItem.beeComb.getItemStack(1, 13), 100) + .setJubilanceProvider(new JubilanceNone()).setIsSecret().setIsNotCounted(); + AlleleManager.alleleRegistry.blacklistAllele(Allele.speciesOmega.getUID()); + + // Festive branch + Allele.speciesLeporine = new AlleleBeeSpecies("speciesLeporine", false, "bees.species.leporine", festive, "lepus", 0xfeff8f, 0x3cd757) + .addProduct(ForestryItem.beeComb.getItemStack(1, 6), 30).addProduct(new ItemStack(Items.egg), 10).setIsSecret().setIsNotCounted() + .setHasEffect(); + Allele.speciesMerry = new AlleleBeeSpecies("speciesMerry", false, "bees.species.merry", festive, "feliciter", 0xffffff, 0xd40000) + .addProduct(ForestryItem.beeComb.getItemStack(1, 4), 30).addProduct(ForestryItem.craftingMaterial.getItemStack(1, 5), 20) + .setTemperature(EnumTemperature.ICY).setIsSecret().setIsNotCounted().setHasEffect(); + Allele.speciesTipsy = new AlleleBeeSpecies("speciesTipsy", false, "bees.species.tipsy", festive, "ebrius", 0xffffff, 0xc219ec) + .addProduct(ForestryItem.beeComb.getItemStack(1, 4), 30).addProduct(ForestryItem.craftingMaterial.getItemStack(1, 5), 20) + .setTemperature(EnumTemperature.ICY).setIsSecret().setIsNotCounted().setHasEffect(); + // 35 Solstice + Allele.speciesTricky = new AlleleBeeSpecies("speciesTricky", false, "bees.species.tricky", festive, "libita", 0x49413B, 0xFF6A00) + .addProduct(ForestryItem.beeComb.getItemStack(1, 0), 40).addProduct(new ItemStack(Items.cookie), 15) + .addSpecialty(new ItemStack(Items.skull, 1, 0), 2).addSpecialty(new ItemStack(Items.skull, 1, 2), 2) + .addSpecialty(new ItemStack(Items.skull, 1, 3), 2).addSpecialty(new ItemStack(Items.skull, 1, 4), 2) + .setIsSecret().setIsNotCounted().setHasEffect(); + // 37 Thanksgiving + + // Agrarian branch + Allele.speciesRural = new AlleleBeeSpecies("speciesRural", false, "bees.species.rural", agrarian, "rustico", 0xfeff8f, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 14), 20).setIsSecret(); + // 41 Farmerly + // 42 Agrarian + + // Boggy branch + Allele.speciesMarshy = new AlleleBeeSpecies("speciesMarshy", true, "bees.species.marshy", boggy, "adorasti", 0x546626, 0xffdc16).addProduct( + ForestryItem.beeComb.getItemStack(1, 15), 30).setHumidity(EnumHumidity.DAMP); + // 44 speciesMiry + // 45 speciesBoggy + + // Monastic branch + Allele.speciesMonastic = new AlleleBeeSpecies("speciesMonastic", false, "bees.species.monastic", monastic, "monachus", 0x42371c, 0xfff7b6) + .addProduct(ForestryItem.beeComb.getItemStack(1, 14), 30).addSpecialty(ForestryItem.beeComb.getItemStack(1, 16), 10) + .setJubilanceProvider(new JubilanceProviderHermit()).setIsSecret(); + Allele.speciesSecluded = new AlleleBeeSpecies("speciesSecluded", true, "bees.species.secluded", monastic, "contractus", 0x7b6634, 0xfff7b6) + .addSpecialty(ForestryItem.beeComb.getItemStack(1, 16), 20).setJubilanceProvider(new JubilanceProviderHermit()).setIsSecret(); + Allele.speciesHermitic = new AlleleBeeSpecies("speciesHermitic", false, "bees.species.hermitic", monastic, "anachoreta", 0xffd46c, 0xfff7b6) + .addSpecialty(ForestryItem.beeComb.getItemStack(1, 16), 20).setJubilanceProvider(new JubilanceProviderHermit()).setHasEffect().setIsSecret(); + + // / BEES // FLOWER PROVIDERS 1500 - 1599 + Allele.flowersVanilla = new AlleleFlowers("flowersVanilla", new FlowerProviderVanilla(), true); + Allele.flowersNether = new AlleleFlowers("flowersNether", new FlowerProviderNetherwart()); + Allele.flowersCacti = new AlleleFlowers("flowersCacti", new FlowerProviderCacti()); + Allele.flowersMushrooms = new AlleleFlowers("flowersMushrooms", new FlowerProviderMushroom()); + Allele.flowersEnd = new AlleleFlowers("flowersEnd", new FlowerProviderEnd()); + Allele.flowersJungle = new AlleleFlowers("flowersJungle", new FlowerProviderJungle()); + Allele.flowersSnow = new AlleleFlowers("flowersSnow", new FlowerProviderVanilla(), true); + Allele.flowersWheat = new AlleleFlowers("flowersWheat", new FlowerProviderWheat(), true); + Allele.flowersGourd = new AlleleFlowers("flowersGourd", new FlowerProviderGourd(), true); + + // / BEES // EFFECTS 1800 - 1899 + Allele.effectNone = new AlleleEffectNone("effectNone"); + Allele.effectAggressive = new AlleleEffectAggressive("effectAggressive"); + Allele.effectHeroic = new AlleleEffectHeroic("effectHeroic"); + Allele.effectBeatific = new AlleleEffectPotion("effectBeatific", "beatific", false, Potion.regeneration, 100, true); + Allele.effectMiasmic = new AlleleEffectMiasmic("effectMiasmic"); + Allele.effectMisanthrope = new AlleleEffectMisanthrope("effectMisanthrope"); + Allele.effectGlacial = new AlleleEffectGlacial("effectGlacial"); + Allele.effectRadioactive = new AlleleEffectRadioactive("effectRadioactive"); + Allele.effectCreeper = new AlleleEffectCreeper("effectCreeper"); + Allele.effectIgnition = new AlleleEffectIgnition("effectIgnition"); + Allele.effectExploration = new AlleleEffectExploration("effectExploration"); + Allele.effectFestiveEaster = new AlleleEffectNone("effectFestiveEaster"); + Allele.effectSnowing = new AlleleEffectSnowing("effectSnowing"); + Allele.effectDrunkard = new AlleleEffectPotion("effectDrunkard", "drunkard", false, Potion.confusion, 100, false); + Allele.effectReanimation = new AlleleEffectResurrection("effectReanimation", "reanimation", AlleleEffectResurrection.getReanimationList()); + Allele.effectResurrection = new AlleleEffectResurrection("effectResurrection", "resurrection", AlleleEffectResurrection.getResurrectionList()); + Allele.effectRepulsion = new AlleleEffectRepulsion("effectRepulsion"); + + } + + private void createMutations() { + // / MUTATIONS + BeeTemplates.commonA = new BeeMutation(Allele.speciesForest, Allele.speciesMeadows, BeeTemplates.getCommonTemplate(), 15); + + BeeTemplates.commonB = new BeeMutation(Allele.speciesModest, Allele.speciesForest, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonC = new BeeMutation(Allele.speciesModest, Allele.speciesMeadows, BeeTemplates.getCommonTemplate(), 15); + + BeeTemplates.commonD = new BeeMutation(Allele.speciesWintry, Allele.speciesForest, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonE = new BeeMutation(Allele.speciesWintry, Allele.speciesMeadows, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonF = new BeeMutation(Allele.speciesWintry, Allele.speciesModest, BeeTemplates.getCommonTemplate(), 15); + + BeeTemplates.commonG = new BeeMutation(Allele.speciesTropical, Allele.speciesForest, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonH = new BeeMutation(Allele.speciesTropical, Allele.speciesMeadows, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonI = new BeeMutation(Allele.speciesTropical, Allele.speciesModest, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonJ = new BeeMutation(Allele.speciesTropical, Allele.speciesWintry, BeeTemplates.getCommonTemplate(), 15); + + BeeTemplates.commonK = new BeeMutation(Allele.speciesMarshy, Allele.speciesForest, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonL = new BeeMutation(Allele.speciesMarshy, Allele.speciesMeadows, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonM = new BeeMutation(Allele.speciesMarshy, Allele.speciesModest, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonN = new BeeMutation(Allele.speciesMarshy, Allele.speciesWintry, BeeTemplates.getCommonTemplate(), 15); + BeeTemplates.commonO = new BeeMutation(Allele.speciesMarshy, Allele.speciesTropical, BeeTemplates.getCommonTemplate(), 15); + + BeeTemplates.cultivatedA = new BeeMutation(Allele.speciesCommon, Allele.speciesForest, BeeTemplates.getCultivatedTemplate(), 12); + BeeTemplates.cultivatedB = new BeeMutation(Allele.speciesCommon, Allele.speciesMeadows, BeeTemplates.getCultivatedTemplate(), 12); + BeeTemplates.cultivatedC = new BeeMutation(Allele.speciesCommon, Allele.speciesModest, BeeTemplates.getCultivatedTemplate(), 12); + BeeTemplates.cultivatedD = new BeeMutation(Allele.speciesCommon, Allele.speciesWintry, BeeTemplates.getCultivatedTemplate(), 12); + BeeTemplates.cultivatedE = new BeeMutation(Allele.speciesCommon, Allele.speciesTropical, BeeTemplates.getCultivatedTemplate(), 12); + BeeTemplates.cultivatedF = new BeeMutation(Allele.speciesCommon, Allele.speciesMarshy, BeeTemplates.getCultivatedTemplate(), 12); + + BeeTemplates.nobleA = new BeeMutation(Allele.speciesCommon, Allele.speciesCultivated, BeeTemplates.getNobleTemplate(), 10); + BeeTemplates.majesticA = new BeeMutation(Allele.speciesNoble, Allele.speciesCultivated, BeeTemplates.getMajesticTemplate(), 8); + BeeTemplates.imperialA = new BeeMutation(Allele.speciesNoble, Allele.speciesMajestic, BeeTemplates.getImperialTemplate(), 8); + + BeeTemplates.diligentA = new BeeMutation(Allele.speciesCommon, Allele.speciesCultivated, BeeTemplates.getDiligentTemplate(), 10); + BeeTemplates.unwearyA = new BeeMutation(Allele.speciesDiligent, Allele.speciesCultivated, BeeTemplates.getUnwearyTemplate(), 8); + BeeTemplates.industriousA = new BeeMutation(Allele.speciesDiligent, Allele.speciesUnweary, BeeTemplates.getIndustriousTemplate(), 8); + + BeeTemplates.heroicA = new BeeMutation(Allele.speciesSteadfast, Allele.speciesValiant, BeeTemplates.getHeroicTemplate(), 6) + .restrictBiomeType(BiomeDictionary.Type.FOREST).enableStrictBiomeCheck(); + + BeeTemplates.sinisterA = new BeeMutation(Allele.speciesModest, Allele.speciesCultivated, BeeTemplates.getSinisterTemplate(), 60) + .restrictBiomeType(BiomeDictionary.Type.NETHER); + BeeTemplates.sinisterB = new BeeMutation(Allele.speciesTropical, Allele.speciesCultivated, BeeTemplates.getSinisterTemplate(), 60) + .restrictBiomeType(BiomeDictionary.Type.NETHER); + BeeTemplates.fiendishA = new BeeMutation(Allele.speciesSinister, Allele.speciesCultivated, BeeTemplates.getFiendishTemplate(), 40) + .restrictBiomeType(BiomeDictionary.Type.NETHER); + BeeTemplates.fiendishB = new BeeMutation(Allele.speciesSinister, Allele.speciesModest, BeeTemplates.getFiendishTemplate(), 40) + .restrictBiomeType(BiomeDictionary.Type.NETHER); + BeeTemplates.fiendishC = new BeeMutation(Allele.speciesSinister, Allele.speciesTropical, BeeTemplates.getFiendishTemplate(), 40) + .restrictBiomeType(BiomeDictionary.Type.NETHER); + BeeTemplates.demonicA = new BeeMutation(Allele.speciesSinister, Allele.speciesFiendish, BeeTemplates.getDemonicTemplate(), 25) + .restrictBiomeType(BiomeDictionary.Type.NETHER); + + // Austere branch + BeeTemplates.frugalA = new BeeMutation(Allele.speciesModest, Allele.speciesSinister, BeeTemplates.getFrugalTemplate(), 16).setTemperatureRainfall(1.9f, + 2.0f, 0.0f, 0.1f); + BeeTemplates.frugalB = new BeeMutation(Allele.speciesModest, Allele.speciesFiendish, BeeTemplates.getFrugalTemplate(), 10).setTemperatureRainfall(1.9f, + 2.0f, 0.0f, 0.1f); + BeeTemplates.austereA = new BeeMutation(Allele.speciesModest, Allele.speciesFrugal, BeeTemplates.getAustereTemplate(), 8).setTemperatureRainfall(1.9f, + 2.0f, 0.0f, 0.1f); + + // Tropical branch + BeeTemplates.exoticA = new BeeMutation(Allele.speciesAustere, Allele.speciesTropical, BeeTemplates.getExoticTemplate(), 12); + BeeTemplates.edenicA = new BeeMutation(Allele.speciesExotic, Allele.speciesTropical, BeeTemplates.getEdenicTemplate(), 8); + + // Wintry branch + BeeTemplates.icyA = new BeeMutation(Allele.speciesIndustrious, Allele.speciesWintry, BeeTemplates.getIcyTemplate(), 12).setTemperature(0f, 0.15f); + BeeTemplates.glacialA = new BeeMutation(Allele.speciesIcy, Allele.speciesWintry, BeeTemplates.getGlacialTemplate(), 8).setTemperature(0f, 0.15f); + + // Festive branch + BeeTemplates.leporineA = new MutationTimeLimited(Allele.speciesMeadows, Allele.speciesForest, BeeTemplates.getLeporineTemplate(), 10, + new MutationTimeLimited.DayMonth(29, 3), new MutationTimeLimited.DayMonth(15, 4)).setIsSecret(); + BeeTemplates.merryA = new MutationTimeLimited(Allele.speciesWintry, Allele.speciesForest, BeeTemplates.getMerryTemplate(), 10, + new MutationTimeLimited.DayMonth(21, 12), new MutationTimeLimited.DayMonth(27, 12)).setIsSecret(); + BeeTemplates.tipsyA = new MutationTimeLimited(Allele.speciesWintry, Allele.speciesMeadows, BeeTemplates.getTipsyTemplate(), 10, + new MutationTimeLimited.DayMonth(27, 12), new MutationTimeLimited.DayMonth(2, 1)).setIsSecret(); + BeeTemplates.trickyA = new MutationTimeLimited(Allele.speciesSinister, Allele.speciesCommon, BeeTemplates.getTrickyTemplate(), 10, + new MutationTimeLimited.DayMonth(15, 10), new MutationTimeLimited.DayMonth(3, 11)).setIsSecret(); + + // Agrarian branch + BeeTemplates.ruralA = new BeeMutation(Allele.speciesMeadows, Allele.speciesDiligent, BeeTemplates.getRuralTemplate(), 12) + .restrictBiomeType(BiomeDictionary.Type.PLAINS).enableStrictBiomeCheck(); + + // Monastic branch + BeeTemplates.secludedA = new BeeMutation(Allele.speciesMonastic, Allele.speciesAustere, BeeTemplates.getSecludedTemplate(), 12); + BeeTemplates.hermiticA = new BeeMutation(Allele.speciesMonastic, Allele.speciesSecluded, BeeTemplates.getHermiticTemplate(), 8); + + // End branch + BeeTemplates.spectralA = new BeeMutation(Allele.speciesHermitic, Allele.speciesEnded, BeeTemplates.getSpectralTemplate(), 4); + BeeTemplates.phantasmalA = new BeeMutation(Allele.speciesSpectral, Allele.speciesEnded, BeeTemplates.getPhantasmalTemplate(), 2); + + // Vindictive branch + BeeTemplates.vindictiveA = new BeeMutation(Allele.speciesMonastic, Allele.speciesDemonic, BeeTemplates.getVindictiveTemplate(), 4).setIsSecret(); + + BeeTemplates.vengefulA = new BeeMutation(Allele.speciesDemonic, Allele.speciesVindictive, BeeTemplates.getVengefulTemplate(), 8).setIsSecret(); + BeeTemplates.vengefulB = new BeeMutation(Allele.speciesMonastic, Allele.speciesVindictive, BeeTemplates.getVengefulTemplate(), 8).setIsSecret(); + BeeTemplates.avengingA = new BeeMutation(Allele.speciesVengeful, Allele.speciesVindictive, BeeTemplates.getAvengingTemplate(), 4); + } + + private void registerTemplates() { + beeInterface.registerTemplate(BeeTemplates.getForestTemplate()); + beeInterface.registerTemplate(BeeTemplates.getMeadowsTemplate()); + beeInterface.registerTemplate(BeeTemplates.getCommonTemplate()); + beeInterface.registerTemplate(BeeTemplates.getCultivatedTemplate()); + beeInterface.registerTemplate(BeeTemplates.getNobleTemplate()); + beeInterface.registerTemplate(BeeTemplates.getMajesticTemplate()); + beeInterface.registerTemplate(BeeTemplates.getImperialTemplate()); + beeInterface.registerTemplate(BeeTemplates.getDiligentTemplate()); + beeInterface.registerTemplate(BeeTemplates.getUnwearyTemplate()); + beeInterface.registerTemplate(BeeTemplates.getIndustriousTemplate()); + beeInterface.registerTemplate(BeeTemplates.getSteadfastTemplate()); + beeInterface.registerTemplate(BeeTemplates.getValiantTemplate()); + beeInterface.registerTemplate(BeeTemplates.getHeroicTemplate()); + beeInterface.registerTemplate(BeeTemplates.getSinisterTemplate()); + beeInterface.registerTemplate(BeeTemplates.getFiendishTemplate()); + beeInterface.registerTemplate(BeeTemplates.getDemonicTemplate()); + beeInterface.registerTemplate(BeeTemplates.getModestTemplate()); + beeInterface.registerTemplate(BeeTemplates.getFrugalTemplate()); + beeInterface.registerTemplate(BeeTemplates.getAustereTemplate()); + beeInterface.registerTemplate(BeeTemplates.getTropicalTemplate()); + beeInterface.registerTemplate(BeeTemplates.getExoticTemplate()); + beeInterface.registerTemplate(BeeTemplates.getEdenicTemplate()); + beeInterface.registerTemplate(BeeTemplates.getWintryTemplate()); + beeInterface.registerTemplate(BeeTemplates.getIcyTemplate()); + beeInterface.registerTemplate(BeeTemplates.getGlacialTemplate()); + beeInterface.registerTemplate(BeeTemplates.getVindictiveTemplate()); + beeInterface.registerTemplate(BeeTemplates.getVengefulTemplate()); + beeInterface.registerTemplate(BeeTemplates.getAvengingTemplate()); + beeInterface.registerTemplate(BeeTemplates.getDarkenedTemplate()); + beeInterface.registerTemplate(BeeTemplates.getReddenedTemplate()); + beeInterface.registerTemplate(BeeTemplates.getOmegaTemplate()); + beeInterface.registerTemplate(BeeTemplates.getRuralTemplate()); + beeInterface.registerTemplate(BeeTemplates.getLeporineTemplate()); + beeInterface.registerTemplate(BeeTemplates.getMerryTemplate()); + beeInterface.registerTemplate(BeeTemplates.getTipsyTemplate()); + beeInterface.registerTemplate(BeeTemplates.getTrickyTemplate()); + beeInterface.registerTemplate(BeeTemplates.getMarshyTemplate()); + beeInterface.registerTemplate(BeeTemplates.getMonasticTemplate()); + beeInterface.registerTemplate(BeeTemplates.getSecludedTemplate()); + beeInterface.registerTemplate(BeeTemplates.getHermiticTemplate()); + beeInterface.registerTemplate(BeeTemplates.getEnderTemplate()); + beeInterface.registerTemplate(BeeTemplates.getSpectralTemplate()); + beeInterface.registerTemplate(BeeTemplates.getPhantasmalTemplate()); + } + + private void parseAdditionalFlowers(String list, ArrayList target) { + String[] parts = list.split("[;]+"); + + for (String part : parts) { + if (part.isEmpty()) + continue; + + String[] ident = part.split("[:]+"); + + if (ident.length != 1 && ident.length != 2) { + Proxies.log.warning("Failed to add flower of (" + part + ") to vanilla flower provider since it isn't formatted properly."); + continue; + } + + Item item = GameData.itemRegistry.getObject(ident[0]); + + if (item == null) { + Block block = GameData.blockRegistry.getObject(ident[0]); + + if (block == null || block == Blocks.air || Item.getItemFromBlock(block) == null) { + Proxies.log.warning("Failed to add flower of (" + part + ") to vanilla flower provider since it couldn't be found."); + continue; + } + + item = Item.getItemFromBlock(block); + } + + int meta = ident.length > 1 ? Integer.parseInt(ident[1]) : 0; + + Proxies.log.finer("Adding flower of (" + part + ") to vanilla flower provider."); + target.add(new ItemStack(item, 1, meta)); + } + } + + private void parseBeeBlacklist(String list) { + String[] items = list.split("[;]+"); + + for (String item : items) { + if (item.isEmpty()) + continue; + + FMLCommonHandler.instance().getFMLLogger().debug("Blacklisting bee species identified by " + item); + AlleleManager.alleleRegistry.blacklistAllele(item); + } + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return new SaveEventHandlerApiculture(); + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } + + @Override + public ICommand[] getConsoleCommands() { + return new ICommand[] { new CommandBeekeepingMode(), new CommandGiveBee(EnumBeeType.DRONE), new CommandGiveBee(EnumBeeType.PRINCESS), + new CommandGiveBee(EnumBeeType.QUEEN), }; + } + + @Override + public boolean processIMCMessage(IMCMessage message) { + if (message.key.equals("add-candle-lighting-id")) { + ItemStack value = message.getItemStackValue(); + if (value != null) { + ((BlockCandle) ForestryBlock.candle).addItemToLightingList(value.getItem()); + } else { + Logger.getLogger("Forestry").log(Level.WARNING, + "Recieved an invalid 'add-candle-lighting-id' request from mod %s. Please contact the author and report this issue.", + message.getSender()); + } + return true; + } + else if (message.key.equals("add-alveary-slab") && message.isStringMessage()) { + try { + Block block = GameData.blockRegistry.getObject(message.getStringValue()); + + if (block == null || block == Blocks.air) { + Logger.getLogger("Forestry").log(Level.WARNING, + "Recieved an invalid 'add-alveary-slab' request from mod %s. Please contact the author and report this issue.", + message.getSender()); + } else { + StructureLogicAlveary.slabBlocks.add(block); + } + } catch (Exception e) { + } + } + return super.processIMCMessage(message); + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public void textureHook(TextureStitchEvent.Pre event) { + if (event.map.getTextureType() == 1) { + EntitySnowFX.icons = new IIcon[3]; + for (int i = 0; i < EntitySnowFX.icons.length; i++) { + EntitySnowFX.icons[i] = event.map.registerIcon("forestry:particles/snow." + (i + 1)); + } + } + } +} diff --git a/forestry_common/apiculture/forestry/plugins/PluginEE.java b/forestry_common/apiculture/forestry/plugins/PluginEE.java new file mode 100755 index 000000000..1b99e8a71 --- /dev/null +++ b/forestry_common/apiculture/forestry/plugins/PluginEE.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.lang.reflect.Field; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.core.IPlugin; +import forestry.api.core.PluginInfo; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IMutation; +import forestry.apiculture.genetics.AlleleBeeSpecies; +import forestry.apiculture.genetics.BeeTemplates; +import forestry.apiculture.genetics.IJubilanceProvider; +import forestry.apiculture.genetics.JubilanceReqRes; +import forestry.apiculture.genetics.MutationEMC; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.genetics.Allele; +import forestry.core.proxy.Proxies; + +@PluginInfo(pluginID = "EqEx2", name = "Equivalent Exchange 2", author = "SirSengir", url = Defaults.URL, description = "Compatibility plugin for Equivalent Exchange 2. Enables the Omega branch of bees. Requires Apiculture to be enabled.") +public class PluginEE implements IPlugin { + + public IMutation darkenedA; + public IMutation reddenedA; + public IMutation omegaA; + + public ItemStack eeBlock1; + public ItemStack eeBlock2; + + public Class eeRelay2Class; + public Class eeRelay3Class; + public Field eeRelay2EMCField; + public Field eeRelay3EMCField; + + @Override + public boolean isAvailable() { + return Proxies.common.isModLoaded("mod_EE") && !Config.disableApiculture; + } + + @Override + public void postInit() { + + try { + + eeBlock1 = new ItemStack((Block) Class.forName("ee.EEBlock").getField("eeStone").get(null), 1, 8); + eeBlock2 = new ItemStack((Block) Class.forName("ee.EEBlock").getField("eeStone").get(null), 1, 9); + eeRelay2Class = Class.forName("ee.TileRelay2"); + eeRelay2EMCField = eeRelay2Class.getField("scaledEnergy"); + eeRelay3Class = Class.forName("ee.TileRelay3"); + eeRelay3EMCField = eeRelay3Class.getField("scaledEnergy"); + + } catch (Exception ex) { + Proxies.log.fine("Necessary block/classes from EE were not found"); + return; + } + + IJubilanceProvider jubilanceProviderDarkened = new JubilanceReqRes(eeBlock1); + IJubilanceProvider jubilanceProviderReddened = new JubilanceReqRes(eeBlock2); + + ((AlleleBeeSpecies) AlleleManager.alleleRegistry.getAllele("forestry.speciesDarkened")).jubilanceProvider = jubilanceProviderDarkened; + ((AlleleBeeSpecies) AlleleManager.alleleRegistry.getAllele("forestry.speciesReddened")).jubilanceProvider = jubilanceProviderReddened; + ((AlleleBeeSpecies) AlleleManager.alleleRegistry.getAllele("forestry.speciesOmega")).jubilanceProvider = jubilanceProviderReddened; + + darkenedA = new MutationEMC(Allele.speciesModest, Allele.speciesWintry, BeeTemplates.getDarkenedTemplate(), 100, eeBlock1, eeRelay2Class, + eeRelay2EMCField, 139264); + reddenedA = new MutationEMC(Allele.speciesDarkened, Allele.speciesTropical, BeeTemplates.getReddenedTemplate(), 100, eeBlock2, eeRelay3Class, + eeRelay3EMCField, 466944); + omegaA = new MutationEMC(Allele.speciesDarkened, Allele.speciesReddened, BeeTemplates.getOmegaTemplate(), 100, eeBlock2, eeRelay3Class, + eeRelay3EMCField, 933888).restrictBiomeType(BiomeDictionary.Type.NETHER).restrictBiomeType(BiomeDictionary.Type.DESERT); + + } + + @Override + public void preInit() { + } + + @Override + public void doInit() { + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/CommandSpawnForest.java b/forestry_common/arboriculture/forestry/arboriculture/CommandSpawnForest.java new file mode 100755 index 000000000..88c35192d --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/CommandSpawnForest.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.gen.feature.WorldGenerator; + +import forestry.api.world.ITreeGenData; +import forestry.arboriculture.genetics.TreeTemplates; +import forestry.arboriculture.worldgen.WorldGenBalsa; +import forestry.core.utils.CommandMC; +import forestry.plugins.PluginArboriculture; + +public class CommandSpawnForest extends CommandMC { + + public String getCommandName() { + return "spawnforest"; + } + + public String getCommandUsage(ICommandSender sender) { + return "/" + getCommandName() + " "; + } + + public void processCommand(ICommandSender sender, String[] arguments) { + + EntityPlayer player = this.getPlayerFromName(sender.getCommandSenderName()); + + int x = (int) player.posX - 16; + int y = (int) (player.posY); + int z = (int) player.posZ - 16; + + WorldGenerator gen = new WorldGenBalsa((ITreeGenData) PluginArboriculture.treeInterface.getTree(player.worldObj, + TreeTemplates.templateAsGenome(PluginArboriculture.treeInterface.getTemplate("treeBalsa")))); + + for (int i = 0; i < 16; i++) + gen.generate(player.worldObj, player.worldObj.rand, x + player.worldObj.rand.nextInt(32), y, z + player.worldObj.rand.nextInt(32)); + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/CommandSpawnTree.java b/forestry_common/arboriculture/forestry/arboriculture/CommandSpawnTree.java new file mode 100755 index 000000000..8fd1f1d6e --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/CommandSpawnTree.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.gen.feature.WorldGenerator; + +import forestry.api.world.ITreeGenData; +import forestry.arboriculture.genetics.TreeTemplates; +import forestry.arboriculture.worldgen.WorldGenBalsa; +import forestry.core.utils.CommandMC; +import forestry.plugins.PluginArboriculture; + +public class CommandSpawnTree extends CommandMC { + + public CommandSpawnTree() { + } + + public String getCommandName() { + return "spawntree"; + } + + public String getCommandUsage(ICommandSender sender) { + return "/" + getCommandName() + " "; + } + + public void processCommand(ICommandSender sender, String[] arguments) { + + EntityPlayer player = this.getPlayerFromName(sender.getCommandSenderName()); + + int x = (int) player.posX; + int y = (int) (player.posY); + int z = (int) player.posZ; + + WorldGenerator gen = new WorldGenBalsa((ITreeGenData) PluginArboriculture.treeInterface.getTree(player.worldObj, + TreeTemplates.templateAsGenome(PluginArboriculture.treeInterface.getTemplate("treeBalsa")))); + + gen.generate(player.worldObj, player.worldObj.rand, x, y, z); + + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/CommandTreekeepingMode.java b/forestry_common/arboriculture/forestry/arboriculture/CommandTreekeepingMode.java new file mode 100755 index 000000000..88bec26a1 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/CommandTreekeepingMode.java @@ -0,0 +1,241 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommand; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.api.arboriculture.IArboristTracker; +import forestry.api.arboriculture.ITreekeepingMode; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.core.config.Defaults; +import forestry.core.config.Version; +import forestry.core.proxy.Proxies; +import forestry.core.utils.CommandMC; +import forestry.core.utils.StringUtil; +import forestry.plugins.PluginArboriculture; + +public class CommandTreekeepingMode extends CommandMC { + + String[] modeStrings; + + public CommandTreekeepingMode() { + modeStrings = new String[PluginArboriculture.treeInterface.getTreekeepingModes().size()]; + for (int i = 0; i < PluginArboriculture.treeInterface.getTreekeepingModes().size(); i++) + modeStrings[i] = PluginArboriculture.treeInterface.getTreekeepingModes().get(i).getName(); + } + + @Override + public int compareTo(Object arg0) { + return this.getCommandName().compareTo(((ICommand) arg0).getCommandName()); + } + + @Override + public String getCommandName() { + return "treekeeping"; + } + + @Override + public String getCommandUsage(ICommandSender var1) { + return "/" + this.getCommandName() + " help"; + } + + @SuppressWarnings("rawtypes") + @Override + public List getCommandAliases() { + return null; + } + + @Override + public void processCommand(ICommandSender sender, String[] arguments) { + + if (arguments.length <= 0) + throw new WrongUsageException("Type '" + this.getCommandUsage(sender) + "' for help."); + + if (arguments[0].matches("list")) + listModes(sender, arguments); + else if (arguments[0].matches("info")) + listModeInfo(sender, arguments); + else if (arguments[0].matches("set")) { + if (arguments.length <= 1) + throw new WrongUsageException("/" + this.getCommandName() + " set [] "); + + World world = getWorld(sender, arguments); + String desired = arguments[arguments.length - 1]; + + ITreekeepingMode mode = PluginArboriculture.treeInterface.getTreekeepingMode(desired); + if (mode == null) + throw new CommandException("A treekeeping mode called '%s' is not available.", desired); + + PluginArboriculture.treeInterface.setTreekeepingMode(world, mode.getName()); + notifyAdmins(sender, "Treekeeping mode set to %s.", mode.getName()); + + } else if (arguments[0].matches("save")) { + if (arguments.length <= 1) + throw new WrongUsageException("/" + this.getCommandName() + " save "); + + saveStatistics(sender, arguments); + } else if (arguments[0].matches("help")) { + sendChatMessage(sender, "Format: '/" + this.getCommandName() + " '"); + sendChatMessage(sender, "Available commands:"); + sendChatMessage(sender, "- list []: lists current and available treekeeping modes."); + sendChatMessage(sender, "- info : information on treekeeping mode."); + sendChatMessage(sender, "- set [] : set treekeeping mode for world."); + sendChatMessage(sender, "- save [] : save treekeeping statistics for the given player."); + } + } + + private void saveStatistics(ICommandSender sender, String[] arguments) { + + String newLine = System.getProperty("line.separator"); + World world = getWorld(sender, arguments); + + String player = arguments[1]; + Collection statistics = new ArrayList(); + + statistics.add(String.format("Treekeeping statistics for %s on %s:", player, DateFormat.getInstance().format(new Date()))); + statistics.add(""); + statistics.add("MODE: " + PluginArboriculture.treeInterface.getTreekeepingMode(world).getName()); + statistics.add(""); + + IArboristTracker tracker = PluginArboriculture.treeInterface.getBreedingTracker(world, player); + if (tracker == null) + statistics.add("No statistics found."); + else { + statistics.add("BRED:"); + statistics.add("-----"); + statistics.add(""); + + Collection species = new ArrayList(); + for (IAllele allele : AlleleManager.alleleRegistry.getRegisteredAlleles().values()) + if (allele instanceof IAlleleTreeSpecies) + species.add((IAlleleTreeSpecies) allele); + + statistics.add(String.format("SPECIES (%s):", species.size())); + statistics.add("-------------"); + statistics.add(""); + + for (IAlleleTreeSpecies allele : species) + statistics.add(generateSpeciesListEntry(allele, tracker)); + } + + File file = new File(Proxies.common.getForestryRoot(), "config/" + Defaults.MOD.toLowerCase(Locale.ENGLISH) + "/stats/" + player + ".log"); + try { + + if (file.getParentFile() != null) + file.getParentFile().mkdirs(); + + if (!file.exists() && !file.createNewFile()) { + sendChatMessage(sender, "Log file could not be created. Failed to save statistics."); + return; + } + + if (!file.canWrite()) { + sendChatMessage(sender, "Cannot write to log file. Failed to save statistics."); + return; + } + + FileOutputStream fileout = new FileOutputStream(file); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fileout, "UTF-8")); + + writer.write("# " + Defaults.MOD + newLine + "# " + Version.getVersion() + newLine); + + for (String line : statistics) + writer.write(line + newLine); + + writer.close(); + + } catch (Exception ex) { + sendChatMessage(sender, "Write operation threw an exception. Failed to save statistics."); + ex.printStackTrace(); + } + + sendChatMessage(sender, "Saved statistics for player " + player); + } + + private String generateSpeciesListEntry(IAlleleTreeSpecies species, IArboristTracker tracker) { + String discovered = "[ ]"; + if (tracker.isDiscovered(species)) + discovered = "[ X ]"; + String blacklisted = "[ ]"; + if (AlleleManager.alleleRegistry.isBlacklisted(species.getUID())) + blacklisted = "[ BL ]"; + String notcounted = "[ ]"; + if (!species.isCounted()) + notcounted = "[ NC ]"; + + return String.format("%s %s %s\t%-40s %-20s %-20s", discovered, blacklisted, notcounted, species.getUID(), species.getName(), species.getAuthority()); + } + + private void listModes(ICommandSender sender, String[] arguments) { + World world = getWorld(sender, arguments); + + sendChatMessage(sender, "Current: " + PluginArboriculture.treeInterface.getTreekeepingMode(world).getName() + " (#" + world.getWorldInfo().getSaveVersion() + + ")"); + + String help = ""; + for (ITreekeepingMode mode : PluginArboriculture.treeInterface.getTreekeepingModes()) { + if (!help.isEmpty()) + help += ", "; + help += mode.getName(); + } + sendChatMessage(sender, "Available modes: " + help); + return; + } + + private void listModeInfo(ICommandSender sender, String[] arguments) { + if (arguments.length <= 1) + throw new WrongUsageException("/" + this.getCommandName() + " info "); + + ITreekeepingMode found = null; + for (ITreekeepingMode mode : PluginArboriculture.treeInterface.getTreekeepingModes()) + if (mode.getName().equalsIgnoreCase(arguments[1])) { + found = mode; + break; + } + + if (found == null) + throw new CommandException("No treekeeping mode called '%s' is available.", arguments[1]); + + sendChatMessage(sender, "\u00A7aMode: " + found.getName()); + for (String desc : found.getDescription()) + sendChatMessage(sender, StringUtil.localize(desc)); + } + + @Override + public boolean canCommandSenderUseCommand(ICommandSender sender) { + if (sender instanceof EntityPlayer) + return Proxies.common.isOp((EntityPlayer) sender); + else + return sender.canCommandSenderUseCommand(4, getCommandName()); + } + + @SuppressWarnings("rawtypes") + @Override + public List addTabCompletionOptions(ICommandSender sender, String[] incomplete) { + return getListOfStringsMatchingLastWord(incomplete, modeStrings); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/EventHandlerArboriculture.java b/forestry_common/arboriculture/forestry/arboriculture/EventHandlerArboriculture.java new file mode 100755 index 000000000..ed9bd0ea4 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/EventHandlerArboriculture.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import net.minecraft.tileentity.TileEntity; + +import cpw.mods.fml.common.eventhandler.Event.Result; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +import net.minecraftforge.event.entity.player.BonemealEvent; + +import forestry.api.genetics.IFruitBearer; +import forestry.arboriculture.gadgets.TileFruitPod; +import forestry.arboriculture.gadgets.TileSapling; +import forestry.core.proxy.Proxies; + +public class EventHandlerArboriculture { + + @SubscribeEvent + public void handleBonemeal(BonemealEvent event) { + + if (!Proxies.common.isSimulating(event.world)) + return; + + TileEntity tile = event.world.getTileEntity(event.x, event.y, event.z); + if (tile instanceof TileSapling) { + int result = ((TileSapling) tile).tryGrow(true); + if (result == 1 || result == 2) + event.setResult(Result.ALLOW); + } else if (tile instanceof IFruitBearer) { + IFruitBearer bearer = (IFruitBearer) tile; + if (bearer.getRipeness() <= 1.0f) { + bearer.addRipeness(1.0f); + event.setResult(Result.ALLOW); + } + } else if(tile instanceof TileFruitPod) { + if(((TileFruitPod)tile).canMature()) { + ((TileFruitPod)tile).mature(); + event.setResult(Result.ALLOW); + } + } + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/FruitProviderNone.java b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderNone.java new file mode 100755 index 000000000..57e6f55ff --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderNone.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.util.HashMap; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.arboriculture.IFruitProvider; +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.genetics.IFruitFamily; +import forestry.core.render.TextureManager; + +public class FruitProviderNone implements IFruitProvider { + + private static class OverlayType { + public final String ident; + public final short texUID; + + public OverlayType(String ident, short texUID) { + this.ident = ident; + this.texUID = texUID; + } + } + + private static HashMap overlayTypes = new HashMap(); + static { + overlayTypes.put("berries", new OverlayType("berries", (short) 1000)); + overlayTypes.put("pomes", new OverlayType("pomes", (short) 1001)); + overlayTypes.put("nuts", new OverlayType("nuts", (short) 1002)); + overlayTypes.put("citrus", new OverlayType("citrus", (short) 1003)); + overlayTypes.put("plums", new OverlayType("plums", (short) 1004)); + } + + String key; + IFruitFamily family = null; + + int ripeningPeriod = 10; + + OverlayType overlay = null; + + public FruitProviderNone(String key, IFruitFamily family) { + this.key = key; + this.family = family; + } + + public IFruitProvider setOverlay(String ident) { + overlay = overlayTypes.get(ident); + return this; + } + + @Override + public IFruitFamily getFamily() { + return family; + } + + @Override + public ItemStack[] getFruits(ITreeGenome genome, World world, int x, int y, int z, int ripeningTime) { + return new ItemStack[0]; + } + + @Override + public boolean requiresFruitBlocks() { + return false; + } + + @Override + public boolean trySpawnFruitBlock(ITreeGenome genome, World world, int x, int y, int z) { + return false; + } + + @Override + public int getColour(ITreeGenome genome, IBlockAccess world, int x, int y, int z, int ripeningTime) { + return 0xffffff; + } + + @Override + public boolean markAsFruitLeaf(ITreeGenome genome, World world, int x, int y, int z) { + return false; + } + + @Override + public int getRipeningPeriod() { + return ripeningPeriod; + } + + @Override + public ItemStack[] getProducts() { + return new ItemStack[0]; + } + + @Override + public ItemStack[] getSpecialty() { + return new ItemStack[0]; + } + + @Override + public String getDescription() { + return "fruits." + key; + } + + @Override + public short getIconIndex(ITreeGenome genome, IBlockAccess world, int x, int y, int z, int ripeningTime, boolean fancy) { + if(overlay != null) + return overlay.texUID; + else + return -1; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + if (overlay != null) + TextureManager.getInstance().registerTexUID(register, overlay.texUID, "leaves/fruits." + overlay.ident); + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/FruitProviderPod.java b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderPod.java new file mode 100755 index 000000000..2e99a4bff --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderPod.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.util.Locale; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.genetics.IFruitFamily; +import forestry.core.render.TextureManager; +import forestry.core.utils.BlockUtil; +import forestry.plugins.PluginArboriculture; + +public class FruitProviderPod extends FruitProviderNone { + + public static enum EnumPodType { + COCOA((short) 2000, (short) 2001, (short) 2002), DATES((short) 2010, (short) 2011, (short) 2012), + PAPAYA((short)2013, (short)2014, (short)2015);//, COCONUT((short)2016, (short)2017, (short)2018); + + public final short[] uids; + + private EnumPodType(short stage1, short stage2, short stage3) { + uids = new short[] { stage1, stage2, stage3 }; + } + } + + private static ItemStack[] DUMMY = new ItemStack[0]; + + private final EnumPodType type; + private final ItemStack[] drop; + + public FruitProviderPod(String key, IFruitFamily family, EnumPodType type, ItemStack... dropOnMature) { + super(key, family); + this.type = type; + this.drop = dropOnMature; + } + + @Override + public boolean requiresFruitBlocks() { + return true; + } + + @Override + public ItemStack[] getFruits(ITreeGenome genome, World world, int x, int y, int z, int ripeningTime) { + if (drop == null || drop.length == 0) + return DUMMY; + + if (ripeningTime >= 2) { + ItemStack[] dropping = new ItemStack[drop.length]; + for (int i = 0; i < drop.length; i++) + dropping[i] = drop[i].copy(); + return dropping; + } + + return DUMMY; + } + + @Override + public boolean trySpawnFruitBlock(ITreeGenome genome, World world, int x, int y, int z) { + + if (world.rand.nextFloat() > genome.getSappiness()) + return false; + + if (type == EnumPodType.COCOA) + return BlockUtil.tryPlantPot(world, x, y, z, Blocks.cocoa); + else { + return PluginArboriculture.treeInterface.setFruitBlock(world, (IAlleleFruit) genome.getActiveAllele(EnumTreeChromosome.FRUITS.ordinal()), + genome.getSappiness(), type.uids, x, y, z); + } + } + + @Override + public short getIconIndex(ITreeGenome genome, IBlockAccess world, int x, int y, int z, int ripeningTime, boolean fancy) { + return type.uids[0]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + if (type == EnumPodType.COCOA) + return; + + TextureManager.getInstance().registerTexUID(register, type.uids[0], "pods/" + type.toString().toLowerCase(Locale.ENGLISH) + ".0"); + TextureManager.getInstance().registerTexUID(register, type.uids[1], "pods/" + type.toString().toLowerCase(Locale.ENGLISH) + ".1"); + TextureManager.getInstance().registerTexUID(register, type.uids[2], "pods/" + type.toString().toLowerCase(Locale.ENGLISH) + ".2"); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/FruitProviderRandom.java b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderRandom.java new file mode 100755 index 000000000..d9b76d464 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderRandom.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.genetics.IFruitFamily; +import forestry.plugins.PluginArboriculture; + +/** + * Simple fruit provider which drops from any leaf block according to yield and either marks all leave blocks as fruit leaves or none. + */ +public class FruitProviderRandom extends FruitProviderNone { + + HashMap products = new HashMap(); + int colour = 0xffffff; + + public FruitProviderRandom(String key, IFruitFamily family, ItemStack product, float modifier) { + super(key, family); + products.put(product, modifier); + } + + public FruitProviderRandom setColour(int colour) { + this.colour = colour; + return this; + } + + @Override + public int getColour(ITreeGenome genome, IBlockAccess world, int x, int y, int z, int ripeningTime) { + return colour; + } + + @Override + public ItemStack[] getFruits(ITreeGenome genome, World world, int x, int y, int z, int ripeningTime) { + ArrayList product = new ArrayList(); + + float modeYieldMod = PluginArboriculture.treeInterface.getTreekeepingMode(world).getYieldModifier(genome, 1f); + + for (Map.Entry entry : products.entrySet()) + if (world.rand.nextFloat() <= genome.getYield() * modeYieldMod * entry.getValue()) + product.add(entry.getKey().copy()); + + return product.toArray(new ItemStack[0]); + } + + @Override + public ItemStack[] getProducts() { + return products.keySet().toArray(new ItemStack[0]); + } + + @Override + public ItemStack[] getSpecialty() { + return new ItemStack[0]; + } + + @Override + public boolean markAsFruitLeaf(ITreeGenome genome, World world, int x, int y, int z) { + return true; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/FruitProviderRipening.java b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderRipening.java new file mode 100755 index 000000000..75dbf9e84 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/FruitProviderRipening.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.genetics.IFruitFamily; +import forestry.plugins.PluginArboriculture; + +public class FruitProviderRipening extends FruitProviderNone { + + HashMap products = new HashMap(); + + int colourRipe = 0xffffff; + int colourCallow = 0xffffff; + + int diffR, diffG, diffB = 0; + + public FruitProviderRipening(String key, IFruitFamily family, ItemStack product, float modifier) { + super(key, family); + products.put(product, modifier); + } + + public FruitProviderRipening setColours(int ripe, int callow) { + colourRipe = ripe; + colourCallow = callow; + + diffR = (ripe >> 16 & 255) - (callow >> 16 & 255); + diffG = (ripe >> 8 & 255) - (callow >> 8 & 255); + diffB = (ripe & 255) - (callow & 255); + + return this; + } + + public FruitProviderRipening setRipeningPeriod(int period) { + ripeningPeriod = period; + return this; + } + + private float getRipeningStage(int ripeningTime) { + if (ripeningTime >= ripeningPeriod) + return 1.0f; + + return (float) ripeningTime / ripeningPeriod; + } + + @Override + public ItemStack[] getFruits(ITreeGenome genome, World world, int x, int y, int z, int ripeningTime) { + ArrayList product = new ArrayList(); + + float stage = getRipeningStage(ripeningTime); + if (stage < 0.5f) + return new ItemStack[0]; + + float modeYieldMod = PluginArboriculture.treeInterface.getTreekeepingMode(world).getYieldModifier(genome, 1f); + + for (Map.Entry entry : products.entrySet()) + if (world.rand.nextFloat() <= genome.getYield() * entry.getValue() * modeYieldMod * 5.0f * stage) + product.add(entry.getKey().copy()); + + return product.toArray(new ItemStack[0]); + } + + @Override + public ItemStack[] getProducts() { + return products.keySet().toArray(new ItemStack[0]); + } + + @Override + public ItemStack[] getSpecialty() { + return new ItemStack[0]; + } + + @Override + public boolean markAsFruitLeaf(ITreeGenome genome, World world, int x, int y, int z) { + return true; + } + + @Override + public int getColour(ITreeGenome genome, IBlockAccess world, int x, int y, int z, int ripeningTime) { + float stage = getRipeningStage(ripeningTime); + + int r = (colourCallow >> 16 & 255) + (int) (diffR * stage); + int g = (colourCallow >> 8 & 255) + (int) (diffG * stage); + int b = (colourCallow & 255) + (int) (diffB * stage); + + // System.out.println(String.format("Calcultated rgb %s/%s/%s from %s and %s, resulting in %s", + // r, g, b, colourCallow, stage, (r & 255) << 16 | (g & 255) << 8 | b & 255)); + return (r & 255) << 16 | (g & 255) << 8 | b & 255; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/GuiHandlerArboriculture.java b/forestry_common/arboriculture/forestry/arboriculture/GuiHandlerArboriculture.java new file mode 100755 index 000000000..48e13daaf --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/GuiHandlerArboriculture.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.arboriculture.genetics.TreeHelper; +import forestry.arboriculture.gui.ContainerTreealyzer; +import forestry.arboriculture.gui.GuiTreealyzer; +import forestry.arboriculture.items.ItemTreealyzer.TreealyzerInventory; +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; + +public class GuiHandlerArboriculture extends GuiHandlerBase { + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + + if (cleanId >= GuiId.values().length) + return null; + + switch (GuiId.values()[cleanId]) { + + case ArboristChestGUI: + return this.getNaturalistChestContainer(TreeHelper.UID, player, world, x, y, z, decodeGuiData(id)); + + case TreealyzerGUI: + ItemStack equipped = getEquippedItem(player); + if (equipped == null) + return null; + + return new ContainerTreealyzer(player.inventory, new TreealyzerInventory(player, equipped)); + + default: + return null; + + } + + } + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + + if (cleanId >= GuiId.values().length) + return null; + + switch (GuiId.values()[cleanId]) { + + case ArboristChestGUI: + return this.getNaturalistChestGui(TreeHelper.UID, player, world, x, y, z, decodeGuiData(id)); + + case TreealyzerGUI: + ItemStack equipped = getEquippedItem(player); + if (equipped == null) + return null; + + return new GuiTreealyzer(player, new TreealyzerInventory(player, equipped)); + + default: + return null; + + } + + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/IWoodTyped.java b/forestry_common/arboriculture/forestry/arboriculture/IWoodTyped.java new file mode 100755 index 000000000..dcfc0e454 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/IWoodTyped.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +public interface IWoodTyped { + WoodType getWoodType(int meta); + + String getBlockKind(); +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/PacketHandlerArboriculture.java b/forestry_common/arboriculture/forestry/arboriculture/PacketHandlerArboriculture.java new file mode 100755 index 000000000..1d09ff5a7 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/PacketHandlerArboriculture.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.io.DataInputStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; + +import forestry.arboriculture.gadgets.TileLeaves; +import forestry.arboriculture.network.PacketLeafUpdate; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.network.ILocatedPacket; +import forestry.core.network.PacketIds; +import forestry.core.proxy.Proxies; + +public class PacketHandlerArboriculture implements IPacketHandler { + + @Override + public void onPacketData(int packetID, DataInputStream data, EntityPlayer player) { + try { + + switch (packetID) { + case PacketIds.LEAF_UPDATE: + PacketLeafUpdate packet = new PacketLeafUpdate(); + packet.readData(data); + onLeafUpdate(packet); + break; + } + + } catch(Exception ex) { + ex.printStackTrace(); + } + } + + private void onLeafUpdate(PacketLeafUpdate packet) { + + TileEntity tile = ((ILocatedPacket) packet).getTarget(Proxies.common.getRenderWorld()); + if (tile instanceof TileLeaves) + ((TileLeaves) tile).fromPacket(packet); + + } + + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/VillageHandlerArboriculture.java b/forestry_common/arboriculture/forestry/arboriculture/VillageHandlerArboriculture.java new file mode 100755 index 000000000..251d94d81 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/VillageHandlerArboriculture.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.entity.passive.EntityVillager; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.village.MerchantRecipe; +import net.minecraft.village.MerchantRecipeList; + +import cpw.mods.fml.common.registry.VillagerRegistry.IVillageTradeHandler; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.plugins.PluginArboriculture; + +public class VillageHandlerArboriculture implements IVillageTradeHandler { + + @SuppressWarnings("unchecked") + @Override + public void manipulateTradesForVillager(EntityVillager villager, MerchantRecipeList recipeList, Random random) { + recipeList.add(new MerchantRecipe(new ItemStack(Items.emerald, 8), PluginArboriculture.treeInterface.getMemberStack( + PluginArboriculture.treeInterface.getTree(villager.worldObj, + PluginArboriculture.treeInterface.templateAsGenome(PluginArboriculture.treeInterface.getRandomTemplate(random))), + EnumGermlingType.SAPLING.ordinal()))); + + recipeList.add(new MerchantRecipe(new ItemStack(Items.emerald, 2), ForestryItem.grafterProven.getItemStack())); + + WoodType sells = WoodType.VALUES[random.nextInt(WoodType.VALUES.length)]; + Block plankBlock; + int meta; + if(!sells.hasPlank) { + plankBlock = ForestryBlock.planks1; + meta = 0; + } else if(sells.ordinal() > 15) { + plankBlock = ForestryBlock.planks2; + meta = sells.ordinal() - 16; + } else { + plankBlock = ForestryBlock.planks1; + meta = sells.ordinal(); + } + + recipeList.add(new MerchantRecipe(new ItemStack(Items.emerald, 1), new ItemStack(plankBlock, 32, meta))); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/WoodType.java b/forestry_common/arboriculture/forestry/arboriculture/WoodType.java new file mode 100755 index 000000000..6f6f32476 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/WoodType.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.util.Locale; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.render.TextureManager; + +public enum WoodType { + LARCH, TEAK, ACACIA, LIME, CHESTNUT, WENGE, BAOBAB, SEQUOIA(4.0f), KAPOK, EBONY, MAHOGANY, BALSA(1.0f), WILLOW, WALNUT, GREENHEART(7.5f), CHERRY, MAHOE, POPLAR, PALM, PAPAYA, PINE( + 3.0f), PLUM, MAPLE, CITRUS, GIGANTEUM(2.0f, false); + + public static final WoodType[] VALUES = values(); + private final float hardness; + public final boolean hasPlank; + + private WoodType() { + this(2.0f, true); + } + + private WoodType(float hardness) { + this(hardness, true); + } + + private WoodType(float hardness, boolean hasPlank) { + this.hardness = hardness; + this.hasPlank = hasPlank; + } + + @SideOnly(Side.CLIENT) + private static IIcon[][] icons; + + @SideOnly(Side.CLIENT) + public static void registerIcons(IIconRegister register) { + icons = new IIcon[3][VALUES.length]; + for (int i = 0; i < VALUES.length; i++) + icons[0][i] = TextureManager.getInstance().registerTex(register, "wood/planks." + VALUES[i].toString().toLowerCase(Locale.ENGLISH)); + for (int i = 0; i < VALUES.length; i++) + icons[1][i] = TextureManager.getInstance().registerTex(register, "wood/bark." + VALUES[i].toString().toLowerCase(Locale.ENGLISH)); + for (int i = 0; i < VALUES.length; i++) + icons[2][i] = TextureManager.getInstance().registerTex(register, "wood/heart." + VALUES[i].toString().toLowerCase(Locale.ENGLISH)); + } + + @SideOnly(Side.CLIENT) + public IIcon getPlankIcon() { + return icons[0][ordinal()]; + } + + @SideOnly(Side.CLIENT) + public IIcon getBarkIcon() { + return icons[1][ordinal()]; + } + + @SideOnly(Side.CLIENT) + public IIcon getHeartIcon() { + return icons[2][ordinal()]; + } + + public float getHardness() { + return hardness; + } + + public void saveToCompound(NBTTagCompound compound) { + compound.setInteger("WoodType", this.ordinal()); + } + + public static WoodType getFromCompound(NBTTagCompound compound) { + + if (compound != null) { + int typeOrdinal = compound.getInteger("WoodType"); + if (typeOrdinal < WoodType.VALUES.length) + return WoodType.VALUES[typeOrdinal]; + } + + return WoodType.LARCH; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/WorldGenHelper.java b/forestry_common/arboriculture/forestry/arboriculture/WorldGenHelper.java new file mode 100755 index 000000000..fc5e97c91 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/WorldGenHelper.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture; + +import java.util.ArrayList; + +import net.minecraft.world.gen.feature.WorldGenerator; + +import forestry.api.arboriculture.ITree; +import forestry.api.genetics.IIndividual; +import forestry.api.world.IWorldGenInterface; +import forestry.plugins.PluginArboriculture; + +public class WorldGenHelper implements IWorldGenInterface { + + @SuppressWarnings("unchecked") + @Override + public Class[] getTreeGenerators(String ident) { + + ArrayList> generators = new ArrayList>(); + for (IIndividual tree : PluginArboriculture.treeInterface.getIndividualTemplates()) + if (tree.getIdent().equals(ident)) + for (Class generator : ((ITree)tree).getGenome().getPrimary().getGeneratorClasses()) + generators.add(generator); + + return generators.toArray(new Class[0]); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbFence.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbFence.java new file mode 100755 index 000000000..31d2fdd23 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbFence.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockFence; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.core.Tabs; +import forestry.arboriculture.IWoodTyped; +import forestry.arboriculture.WoodType; +import forestry.plugins.PluginArboriculture; + +public class BlockArbFence extends BlockFence implements IWoodTyped { + + public static enum FenceCat { + CAT0, CAT1 + } + + private final FenceCat cat; + + public BlockArbFence(FenceCat cat) { + super("", Material.wood); + this.cat = cat; + setHardness(2.0F); + setResistance(5.0F); + setStepSound(soundTypeWood); + setCreativeTab(Tabs.tabArboriculture); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + int count = (cat == FenceCat.CAT0 ? 16 : 8); + for (int i = 0; i < count; i++) + itemList.add(new ItemStack(this, 1, i)); + } + + @Override + public int damageDropped(int meta) { + return meta; + } + + @Override + public boolean canPlaceTorchOnTop(World world, int x, int y, int z) { + return true; + } + + @Override + public boolean canConnectFenceTo(IBlockAccess world, int x, int y, int z) { + if (!isFence(world, x, y, z)) { + Block block = world.getBlock(x, y, z); + return block != null && block.getMaterial().isOpaque() && block.renderAsNormalBlock() ? block.getMaterial() != Material.gourd : false; + } else + return true; + } + + @Override + public int getRenderType() { + return PluginArboriculture.modelIdFences; + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + WoodType.registerIcons(register); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int meta) { + return getWoodType(meta).getPlankIcon(); + } + + public boolean isFence(IBlockAccess world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + if (PluginArboriculture.validFences.contains(block)) + return true; + + return false; + } + + /* PROPERTIES */ + @Override + public boolean isWood(IBlockAccess world, int x, int y, int z) { + return true; + } + + @Override + public int getFlammability(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 20; + } + + @Override + public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return true; + } + + @Override + public int getFireSpreadSpeed(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 5; + } + + @Override + public WoodType getWoodType(int meta) { + if(cat.ordinal() * 16 + meta < WoodType.VALUES.length) + return WoodType.VALUES[cat.ordinal() * 16 + meta]; + else + return WoodType.LARCH; + } + + @Override + public String getBlockKind() { + return "fences"; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbStairs.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbStairs.java new file mode 100755 index 000000000..8a45dcf9a --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockArbStairs.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockStairs; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.Tabs; +import forestry.arboriculture.WoodType; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; + +public class BlockArbStairs extends BlockStairs { + + public BlockArbStairs(Block par2Block, int par3) { + super(par2Block, par3); + setCreativeTab(Tabs.tabArboriculture); + setHardness(2.0F); + setResistance(5.0F); + } + + public static TileStairs getStairTile(IBlockAccess world, int x, int y, int z) { + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileStairs)) + return null; + + return (TileStairs) tile; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + @SideOnly(Side.CLIENT) + public void getSubBlocks(Item item, CreativeTabs tab, List list) { + for (WoodType type : WoodType.VALUES) { + if(!type.hasPlank) + continue; + ItemStack stack = new ItemStack(item, 1, 0); + NBTTagCompound compound = new NBTTagCompound(); + type.saveToCompound(compound); + stack.setTagCompound(compound); + list.add(stack); + } + } + + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + int meta = world.getBlockMetadata(x, y, z); + if (Proxies.common.isSimulating(world) && canHarvestBlock(player, meta)) + if (!player.capabilities.isCreativeMode) { + // Handle TE'd beehives + TileEntity tile = world.getTileEntity(x, y, z); + + if (tile instanceof TileStairs) { + TileStairs stairs = (TileStairs) tile; + + ItemStack stack = new ItemStack(this, 1, 0); + NBTTagCompound compound = new NBTTagCompound(); + stairs.getType().saveToCompound(compound); + stack.setTagCompound(compound); + StackUtils.dropItemStackAsEntity(stack, world, x, y, z); + } + } + + return world.setBlockToAir(x, y, z); + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + world.removeTileEntity(x, y, z); + super.breakBlock(world, x, y, z, block, meta); + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + return new ArrayList(); + } + + @Override + public boolean hasTileEntity(int meta) { + return true; + } + + @Override + public TileEntity createTileEntity(World world, int meta) { + return new TileStairs(); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + WoodType.registerIcons(register); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + TileStairs stairs = getStairTile(world, x, y, z); + if (stairs != null && stairs.getType() != null) + return stairs.getType().getPlankIcon(); + else + return WoodType.LARCH.getPlankIcon(); + } + + @Override + public boolean getUseNeighborBrightness() { + return true; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockFruitPod.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockFruitPod.java new file mode 100755 index 000000000..502748fa5 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockFruitPod.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.ArrayList; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockCocoa; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.BlockUtil; +import forestry.core.utils.StackUtils; +import forestry.plugins.PluginArboriculture; + +public class BlockFruitPod extends BlockCocoa { + + public BlockFruitPod() { + super(); + } + + public static TileFruitPod getPodTile(IBlockAccess world, int x, int y, int z) { + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileFruitPod)) + return null; + + return (TileFruitPod) tile; + } + + @Override + public void updateTick(World world, int x, int y, int z, Random rand) { + + if (!canBlockStay(world, x, y, z)) { + dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0); + world.setBlockToAir(x, y, z); + return; + } + + TileFruitPod tile = getPodTile(world, x, y, z); + if (tile == null) + return; + + tile.onBlockTick(); + } + + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + if(Proxies.common.isSimulating(world)) { + TileFruitPod tile = getPodTile(world, x, y, z); + if (tile != null) { + for(ItemStack drop : tile.getDrop()) { + StackUtils.dropItemStackAsEntity(drop, world, x, y, z); + } + } + } + + return super.removedByPlayer(world, player, x, y, z); + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + return new ArrayList(); + } + + @Override + public boolean canBlockStay(World world, int x, int y, int z) { + return BlockUtil.getDirectionalMetadata(world, x, y, z) >= 0; + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + world.removeTileEntity(x, y, z); + super.breakBlock(world, x, y, z, block, meta); + } + + @Override + public boolean hasTileEntity(int meta) { + return true; + } + + @Override + public TileEntity createTileEntity(World world, int meta) { + return new TileFruitPod(); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private static IIcon defaultIcon; + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + defaultIcon = TextureManager.getInstance().registerTex(register, "pods/papaya.2"); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int par1, int par2) { + return defaultIcon; + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + TileFruitPod pod = getPodTile(world, x, y, z); + if (pod != null) { + IIcon podIcon = pod.getIcon(world.getBlockMetadata(x, y, z), side); + if (podIcon != null) + return podIcon; + } + + return defaultIcon; + } + + @Override + public int getRenderType() { + return PluginArboriculture.modelIdPods; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLeaves.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLeaves.java new file mode 100755 index 000000000..a92e92855 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLeaves.java @@ -0,0 +1,334 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.ArrayList; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.ColorizerFoliage; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.IToolGrafter; +import forestry.api.arboriculture.ITree; +import forestry.api.core.IToolScoop; +import forestry.api.lepidopterology.EnumFlutterType; +import forestry.api.lepidopterology.IButterfly; +import forestry.core.config.Defaults; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.StackUtils; +import forestry.plugins.PluginArboriculture; +import forestry.plugins.PluginLepidopterology; + +public class BlockLeaves extends BlockTreeContainer { + + int[] adjacentTreeBlocks; + + public BlockLeaves() { + super(Material.leaves); + this.setTickRandomly(true); + this.setHardness(0.2F); + this.setLightOpacity(1); + this.setStepSound(soundTypeGrass); + } + + public static TileLeaves getLeafTile(IBlockAccess world, int x, int y, int z) { + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileLeaves)) + return null; + + return (TileLeaves) tile; + } + + @Override + public TileEntity createNewTileEntity(World world, int meta) { + return new TileLeaves(); + } + + /* DROP HANDLING */ + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + int metadata = world.getBlockMetadata(x, y, z); + + if (Proxies.common.isSimulating(world) && canHarvestBlock(player, metadata)) { + + ItemStack held = player.inventory.getCurrentItem(); + if (held != null && held.getItem() instanceof IToolGrafter) { + float saplingModifier = 1.0f; + saplingModifier = ((IToolGrafter) held.getItem()).getSaplingModifier(held, world, player, x, y, z); + held.damageItem(1, player); + if(held.stackSize <= 0) + player.destroyCurrentEquippedItem(); + + spawnLeafDrops(world, x, y, z, metadata, saplingModifier, false); + } + } + + return world.setBlockToAir(x, y, z); + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int metadata) { + + byte offset = 1; + int shift = offset + 1; + + if (world.checkChunksExist(x - shift, y - shift, z - shift, x + shift, y + shift, z + shift)) + for (int i = -offset; i <= offset; ++i) + for (int j = -offset; j <= offset; ++j) + for (int k = -offset; k <= offset; ++k) { + Block neighborBlock = world.getBlock(x + i, y + j, z + k); + neighborBlock.beginLeavesDecay(world, x + i, y + j, z + k); + } + + spawnLeafDrops(world, x, y, z, metadata, 1.0f, true); + super.breakBlock(world, x, y, z, block, metadata); + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + return StackUtils.EMPTY_STACK_LIST; + } + + private void removeLeaves(World world, int x, int y, int z) { + this.spawnLeafDrops(world, x, y, z, world.getBlockMetadata(x, y, z), 1.0f, true); + world.setBlockToAir(x, y, z); + } + + private void spawnLeafDrops(World world, int x, int y, int z, int metadata, float saplingModifier, boolean doFruitDrop) { + for (ItemStack drop : getLeafDrop(world, x, y, z, metadata, saplingModifier, doFruitDrop)) + if (drop != null) + StackUtils.dropItemStackAsEntity(drop, world, x, y, z); + } + + private ArrayList getLeafDrop(World world, int x, int y, int z, int metadata, float saplingModifier, boolean doFruitDrop) { + ArrayList prod = new ArrayList(); + + TileLeaves tile = getLeafTile(world, x, y, z); + if (tile == null) + return prod; + + if (tile.getTree() == null) + return prod; + + // Add saplings + ITree[] saplings = tile.getTree().getSaplings(world, x, y, z, saplingModifier); + for (ITree sapling : saplings) + if (sapling != null) + prod.add(PluginArboriculture.treeInterface.getMemberStack(sapling, EnumGermlingType.SAPLING.ordinal())); + + // Add fruits + if (doFruitDrop && tile.hasFruit()) + for (ItemStack stack : tile.getTree().produceStacks(world, x, y, z, tile.getRipeningTime())) + prod.add(stack); + + return prod; + } + + /* RENDERING */ + @Override + public boolean isOpaqueCube() { + return !Proxies.render.fancyGraphicsEnabled(); + } + + @Override + public int getRenderType() { + return PluginArboriculture.modelIdLeaves; + } + + @Override + @SideOnly(Side.CLIENT) + public int getBlockColor() { + double var1 = 0.5D; + double var3 = 1.0D; + return ColorizerFoliage.getFoliageColor(var1, var3); + } + + @Override + @SideOnly(Side.CLIENT) + public int colorMultiplier(IBlockAccess world, int x, int y, int z) { + + TileLeaves leaves = getLeafTile(world, x, y, z); + if (leaves == null) + return ColorizerFoliage.getFoliageColorBasic(); + + int colour = leaves.getFoliageColour(Proxies.common.getClientInstance().thePlayer); + if (colour == PluginArboriculture.proxy.getFoliageColorBasic()) + colour = world.getBiomeGenForCoords(x, z).getBiomeFoliageColor(x, y, z); // TODO: vanilla uses a more elaborate color query + + return colour; + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private static IIcon defaultIcon; + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + defaultIcon = TextureManager.getInstance().registerTex(register, "leaves/deciduous.fancy"); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int metadata) { + return defaultIcon; + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + TileLeaves leaves = getLeafTile(world, x, y, z); + if (leaves != null) + return leaves.getIcon(Proxies.render.fancyGraphicsEnabled()); + + return defaultIcon; + } + + /* BREAKING, LEAF DECAY */ + @Override + public void updateTick(World world, int x, int y, int z, Random random) { + + super.updateTick(world, x, y, z, random); + if (!Proxies.common.isSimulating(world)) + return; + + int meta = world.getBlockMetadata(x, y, z); + + if ((meta & 8) != 0 && (meta & 4) == 0) { + byte offset = 4; + int shift = offset + 1; + byte var9 = 32; + int var10 = var9 * var9; + int var11 = var9 / 2; + + if (this.adjacentTreeBlocks == null) + this.adjacentTreeBlocks = new int[var9 * var9 * var9]; + + int var12; + + if (world.checkChunksExist(x - shift, y - shift, z - shift, x + shift, y + shift, z + shift)) { + + int var13; + int var14; + int var15; + + for (var12 = -offset; var12 <= offset; ++var12) + for (var13 = -offset; var13 <= offset; ++var13) + for (var14 = -offset; var14 <= offset; ++var14) { + Block block = world.getBlock(x + var12, y + var13, z + var14); + + if (block.canSustainLeaves(world, x + var12, y + var13, z + var14)) + this.adjacentTreeBlocks[(var12 + var11) * var10 + (var13 + var11) * var9 + var14 + var11] = 0; + else if (block.isLeaves(world, x + var12, y + var13, z + var14)) + this.adjacentTreeBlocks[(var12 + var11) * var10 + (var13 + var11) * var9 + var14 + var11] = -2; + else + this.adjacentTreeBlocks[(var12 + var11) * var10 + (var13 + var11) * var9 + var14 + var11] = -1; + } + + for (var12 = 1; var12 <= 4; ++var12) + for (var13 = -offset; var13 <= offset; ++var13) + for (var14 = -offset; var14 <= offset; ++var14) + for (var15 = -offset; var15 <= offset; ++var15) + if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + var15 + var11] == var12 - 1) { + + if (this.adjacentTreeBlocks[(var13 + var11 - 1) * var10 + (var14 + var11) * var9 + var15 + var11] == -2) + this.adjacentTreeBlocks[(var13 + var11 - 1) * var10 + (var14 + var11) * var9 + var15 + var11] = var12; + + if (this.adjacentTreeBlocks[(var13 + var11 + 1) * var10 + (var14 + var11) * var9 + var15 + var11] == -2) + this.adjacentTreeBlocks[(var13 + var11 + 1) * var10 + (var14 + var11) * var9 + var15 + var11] = var12; + + if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 - 1) * var9 + var15 + var11] == -2) + this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 - 1) * var9 + var15 + var11] = var12; + + if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 + 1) * var9 + var15 + var11] == -2) + this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11 + 1) * var9 + var15 + var11] = var12; + + if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + (var15 + var11 - 1)] == -2) + this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + (var15 + var11 - 1)] = var12; + + if (this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + var15 + var11 + 1] == -2) + this.adjacentTreeBlocks[(var13 + var11) * var10 + (var14 + var11) * var9 + var15 + var11 + 1] = var12; + } + } + + var12 = this.adjacentTreeBlocks[var11 * var10 + var11 * var9 + var11]; + + if (var12 >= 0) + world.setBlockMetadataWithNotify(x, y, z, meta & -9, Defaults.FLAG_BLOCK_SYNCH); + else + this.removeLeaves(world, x, y, z); + } + } + + @Override + public void beginLeavesDecay(World world, int x, int y, int z) { + world.setBlockMetadataWithNotify(x, y, z, world.getBlockMetadata(x, y, z) | 8, Defaults.FLAG_BLOCK_SYNCH); + } + + /* PROPERTIES */ + @Override + public int getFlammability(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 60; + } + + @Override + public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return true; + } + + @Override + public int getFireSpreadSpeed(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + if (face == ForgeDirection.DOWN) + return 20; + else if (face != ForgeDirection.UP) + return 10; + else + return 5; + } + + @Override + public boolean isLeaves(IBlockAccess world, int x, int y, int z) { + return true; + } + + @Override + public boolean onBlockActivated(World world, int x, int y, + int z, EntityPlayer player, int par6, float par7, + float par8, float par9) { + + ItemStack heldItem = player.getHeldItem(); + TileEntity tile = world.getTileEntity(x, y, z); + IButterfly caterpillar = tile instanceof TileLeaves ? ((TileLeaves) tile).getCaterpillar() : null; + if(heldItem != null && heldItem.getItem() instanceof IToolScoop + && caterpillar != null) { + StackUtils.dropItemStackAsEntity(PluginLepidopterology.butterflyInterface.getMemberStack(caterpillar, EnumFlutterType.CATERPILLAR.ordinal()), + world, x, y, z); + ((TileLeaves) tile).setCaterpillar(null); + return true; + } + + return super.onBlockActivated(world, x, y, z, player, + par6, par7, par8, par9); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLog.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLog.java new file mode 100755 index 000000000..c9a7c6dcf --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockLog.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.core.Tabs; +import forestry.arboriculture.IWoodTyped; +import forestry.arboriculture.WoodType; + +public class BlockLog extends Block implements IWoodTyped { + + public enum LogCat { + CAT0, CAT1, CAT2, CAT3, CAT4, CAT5, CAT6, CAT7 + } + + private final LogCat cat; + + public BlockLog(LogCat cat) { + + super(Material.wood); + this.cat = cat; + + setHardness(2.0F); + setResistance(5.0F); + setStepSound(soundTypeWood); + setCreativeTab(Tabs.tabArboriculture); + + } + + public static int getTypeFromMeta(int damage) { + return damage & 3; + } + + @Override + public int getRenderType() { + return Blocks.log.getRenderType(); + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + + byte radius = 4; + int boundary = radius + 1; + + if (world.checkChunksExist(x - boundary, y - boundary, z - boundary, x + boundary, y + boundary, z + boundary)) + for (int i = -radius; i <= radius; ++i) + for (int j = -radius; j <= radius; ++j) + for (int k = -radius; k <= radius; ++k) { + Block neighbor = world.getBlock(x + i, y + j, z + k); + + neighbor.beginLeavesDecay(world, x + i, y + j, z + k); + } + } + + @Override + public int onBlockPlaced(World world, int x, int y, int z, int side, float par6, float par7, float par8, int meta) { + int type = getTypeFromMeta(meta); + byte b0 = 0; + + switch (side) { + case 0: + case 1: + b0 = 0; + break; + case 2: + case 3: + b0 = 8; + break; + case 4: + case 5: + b0 = 4; + } + + return type | b0; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + if(cat == LogCat.CAT6) { + return; + } + + for (int i = 0; i < 4; i++) + itemList.add(new ItemStack(this, 1, i)); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + WoodType.registerIcons(register); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(int side, int meta) { + + int oriented = meta & 12; + + WoodType type = getWoodType(getTypeFromMeta(meta)); + switch (oriented) { + case 4: + if (side > 3) + return type.getHeartIcon(); + else + return type.getBarkIcon(); + case 8: + if (side == 2 || side == 3) + return type.getHeartIcon(); + else + return type.getBarkIcon(); + case 0: + default: + if (side < 2) + return type.getHeartIcon(); + else + return type.getBarkIcon(); + } + } + + @Override + public int damageDropped(int meta) { + return getTypeFromMeta(meta); + } + + @Override + protected ItemStack createStackedBlock(int meta) { + return new ItemStack(this, 1, getTypeFromMeta(meta)); + } + + /* PROPERTIES */ + @Override + public float getBlockHardness(World world, int x, int y, int z) { + return getWoodType(getTypeFromMeta(world.getBlockMetadata(x, y, z))).getHardness(); + } + + @Override + public int getFlammability(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 20; + } + + @Override + public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return true; + } + + @Override + public int getFireSpreadSpeed(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + if (face == ForgeDirection.DOWN) + return 20; + else if (face != ForgeDirection.UP) + return 10; + else + return 5; + } + + @Override + public boolean canSustainLeaves(IBlockAccess world, int x, int y, int z) { + return true; + } + + @Override + public boolean isWood(IBlockAccess world, int x, int y, int z) { + return true; + } + + @Override + public WoodType getWoodType(int meta) { + if(meta + cat.ordinal() * 4 < WoodType.VALUES.length) + return WoodType.VALUES[meta + cat.ordinal() * 4]; + else + return WoodType.LARCH; + } + + @Override + public String getBlockKind() { + return "log"; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockPlanks.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockPlanks.java new file mode 100755 index 000000000..7d7c0cf67 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockPlanks.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.core.Tabs; +import forestry.arboriculture.IWoodTyped; +import forestry.arboriculture.WoodType; + +public class BlockPlanks extends Block implements IWoodTyped { + + public static enum PlankCat { + CAT0, CAT1 + } + + private final PlankCat cat; + + public BlockPlanks(PlankCat cat) { + super(Material.wood); + this.cat = cat; + setResistance(5.0F); + setStepSound(soundTypeWood); + setCreativeTab(Tabs.tabArboriculture); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + int count = (cat == PlankCat.CAT0 ? 16 : 8); + for (int i = 0; i < count; i++) + itemList.add(new ItemStack(this, 1, i)); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + WoodType.registerIcons(register); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int meta) { + return getWoodType(meta).getPlankIcon(); + } + + @Override + public int damageDropped(int meta) { + return meta; + } + + /* PROPERTIES */ + @Override + public float getBlockHardness(World world, int x, int y, int z) { + return getWoodType(world.getBlockMetadata(x, y, z)).getHardness(); + } + + @Override + public boolean isWood(IBlockAccess world, int x, int y, int z) { + return true; + } + + @Override + public int getFlammability(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 20; + } + + @Override + public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return true; + } + + @Override + public int getFireSpreadSpeed(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 5; + } + + @Override + public WoodType getWoodType(int meta) { + if(cat.ordinal() * 16 + meta < WoodType.VALUES.length) + return WoodType.VALUES[cat.ordinal() * 16 + meta]; + else + return WoodType.LARCH; + } + + @Override + public String getBlockKind() { + return "planks"; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSapling.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSapling.java new file mode 100755 index 000000000..f8b0f95bf --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSapling.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.StackUtils; +import forestry.plugins.PluginArboriculture; + +public class BlockSapling extends BlockTreeContainer { + + public static TileSapling getSaplingTile(IBlockAccess world, int x, int y, int z) { + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileSapling)) + return null; + + return (TileSapling) tile; + } + + public BlockSapling() { + super(Material.plants); + + float factor = 0.4F; + setBlockBounds(0.5F - factor, 0.0F, 0.5F - factor, 0.5F + factor, factor * 2.0F, 0.5F + factor); + setStepSound(soundTypeGrass); + } + + @Override + public TileEntity createNewTileEntity(World var1, int meta) { + return new TileSapling(); + } + + /* COLLISION BOX */ + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) { + return null; + } + + /* RENDERING */ + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @Override + public int getRenderType() { + return PluginArboriculture.modelIdSaplings; + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private static IIcon defaultIcon; + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + defaultIcon = TextureManager.getInstance().registerTex(register, "germlings/sapling.treeBalsa"); + + for (IAllele allele : AlleleManager.alleleRegistry.getRegisteredAlleles().values()) { + if (allele instanceof IAlleleTreeSpecies) + ((IAlleleTreeSpecies) allele).getIconProvider().registerIcons(register); + if (allele instanceof IAlleleFruit) + ((IAlleleFruit) allele).getProvider().registerIcons(register); + } + + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int metadata) { + return defaultIcon; + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + TileSapling sapling = getSaplingTile(world, x, y, z); + if (sapling == null) + return defaultIcon; + + if (sapling.getTree() == null) + return defaultIcon; + + return sapling.getTree().getGenome().getPrimary().getGermlingIcon(EnumGermlingType.SAPLING, 0); + } + + /* PLANTING */ + @Override + public boolean canBlockStay(World world, int x, int y, int z) { + TileSapling tile = getSaplingTile(world, x, y, z); + if (tile == null) + return false; + if (tile.getTree() == null) + return false; + + return tile.getTree().canStay(world, x, y, z); + } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbour) { + if (Proxies.common.isSimulating(world) && !this.canBlockStay(world, x, y, z)) { + dropAsSapling(world, x, y, z); + world.setBlockToAir(x, y, z); + } + + } + + /* REMOVING */ + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + return new ArrayList(); + } + + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + if (Proxies.common.isSimulating(world) && canHarvestBlock(player, world.getBlockMetadata(x, y, z))) + if (!player.capabilities.isCreativeMode) + dropAsSapling(world, x, y, z); + + return world.setBlockToAir(x, y, z); + } + + private void dropAsSapling(World world, int x, int y, int z) { + if (!Proxies.common.isSimulating(world)) + return; + + TileSapling sapling = getSaplingTile(world, x, y, z); + if (sapling != null && sapling.getTree() != null) { + ItemStack saplingStack = PluginArboriculture.treeInterface.getMemberStack(sapling.getTree(), EnumGermlingType.SAPLING.ordinal()); + StackUtils.dropItemStackAsEntity(saplingStack, world, x, y, z); + } + + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSlab.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSlab.java new file mode 100755 index 000000000..ce5696dfd --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockSlab.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.List; +import java.util.Random; + +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.core.Tabs; +import forestry.arboriculture.IWoodTyped; +import forestry.arboriculture.WoodType; + +public class BlockSlab extends net.minecraft.block.BlockSlab implements IWoodTyped { + + public static enum SlabCat { + CAT0, CAT1, CAT2 + } + + private final SlabCat cat; + + public BlockSlab(SlabCat cat) { + super(false, Material.wood); + this.cat = cat; + setCreativeTab(Tabs.tabArboriculture); + setLightOpacity(0); + setHardness(2.0F); + setResistance(5.0F); + setStepSound(soundTypeWood); + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + WoodType.registerIcons(register); + } + + @Override + public IIcon getIcon(int side, int meta) { + WoodType type = WoodType.VALUES[(8 * cat.ordinal()) + (meta & 7)]; + return type.getPlankIcon(); + } + + @Override + public Item getItemDropped(int meta, Random random, int par3) { + return Item.getItemFromBlock(this); + } + + /** + * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) + */ + /*public int idPicked(World world, int x, int y, int z) { + return blockID; + }*/ + + /** + * Get the block's damage value (for use with pick block). + */ + @Override + public int getDamageValue(World world, int x, int y, int z) { + return super.getDamageValue(world, x, y, z) & 7; + } + + @Override + protected ItemStack createStackedBlock(int meta) { + return new ItemStack(Blocks.wooden_slab, 2, meta & 7); + } + + @Override + public String func_150002_b(int var1) { + return "SomeSlab"; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + for (int i = 0; i < 8; ++i) + itemList.add(new ItemStack(item, 1, i)); + } + + /* PROPERTIES */ + @Override + public int getFlammability(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 20; + } + + @Override + public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return true; + } + + @Override + public int getFireSpreadSpeed(IBlockAccess world, int x, int y, int z, ForgeDirection face) { + return 5; + } + + @Override + public WoodType getWoodType(int meta) { + if(meta + cat.ordinal() * 8 < WoodType.VALUES.length) + return WoodType.VALUES[meta + cat.ordinal() * 8]; + else + return WoodType.LARCH; + } + + @Override + public String getBlockKind() { + return "slab"; + } + + @Override + public boolean getUseNeighborBrightness() { + return true; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockTreeContainer.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockTreeContainer.java new file mode 100755 index 000000000..a730fd0d8 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/BlockTreeContainer.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.Random; + +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public abstract class BlockTreeContainer extends BlockContainer { + + public BlockTreeContainer(Material material) { + super(material); + setTickRandomly(true); + } + + @Override + public void updateTick(World world, int x, int y, int z, Random rand) { + + if (world.rand.nextFloat() > 0.1) + return; + + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileTreeContainer)) + return; + + ((TileTreeContainer) tile).onBlockTick(); + } + + @Override + public boolean hasTileEntity(int metadata) { + return true; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileArboristChest.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileArboristChest.java new file mode 100755 index 000000000..060dafdff --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileArboristChest.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import forestry.api.genetics.AlleleManager; +import forestry.arboriculture.genetics.TreeHelper; +import forestry.core.gadgets.TileNaturalistChest; +import forestry.core.network.GuiId; + +public class TileArboristChest extends TileNaturalistChest { + public TileArboristChest() { + super(AlleleManager.alleleRegistry.getSpeciesRoot(TreeHelper.UID), GuiId.ArboristChestGUI.ordinal()); + } + + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileFruitPod.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileFruitPod.java new file mode 100755 index 000000000..0c2809f12 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileFruitPod.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.Packet; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IFruitBearer; +import forestry.api.genetics.IFruitFamily; +import forestry.core.network.ForestryPacket; +import forestry.core.network.INetworkedEntity; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; + +public class TileFruitPod extends TileEntity implements INetworkedEntity, IFruitBearer { + + private static final short MAX_MATURITY = 2; + + private IAlleleFruit allele; + + private short maturity; + private int[] indices = new int[0]; + private float sappiness; + + public void setFruit(IAlleleFruit allele, float sappiness, short[] indices) { + this.allele = allele; + this.sappiness = sappiness; + this.indices = new int[indices.length]; + for (int i = 0; i < indices.length; i++) + this.indices[i] = indices[i]; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + IAllele stored = AlleleManager.alleleRegistry.getAllele(nbttagcompound.getString("UID")); + if (stored != null && stored instanceof IAlleleFruit) + allele = (IAlleleFruit)stored; + else + allele = (IAlleleFruit) AlleleManager.alleleRegistry.getAllele("fruitCocoa"); + + maturity = nbttagcompound.getShort("MT"); + sappiness = nbttagcompound.getFloat("SP"); + indices = nbttagcompound.getIntArray("IN"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + if (allele != null) + nbttagcompound.setString("UID", allele.getUID()); + + nbttagcompound.setShort("MT", maturity); + nbttagcompound.setFloat("SP", sappiness); + nbttagcompound.setIntArray("IN", indices); + } + + /* UPDATING */ + /** + * This doesn't use normal TE updates + */ + @Override + public boolean canUpdate() { + return false; + } + + public void onBlockTick() { + if (canMature() && worldObj.rand.nextFloat() <= sappiness) { + mature(); + } + } + + public void mature() { + maturity++; + sendNetworkUpdateRipening(); + } + + public boolean canMature() { + return maturity < MAX_MATURITY; + } + + @SideOnly(Side.CLIENT) + public IIcon getIcon(int metadata, int side) { + if (maturity < indices.length) + return TextureManager.getInstance().getIcon((short) indices[maturity]); + else + return null; + } + + public short getMaturity() { + return maturity; + } + + public ItemStack[] getDrop() { + return allele.getProvider().getFruits(null, worldObj, xCoord, yCoord, zCoord, maturity); + } + + /* NETWORK */ + @Override + public Packet getDescriptionPacket() { + return toPacket().getPacket(); + } + + @Override + public void sendNetworkUpdate() { + Proxies.net.sendNetworkPacket(toPacket(), xCoord, yCoord, zCoord); + } + + private void sendNetworkUpdateRipening() { + Proxies.net.sendNetworkPacket(new PacketUpdate(PacketIds.TILE_UPDATE, xCoord, yCoord, zCoord, maturity), xCoord, yCoord, zCoord); + } + + private ForestryPacket toPacket() { + + PacketPayload payload = new PacketPayload(indices.length, 1); + payload.shortPayload[0] = maturity; + payload.intPayload = indices; + + return new PacketUpdate(PacketIds.TILE_UPDATE, xCoord, yCoord, zCoord, payload); + } + + @Override + public void fromPacket(ForestryPacket packetRaw) { + PacketUpdate packet = (PacketUpdate) packetRaw; + maturity = packet.payload.shortPayload[0]; + + if (packet.payload.intPayload != null && packet.payload.intPayload.length > 0) { + indices = packet.payload.intPayload; + } + + worldObj.func_147479_m(xCoord, yCoord, zCoord); + } + + /* IFRUITBEARER */ + @Override + public boolean hasFruit() { + return true ; + } + + @Override + public IFruitFamily getFruitFamily() { + if (allele == null) + return null; + return allele.getProvider().getFamily(); + } + + @Override + public Collection pickFruit(ItemStack tool) { + if (allele == null) + return new ArrayList(); + + + Collection fruits = Arrays.asList(getDrop()); + maturity = 0; + sendNetworkUpdateRipening(); + return fruits; + } + + @Override + public float getRipeness() { + return (float)maturity / MAX_MATURITY; + } + + @Override + public void addRipeness(float add) { + maturity += MAX_MATURITY * add; + sendNetworkUpdateRipening(); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileLeaves.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileLeaves.java new file mode 100755 index 000000000..6b5ed8ed8 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileLeaves.java @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.Packet; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.arboriculture.IFruitProvider; +import forestry.api.arboriculture.ILeafTickHandler; +import forestry.api.arboriculture.ITree; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IEffectData; +import forestry.api.genetics.IFruitBearer; +import forestry.api.genetics.IFruitFamily; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.api.lepidopterology.IButterfly; +import forestry.api.lepidopterology.IButterflyNursery; +import forestry.api.lepidopterology.IButterflyRoot; +import forestry.arboriculture.network.PacketLeafUpdate; +import forestry.core.genetics.Allele; +import forestry.core.network.ForestryPacket; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.Utils; +import forestry.plugins.PluginArboriculture; + +public class TileLeaves extends TileTreeContainer implements IPollinatable, IFruitBearer, IButterflyNursery { + + private int colourLeaves; + private int colourFruits; + private short textureIndexFancy = 48; + private short textureIndexPlain = 64; + private short textureIndexFruits = -1; + + private boolean isFruitLeaf; + private boolean isPollinatedState; + private int ripeningTime; + + private int maturationTime; + private int encumbrance; + + private int biomeId = -1; + + private IEffectData effectData[] = new IEffectData[2]; + + private void updateBiome() { + if(worldObj == null) + return; + BiomeGenBase biome = Utils.getBiomeAt(worldObj, xCoord, zCoord); + if (biome != null) { + this.biomeId = biome.biomeID; + } + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + isFruitLeaf = nbttagcompound.getBoolean("FL"); + ripeningTime = nbttagcompound.getInteger("RT"); + + encumbrance = nbttagcompound.getInteger("ENC"); + + if (nbttagcompound.hasKey("CATER")) { + maturationTime = nbttagcompound.getInteger("CATMAT"); + caterpillar = (IButterfly)AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies").getMember(nbttagcompound.getCompoundTag("CATER")); + } + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setBoolean("FL", isFruitLeaf); + nbttagcompound.setInteger("RT", ripeningTime); + nbttagcompound.setInteger("ENC", encumbrance); + + if (caterpillar != null) { + nbttagcompound.setInteger("CATMAT", maturationTime); + + NBTTagCompound subcompound = new NBTTagCompound(); + caterpillar.writeToNBT(subcompound); + nbttagcompound.setTag("CATER", subcompound); + } + + } + + @Override + public void onBlockTick() { + if(biomeId < 0) + updateBiome(); + + if(getTree() == null) + return; + + boolean isDestroyed = isDestroyed(); + for(ILeafTickHandler tickHandler : getTree().getGenome().getPrimary().getRoot().getLeafTickHandlers()) + if(tickHandler.onRandomLeafTick(getTree(), worldObj, biomeId, xCoord, yCoord, zCoord, isDestroyed)) + return; + + if(isDestroyed) + return; + + if(encumbrance > 0) + encumbrance--; + + if (hasFruit() && ripeningTime < Short.MAX_VALUE - 1) { + float sappiness = getTree().getGenome().getSappiness() + * PluginArboriculture.treeInterface.getTreekeepingMode(worldObj).getSappinessModifier(this.getTree().getGenome(), 1f); + + if (worldObj.rand.nextFloat() < sappiness) { + ripeningTime++; + sendNetworkUpdateRipening(); + } + } + + if(caterpillar != null) + matureCaterpillar(); + + effectData = getTree().doEffect(effectData, worldObj, biomeId, xCoord, yCoord, zCoord); + } + + @Override + public void setTree(ITree tree) { + if (tree.canBearFruit()) + isFruitLeaf = tree.getGenome().getFruitProvider().markAsFruitLeaf(tree.getGenome(), worldObj, xCoord, yCoord, zCoord); + super.setTree(tree); + } + + /* INFORMATION */ + private boolean isDestroyed() { + if(getTree() == null) + return false; + return encumbrance > getTree().getResilience(); + } + + public boolean isPollinated() { + return !isDestroyed() && getTree() != null && getTree().getMate() != null; + } + + public int getFoliageColour(EntityPlayer player) { + return isPollinatedState & Utils.hasNaturalistEye(player) ? 0xffffff : colourLeaves; + } + + public int getFruitColour() { + return colourFruits; + } + + @SideOnly(Side.CLIENT) + public IIcon getIcon(boolean fancy) { + if (fancy) + return TextureManager.getInstance().getIcon(textureIndexFancy); + else + return TextureManager.getInstance().getIcon(textureIndexPlain); + } + + @SideOnly(Side.CLIENT) + public IIcon getFruitTexture() { + if (textureIndexFruits >= 0) + return TextureManager.getInstance().getIcon(textureIndexFruits); + else + return null; + } + + public int getRipeningTime() { + return ripeningTime; + } + + /* IPOLLINATABLE */ + @Override + public EnumSet getPlantType() { + if (getTree() == null) + return EnumSet.noneOf(EnumPlantType.class); + + return getTree().getPlantTypes(); + } + + @Override + public boolean canMateWith(IIndividual individual) { + if (getTree() == null) + return false; + if (getTree().getMate() != null) + return false; + + return !getTree().isGeneticEqual(individual); + } + + @Override + public void mateWith(IIndividual individual) { + if (getTree() == null) + return; + + getTree().mate((ITree) individual); + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + @Override + public IIndividual getPollen() { + return getTree(); + } + + public int determineFoliageColour() { + + if (getTree() == null) + return PluginArboriculture.proxy.getFoliageColorBasic(); + + int colour = getTree().getGenome().getPrimary().getLeafColour(getTree()); + + if(isDestroyed()) + return Utils.addRGBComponents(colour, 92, 61, 0); + else if(caterpillar != null) + return Utils.multiplyRGBComponents(colour, 1.5f); + return colour; + } + + public int determineFruitColour() { + if (getTree() == null) + return 0xffffff; + + IFruitProvider fruit = getTree().getGenome().getFruitProvider(); + return fruit.getColour(getTree().getGenome(), worldObj, xCoord, yCoord, zCoord, getRipeningTime()); + } + + public short determineTextureIndex(boolean fancy) { + if (getTree() != null) + return getTree().getGenome().getPrimary().getLeafIconIndex(getTree(), fancy); + + return 0; + } + + public short determineOverlayIndex() { + if (getTree() == null) + return -1; + if (!hasFruit()) + return -1; + + IFruitProvider fruit = getTree().getGenome().getFruitProvider(); + + // Hardcoded because vanilla oak trees don't show fruits. + if (getTree().getGenome().getPrimary() == Allele.treeOak && fruit == ((IAlleleFruit) Allele.fruitApple).getProvider()) + return -1; + else + return fruit.getIconIndex(getTree().getGenome(), worldObj, xCoord, yCoord, zCoord, getRipeningTime(), true); + + } + + /* NETWORK */ + @Override + public Packet getDescriptionPacket() { + return new PacketLeafUpdate(xCoord, yCoord, zCoord, this).getPacket(); + } + + @Override + public void sendNetworkUpdate() { + Proxies.net.sendNetworkPacket(new PacketLeafUpdate(xCoord, yCoord, zCoord, this), xCoord, yCoord, zCoord); + } + + private void sendNetworkUpdateRipening() { + Proxies.net.sendNetworkPacket(new PacketLeafUpdate(xCoord, yCoord, zCoord, determineFruitColour()), xCoord, yCoord, zCoord); + } + + @Override + public void fromPacket(ForestryPacket packetRaw) { + + PacketLeafUpdate packet = (PacketLeafUpdate)packetRaw; + if(packet.isRipeningUpdate()) { + colourFruits = packet.colourFruits; + } else { + isFruitLeaf = packet.isFruitLeaf(); + isPollinatedState = packet.isPollinated(); + textureIndexFancy = packet.textureIndexFancy; + textureIndexPlain = packet.textureIndexPlain; + textureIndexFruits = packet.textureIndexFruit; + colourLeaves = packet.colourLeaves; + colourFruits = packet.colourFruits; + } + + worldObj.func_147479_m(xCoord, yCoord, zCoord); + } + + /* IFRUITBEARER */ + @Override + public Collection pickFruit(ItemStack tool) { + if (!hasFruit()) + return new ArrayList(); + if (getTree() == null) + return new ArrayList(); + + ArrayList picked = new ArrayList(Arrays.asList(getTree().produceStacks(worldObj, xCoord, yCoord, zCoord, getRipeningTime()))); + ripeningTime = 0; + sendNetworkUpdateRipening(); + return picked; + } + + @Override + public IFruitFamily getFruitFamily() { + if (getTree() == null) + return null; + return getTree().getGenome().getFruitProvider().getFamily(); + } + + @Override + public float getRipeness() { + if (getTree() == null) + return 0f; + int ripeningPeriod = getTree().getGenome().getFruitProvider().getRipeningPeriod(); + if (ripeningPeriod == 0) + return 1.0f; + return (float) ripeningTime / ripeningPeriod; + } + + @Override + public boolean hasFruit() { + return isFruitLeaf && !isDestroyed(); + } + + @Override + public void addRipeness(float add) { + if (getTree() == null) + return; + ripeningTime += getTree().getGenome().getFruitProvider().getRipeningPeriod() * add; + sendNetworkUpdateRipening(); + } + + /* IBUTTERFLYNURSERY */ + private IButterfly caterpillar; + + private void matureCaterpillar() { + maturationTime++; + + boolean wasDestroyed = isDestroyed(); + encumbrance += caterpillar.getGenome().getMetabolism(); + wasDestroyed = !wasDestroyed && isDestroyed() ? true : false; + + if(maturationTime >= (float)caterpillar.getGenome().getLifespan() / (caterpillar.getGenome().getFertility()*2) + && caterpillar.canTakeFlight(worldObj, xCoord, yCoord, zCoord)) { + if(worldObj.isAirBlock(xCoord - 1, yCoord, zCoord)) { + attemptButterflySpawn(worldObj, caterpillar, xCoord - 1, yCoord, zCoord); + } else if(worldObj.isAirBlock(xCoord + 1, yCoord, zCoord)) { + attemptButterflySpawn(worldObj, caterpillar, xCoord + 1, yCoord, zCoord); + } else if(worldObj.isAirBlock(xCoord, yCoord, zCoord - 1)) { + attemptButterflySpawn(worldObj, caterpillar, xCoord, yCoord, zCoord - 1); + } else if(worldObj.isAirBlock(xCoord, yCoord, zCoord + 1)) { + attemptButterflySpawn(worldObj, caterpillar, xCoord, yCoord, zCoord + 1); + } + setCaterpillar(null); + } else if(wasDestroyed) { + sendNetworkUpdate(); + } + } + + private void attemptButterflySpawn(World world, IButterfly butterfly, double x, double y, double z) { + if(((IButterflyRoot)AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies")).spawnButterflyInWorld(world, butterfly.copy(), x, y + 0.1f, z) != null) + Proxies.log.finest("A caterpillar '%s' hatched at %s/%s/%s.", butterfly.getDisplayName(), x, y, z); + } + + @Override public World getWorld() { return worldObj; } + @Override public int getXCoord() { return xCoord; } + @Override public int getYCoord() { return yCoord; } + @Override public int getZCoord() { return zCoord; } + + @Override + public int getBiomeId() { + return 0; + } + + @Override + public EnumTemperature getTemperature() { + return null; + } + + @Override + public EnumHumidity getHumidity() { + return null; + } + + @Override public void setErrorState(int state) {} + @Override public int getErrorOrdinal() { return 0; } + @Override + public boolean addProduct(ItemStack product, boolean all) { + return false; + } + + @Override public IButterfly getCaterpillar() { return caterpillar; } + @Override public IIndividual getNanny() { return getTree(); } + + @Override + public void setCaterpillar(IButterfly butterfly) { + maturationTime = 0; + caterpillar = butterfly; + sendNetworkUpdate(); + } + + @Override + public boolean canNurse(IButterfly butterfly) { + return !isDestroyed() && caterpillar == null; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileSapling.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileSapling.java new file mode 100755 index 000000000..9a8646b4d --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileSapling.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.gen.feature.WorldGenerator; + +import forestry.plugins.PluginArboriculture; + +public class TileSapling extends TileTreeContainer { + + private int timesTicked = 0; + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + timesTicked = nbttagcompound.getInteger("TT"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("TT", timesTicked); + } + + @Override + public void onBlockTick() { + + timesTicked++; + tryGrow(false); + } + + public int tryGrow(boolean bonemealed) { + + int result = 0; + if (this.getTree() == null) + return result; + + int maturity = (int) (getTree().getRequiredMaturity() * PluginArboriculture.treeInterface.getTreekeepingMode(worldObj).getMaturationModifier( + getTree().getGenome(), 1f)); + + if (bonemealed && timesTicked < maturity) { + timesTicked++; + result = 1; + } + + if (timesTicked < maturity) + return result; + + WorldGenerator generator = this.getTree().getTreeGenerator(worldObj, xCoord, yCoord, zCoord, bonemealed); + if (generator.generate(worldObj, worldObj.rand, xCoord, yCoord, zCoord)) { + PluginArboriculture.treeInterface.getBreedingTracker(worldObj, getOwnerName()).registerBirth(getTree()); + return 2; + } + + return 3; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileStairs.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileStairs.java new file mode 100755 index 000000000..aad267a02 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileStairs.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.Packet; +import net.minecraft.tileentity.TileEntity; + +import forestry.arboriculture.WoodType; +import forestry.core.network.ForestryPacket; +import forestry.core.network.INetworkedEntity; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketTileNBT; +import forestry.core.proxy.Proxies; + +public class TileStairs extends TileEntity implements INetworkedEntity { + + private WoodType type; + + public WoodType getType() { + return this.type; + } + + public void setType(WoodType type) { + this.type = type; + sendNetworkUpdate(); + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("WT")) + type = WoodType.VALUES[nbttagcompound.getShort("WT")]; + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + if (type != null) + nbttagcompound.setShort("WT", (short) type.ordinal()); + } + + /* UPDATING */ + /** + * This doesn't use normal TE updates + */ + @Override + public boolean canUpdate() { + return false; + } + + /* INETWORKEDENTITY */ + @Override + public Packet getDescriptionPacket() { + return new PacketTileNBT(PacketIds.TILE_NBT, this).getPacket(); + } + + @Override + public void sendNetworkUpdate() { + Proxies.net.sendNetworkPacket(new PacketTileNBT(PacketIds.TILE_NBT, this), xCoord, yCoord, zCoord); + } + + @Override + public void fromPacket(ForestryPacket packetRaw) { + PacketTileNBT packet = (PacketTileNBT) packetRaw; + this.readFromNBT(packet.getTagCompound()); + worldObj.func_147479_m(xCoord, yCoord, zCoord); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileTreeContainer.java b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileTreeContainer.java new file mode 100755 index 000000000..7bb445eb4 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gadgets/TileTreeContainer.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.Packet; +import net.minecraft.tileentity.TileEntity; + +import forestry.api.arboriculture.ITree; +import forestry.arboriculture.genetics.Tree; +import forestry.core.interfaces.IOwnable; +import forestry.core.network.ForestryPacket; +import forestry.core.network.INetworkedEntity; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketTileNBT; +import forestry.core.proxy.Proxies; +import forestry.core.utils.EnumAccess; + +/** + * This is the base TE class for any block that needs to contain tree genome information. + * + * @author SirSengir + */ +public abstract class TileTreeContainer extends TileEntity implements INetworkedEntity, IOwnable { + + private ITree containedTree; + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("ContainedTree")) + containedTree = new Tree(nbttagcompound.getCompoundTag("ContainedTree")); + if (nbttagcompound.hasKey("Owner")) + owner = nbttagcompound.getString("Owner"); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + if (containedTree != null) { + NBTTagCompound subcompound = new NBTTagCompound(); + containedTree.writeToNBT(subcompound); + nbttagcompound.setTag("ContainedTree", subcompound); + } + if (owner != null) + nbttagcompound.setString("Owner", owner); + + } + + /* CLIENT INFORMATION */ + + /* CONTAINED TREE */ + public void setTree(ITree tree) { + this.containedTree = tree; + if (tree != null) + sendNetworkUpdate(); + } + + public ITree getTree() { + return this.containedTree; + } + + /* UPDATING */ + /** + * This doesn't use normal TE updates + */ + @Override + public boolean canUpdate() { + return false; + } + + /** + * Leaves and saplings will implement their logic here. + */ + public abstract void onBlockTick(); + + /* INETWORKEDENTITY */ + @Override + public Packet getDescriptionPacket() { + return new PacketTileNBT(PacketIds.TILE_NBT, this).getPacket(); + } + + @Override + public void sendNetworkUpdate() { + Proxies.net.sendNetworkPacket(new PacketTileNBT(PacketIds.TILE_NBT, this), xCoord, yCoord, zCoord); + } + + @Override + public void fromPacket(ForestryPacket packetRaw) { + PacketTileNBT packet = (PacketTileNBT) packetRaw; + this.readFromNBT(packet.getTagCompound()); + worldObj.func_147479_m(xCoord, yCoord, zCoord); + } + + /* IOWNABLE */ + public String owner = null; + + @Override + public boolean allowsRemoval(EntityPlayer player) { + return true; + } + + @Override + public boolean allowsInteraction(EntityPlayer player) { + return true; + } + + @Override + public EnumAccess getAccess() { + return EnumAccess.SHARED; + } + + @Override + public boolean isOwnable() { + return false; + } + + @Override + public boolean isOwned() { + return owner != null && !owner.isEmpty(); + } + + @Override + public String getOwnerName() { + return owner; + } + + @Override + public void setOwner(EntityPlayer player) { + this.owner = player.getGameProfile().getId(); + } + + public void setOwner(String playername) { + this.owner = playername; + } + + @Override + public boolean isOwner(EntityPlayer player) { + if (owner != null) + return owner.equals(player.getGameProfile().getId()); + else + return false; + } + + @Override + public boolean switchAccessRule(EntityPlayer player) { + return false; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleFruit.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleFruit.java new file mode 100755 index 000000000..b4bdd911d --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleFruit.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.arboriculture.IFruitProvider; +import forestry.core.genetics.Allele; + +public class AlleleFruit extends Allele implements IAlleleFruit { + + private IFruitProvider provider; + + public AlleleFruit(String uid, IFruitProvider provider) { + this(uid, provider, false); + } + + public AlleleFruit(String uid, IFruitProvider provider, boolean isDominant) { + super(uid, isDominant); + this.provider = provider; + } + + @Override + public IFruitProvider getProvider() { + return this.provider; + } + + @Override + public String getName() { + return getProvider().getDescription(); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleGrowth.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleGrowth.java new file mode 100755 index 000000000..ac5790a77 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleGrowth.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import forestry.api.arboriculture.IAlleleGrowth; +import forestry.api.arboriculture.IGrowthProvider; +import forestry.core.genetics.Allele; + +public class AlleleGrowth extends Allele implements IAlleleGrowth { + + IGrowthProvider provider; + + public AlleleGrowth(String uid, IGrowthProvider provider) { + this(uid, provider, false); + } + + public AlleleGrowth(String uid, IGrowthProvider provider, boolean isDominant) { + super(uid, isDominant); + this.provider = provider; + } + + @Override + public IGrowthProvider getProvider() { + return provider; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleLeafEffectNone.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleLeafEffectNone.java new file mode 100755 index 000000000..8fb0f81d5 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleLeafEffectNone.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; + +import forestry.api.arboriculture.IAlleleLeafEffect; +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.genetics.IEffectData; +import forestry.core.genetics.Allele; +import forestry.core.utils.Vect; + +public class AlleleLeafEffectNone extends Allele implements IAlleleLeafEffect { + + int[] DEFAULT_EFFECT_AREA = new int[] { 12, 12, 12 }; + + public AlleleLeafEffectNone(String uid) { + super(uid, true); + } + + @Override + public boolean isCombinable() { + return true; + } + + @Override + public IEffectData validateStorage(IEffectData storedData) { + return storedData; + } + + @Override + public String getName() { + return "None"; + } + + @Override + public IEffectData doEffect(ITreeGenome genome, IEffectData storedData, World world, int x, int y, int z) { + return storedData; + } + + protected AxisAlignedBB getBounding(int x, int y, int z, float modifier) { + int[] areaAr = DEFAULT_EFFECT_AREA; + Vect area = new Vect(areaAr[0], areaAr[1], areaAr[2]).multiply(modifier); + Vect offset = new Vect(-Math.round(area.x / 2), -Math.round(area.y / 2), -Math.round(area.z / 2)); + + Vect min = new Vect(x + offset.x, y + offset.y, y + offset.z); + Vect max = new Vect(x + offset.x + area.x, y + offset.y + area.y, y + offset.z + area.z); + + return AxisAlignedBB.getAABBPool().getAABB(min.x, min.y, min.z, max.x, max.y, max.z); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleTreeSpecies.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleTreeSpecies.java new file mode 100755 index 000000000..738018daf --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/AlleleTreeSpecies.java @@ -0,0 +1,289 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.api.arboriculture.ITree; +import forestry.api.arboriculture.ITreeRoot; +import forestry.api.core.IIconProvider; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IFruitFamily; +import forestry.api.genetics.IMutation; +import forestry.api.world.ITreeGenData; +import forestry.arboriculture.worldgen.WorldGenArboriculture; +import forestry.arboriculture.worldgen.WorldGenBalsa; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.AlleleSpecies; +import forestry.core.render.TextureManager; +import forestry.core.utils.Utils; + +public class AlleleTreeSpecies extends AlleleSpecies implements IAlleleTreeSpecies, IIconProvider { + + private static class LeafType { + public final String ident; + public final short fancyUID; + public final short plainUID; + public final short changedUID; + + public LeafType(String ident, short fancyUID, short plainUID, short changedUID) { + this.ident = ident; + this.fancyUID = fancyUID; + this.plainUID = plainUID; + this.changedUID = changedUID; + } + } + + private static HashMap leafTypes = new HashMap(); + static { + leafTypes.put("deciduous", new LeafType("deciduous", (short) 10, (short) 11, (short) 12)); + leafTypes.put("conifers", new LeafType("conifers", (short) 15, (short) 16, (short) 17)); + leafTypes.put("jungle", new LeafType("jungle", (short) 20, (short) 21, (short) 22)); + leafTypes.put("willow", new LeafType("willow", (short) 25, (short) 26, (short) 27)); + leafTypes.put("maple", new LeafType("maple", (short) 30, (short) 31, (short) 32)); + leafTypes.put("palm", new LeafType("palm", (short) 35, (short) 36, (short) 37)); + } + + private final ITreeRoot root; + + private Class generatorClass = WorldGenBalsa.class; + + private final int primaryColour; + //private final int secondaryColour; + + private LeafType leafType; + + private int girth = 1; + private EnumPlantType nativeType = EnumPlantType.Plains; + private final ArrayList fruits = new ArrayList(); + + private ItemStack wood; + + public AlleleTreeSpecies(String uid, boolean isDominant, String name, IClassification branch, String binomial, int primaryColor, int secondaryColor) { + super(uid, isDominant, name, branch, binomial); + + this.root = (ITreeRoot)AlleleManager.alleleRegistry.getSpeciesRoot(TreeHelper.UID); + this.primaryColour = primaryColor; + //this.secondaryColour = secondaryColor; + leafType = leafTypes.get("deciduous"); + } + + public AlleleTreeSpecies(String uid, boolean isDominant, String name, IClassification branch, String binomial, int primaryColor, + Class generator, ItemStack wood) { + this(uid, isDominant, name, branch, binomial, primaryColor, Utils.multiplyRGBComponents(primaryColor, 1.35f), generator, wood); + } + + public AlleleTreeSpecies(String uid, boolean isDominant, String name, IClassification branch, String binomial, int primaryColor, int secondaryColor, + Class generator, ItemStack wood) { + super(uid, isDominant, name, branch, binomial); + + this.root = (ITreeRoot)AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees"); + this.generatorClass = generator; + this.primaryColour = primaryColor; + //this.secondaryColour = secondaryColor; + leafType = leafTypes.get("deciduous"); + this.wood = wood; + } + + @Override + public ITreeRoot getRoot() { + return root; + } + + public AlleleTreeSpecies setPlantType(EnumPlantType type) { + this.nativeType = type; + return this; + } + + public AlleleTreeSpecies setGirth(int girth) { + this.girth = girth; + return this; + } + + public AlleleTreeSpecies addFruitFamily(IFruitFamily family) { + fruits.add(family); + return this; + } + + public AlleleTreeSpecies setLeafIndices(String ident) { + leafType = leafTypes.get(ident); + return this; + } + + public AlleleTreeSpecies setVanillaMap(int vanillaMeta) { + vanillaMap = vanillaMeta; + return this; + } + + /* RESEARCH */ + @Override + public int getComplexity() { + return 1 + getGeneticAdvancement(this, new ArrayList()); + } + + private int getGeneticAdvancement(IAllele species, ArrayList exclude) { + + int own = 1; + int highest = 0; + exclude.add(species); + + for(IMutation mutation : getRoot().getPaths(species, EnumBeeChromosome.SPECIES.ordinal())) { + if(!exclude.contains(mutation.getAllele0())) { + int otherAdvance = getGeneticAdvancement(mutation.getAllele0(), exclude); + if(otherAdvance > highest) + highest = otherAdvance; + } + if(!exclude.contains(mutation.getAllele1())) { + int otherAdvance = getGeneticAdvancement(mutation.getAllele1(), exclude); + if(otherAdvance > highest) + highest = otherAdvance; + } + } + + return own + (highest < 0 ? 0 : highest); + } + + /* OTHER */ + @Override + public EnumPlantType getPlantType() { + return nativeType; + } + + @Override + public ArrayList getSuitableFruit() { + return fruits; + } + + @Override + public int getGirth() { + return girth; + } + + @Override + public WorldGenerator getGenerator(ITree tree, World world, int x, int y, int z) { + try { + return generatorClass.getConstructor(new Class[] { ITreeGenData.class }).newInstance(new Object[] { tree }); + } catch (Exception ex) { + throw new RuntimeException("Failed to instantiate generator of class " + generatorClass.getName()); + } + } + + @SuppressWarnings("unchecked") + @Override + public Class[] getGeneratorClasses() { + return new Class[] { generatorClass }; + } + + @Override + public short getLeafIconIndex(ITree tree, boolean fancy) { + + if (!fancy) + return leafType.plainUID; + + if (tree.getMate() != null) + return leafType.changedUID; + + return leafType.fancyUID; + } + + public AlleleTreeSpecies setGenerator(Class generatorClass) { + this.generatorClass = generatorClass; + return this; + } + + @Override + public int getLeafColour(ITree tree) { + //if(tree == null) + // return primaryColour; + + //if (tree.getMate() != null) + // return secondaryColour; + //else + return primaryColour; + } + + /* ICONS */ + private int vanillaMap = -1; + + @Override + public int getIconColour(int renderPass) { + if(renderPass == 0) + return primaryColour; + return 0xffffff; + } + + @SideOnly(Side.CLIENT) + IIcon icon; + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + if (vanillaMap < 0) + icon = TextureManager.getInstance().registerTex(register, "germlings/sapling." + uid); + else + icon = Blocks.sapling.getIcon(0, vanillaMap); + TextureManager.getInstance().registerTexUID(register, leafType.plainUID, "leaves/" + leafType.ident + ".plain"); + TextureManager.getInstance().registerTexUID(register, leafType.changedUID, "leaves/" + leafType.ident + ".changed"); + TextureManager.getInstance().registerTexUID(register, leafType.fancyUID, "leaves/" + leafType.ident + ".fancy"); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getGermlingIcon(EnumGermlingType type, int renderPass) { + if(type == EnumGermlingType.POLLEN) + return ForestryItem.pollen.item().getIconFromDamageForRenderPass(0, renderPass); + + return icon; + } + + + @Override + @SideOnly(Side.CLIENT) + public int getGermlingColour(EnumGermlingType type, int renderPass) { + if(type == EnumGermlingType.SAPLING) + return 0xFFFFFF; + return getLeafColour(null); + } + + + @Override + @SideOnly(Side.CLIENT) + public IIconProvider getIconProvider() { + return this; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(short texUID) { + return TextureManager.getInstance().getIcon(texUID); + } + + @Override + public ItemStack[] getLogStacks() { + return new ItemStack[] {wood}; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/ArboristTracker.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/ArboristTracker.java new file mode 100755 index 000000000..aed6fd802 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/ArboristTracker.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.api.arboriculture.IArboristTracker; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IIndividual; +import forestry.core.genetics.BreedingTracker; +import forestry.plugins.PluginArboriculture; + +public class ArboristTracker extends BreedingTracker implements IArboristTracker { + + public ArboristTracker(String s) { + this(s, ""); + } + + public ArboristTracker(String s, String player) { + super(s, player); + } + + @Override + protected IBreedingTracker getCommonTracker(EntityPlayer player) { + return PluginArboriculture.treeInterface.getBreedingTracker(player.worldObj, "__COMMON_"); + } + + @Override + protected String getPacketTag() { + return TreeHelper.UID; + } + + @Override + public void registerPickup(IIndividual individual) { + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/BranchTrees.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/BranchTrees.java new file mode 100755 index 000000000..a73ad8dd6 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/BranchTrees.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import forestry.core.genetics.Branch; + +public class BranchTrees extends Branch { + + public BranchTrees(String uid, String scientific) { + super("trees." + uid, scientific); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProvider.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProvider.java new file mode 100755 index 000000000..24204ae92 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProvider.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.arboriculture.EnumGrowthConditions; +import forestry.api.arboriculture.IGrowthProvider; +import forestry.api.arboriculture.ITree; +import forestry.api.arboriculture.ITreeGenome; +import forestry.arboriculture.gadgets.TileSapling; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; + +public class GrowthProvider implements IGrowthProvider { + + @Override + public boolean canGrow(ITreeGenome genome, World world, int xPos, int yPos, int zPos, int expectedGirth, int expectedHeight) { + return hasRoom(genome, world, xPos, yPos, zPos, expectedGirth, expectedHeight) + && getGrowthConditions(genome, world, xPos, yPos, zPos) != EnumGrowthConditions.HOSTILE + && hasSufficientSaplings(genome, world, xPos, yPos, zPos, expectedGirth); + } + + @Override + public EnumGrowthConditions getGrowthConditions(ITreeGenome genome, World world, int xPos, int yPos, int zPos) { + return getConditionFromLight(world, xPos, yPos, zPos); + } + + @Override + public String getDescription() { + return "Light"; + } + + @Override + public String[] getInfo() { + return new String[0]; + } + + protected EnumGrowthConditions getConditionsFromRainfall(World world, int xPos, int yPos, int zPos, float min, float max) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(xPos, zPos); + if (biome.rainfall < min || biome.rainfall > max) + return EnumGrowthConditions.HOSTILE; + + return EnumGrowthConditions.EXCELLENT; + } + + protected EnumGrowthConditions getConditionsFromTemperature(World world, int xPos, int yPos, int zPos, float min, float max) { + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(xPos, zPos); + if (biome.temperature < min || biome.temperature > max) + return EnumGrowthConditions.HOSTILE; + + return EnumGrowthConditions.EXCELLENT; + } + + protected EnumGrowthConditions getConditionFromLight(World world, int xPos, int yPos, int zPos) { + int lightvalue = world.getBlockLightValue(xPos, yPos + 1, zPos); + + if (lightvalue > 13) + return EnumGrowthConditions.EXCELLENT; + else if (lightvalue > 11) + return EnumGrowthConditions.GOOD; + else if (lightvalue > 8) + return EnumGrowthConditions.NORMAL; + else if (lightvalue > 6) + return EnumGrowthConditions.PALTRY; + else + return EnumGrowthConditions.HOSTILE; + } + + /* + * protected EnumGrowthConditions getConditionFromGround(World world, int xPos, int yPos, int zPos) { Block block = Block.blocksList[world.getBlock(xPos, + * yPos - 1, zPos)]; if(block == null) return EnumGrowthConditions.HOSTILE; + * + * for(EnumPlantType type : this.validPlantTypes) { this.plantType = type; if(block.canSustainPlant(world, xPos, yPos - 1, zPos, ForgeDirection.UP, this)) + * return EnumGrowthConditions.EXCELLENT; } + * + * return EnumGrowthConditions.HOSTILE; } + */ + + protected boolean hasRoom(ITreeGenome genome, World world, int xPos, int yPos, int zPos, int expectedGirth, int expectedHeight) { + + int offset = (expectedGirth - 1) / 2; + // if(offset <= 0) + // offset = 1; + + return checkArea(world, new Vect(xPos - offset, yPos + 1, zPos + offset), + new Vect(-offset + expectedGirth, expectedHeight + 1, -offset + expectedGirth)); + } + + protected final boolean checkArea(World world, Vect start, Vect area) { + for (int x = start.x; x < start.x + area.x; x++) + for (int y = start.y; y < start.y + area.y; y++) + for (int z = start.z; z < start.z + area.z; z++) + if (!world.isAirBlock(x, y, z) && !Utils.isReplaceableBlock(world, x, y, z)) + return false; + return true; + } + + protected boolean hasSufficientSaplings(ITreeGenome genome, World world, int xPos, int yPos, int zPos, int expectedGirth) { + + if (expectedGirth == 1) + return true; + + int offset = (expectedGirth - 1) / 2; + + for (int x = xPos - offset; x < xPos - offset + expectedGirth; x++) + for (int z = zPos - offset; z < zPos - offset + expectedGirth; z++) { + + if (world.isAirBlock(x, yPos, z)) + return false; + + TileEntity tile = world.getTileEntity(x, yPos, z); + if (!(tile instanceof TileSapling)) + return false; + + ITree tree = ((TileSapling) tile).getTree(); + if (tree == null || !tree.getGenome().getPrimary().getUID().equals(genome.getPrimary().getUID())) + return false; + } + + return true; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProviderTropical.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProviderTropical.java new file mode 100755 index 000000000..aea68de0e --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/GrowthProviderTropical.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import java.util.EnumSet; + +import net.minecraft.world.World; + +import forestry.api.arboriculture.EnumGrowthConditions; +import forestry.api.arboriculture.ITreeGenome; + +public class GrowthProviderTropical extends GrowthProvider { + + @Override + public EnumGrowthConditions getGrowthConditions(ITreeGenome genome, World world, int xPos, int yPos, int zPos) { + EnumGrowthConditions light = getConditionFromLight(world, xPos, yPos, zPos); + EnumGrowthConditions moisture = getConditionsFromRainfall(world, xPos, yPos, zPos, 0.9f, 2.0f); + EnumGrowthConditions temperature = getConditionsFromTemperature(world, xPos, yPos, zPos, 1.2f, 1.9f); + + EnumSet conditions = EnumSet.of(light, moisture, temperature); + + EnumGrowthConditions result = EnumGrowthConditions.HOSTILE; + for (EnumGrowthConditions cond : conditions) { + if (cond == EnumGrowthConditions.HOSTILE) + return EnumGrowthConditions.HOSTILE; + + if (cond.ordinal() > result.ordinal()) + result = cond; + } + + return result; + } + + @Override + public String getDescription() { + return "Tropical"; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/Tree.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/Tree.java new file mode 100755 index 000000000..03db049a7 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/Tree.java @@ -0,0 +1,394 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import net.minecraftforge.common.EnumPlantType; +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.arboriculture.EnumGrowthConditions; +import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.IAlleleLeafEffect; +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.api.arboriculture.IFruitProvider; +import forestry.api.arboriculture.ITree; +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.arboriculture.ITreeMutation; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IEffectData; +import forestry.api.genetics.IFruitFamily; +import forestry.api.genetics.IGenome; +import forestry.api.world.ITreeGenData; +import forestry.core.genetics.Allele; +import forestry.core.genetics.Chromosome; +import forestry.core.genetics.Individual; +import forestry.core.utils.StringUtil; +import forestry.plugins.PluginArboriculture; + +public class Tree extends Individual implements ITree, ITreeGenData, IPlantable { + + private ITreeGenome genome; + private ITreeGenome mate; + + /* CONSTRUCTOR */ + public Tree(NBTTagCompound nbttagcompound) { + readFromNBT(nbttagcompound); + } + + public Tree(ITreeGenome genome) { + this.genome = genome; + } + + public Tree(World world, ITreeGenome genome) { + this.genome = genome; + + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("Genome")) + genome = new TreeGenome(nbttagcompound.getCompoundTag("Genome")); + else + genome = PluginArboriculture.treeInterface.templateAsGenome(TreeTemplates.getOakTemplate()); + if (nbttagcompound.hasKey("Mate")) + mate = new TreeGenome(nbttagcompound.getCompoundTag("Mate")); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + super.writeToNBT(nbttagcompound); + + if (genome != null) { + NBTTagCompound NBTmachine = new NBTTagCompound(); + genome.writeToNBT(NBTmachine); + nbttagcompound.setTag("Genome", NBTmachine); + } + if (mate != null) { + NBTTagCompound NBTmachine = new NBTTagCompound(); + mate.writeToNBT(NBTmachine); + nbttagcompound.setTag("Mate", NBTmachine); + } + + } + + /* INTERACTION */ + @Override + public void mate(ITree other) { + mate = new TreeGenome(other.getGenome().getChromosomes()); + } + + /* EFFECTS */ + @Override + public IEffectData[] doEffect(IEffectData[] storedData, World world, int biomeid, int x, int y, int z) { + IAlleleLeafEffect effect = (IAlleleLeafEffect) getGenome().getActiveAllele(EnumTreeChromosome.EFFECT.ordinal()); + + if (effect == null) + return null; + + storedData[0] = doEffect(effect, storedData[0], world, biomeid, x, y, z); + + // Return here if the primary can already not be combined + if (!effect.isCombinable()) + return storedData; + + IAlleleLeafEffect secondary = (IAlleleLeafEffect) getGenome().getInactiveAllele(EnumTreeChromosome.EFFECT.ordinal()); + if (!secondary.isCombinable()) + return storedData; + + storedData[1] = doEffect(secondary, storedData[1], world, biomeid, x, y, z); + + return storedData; + } + + private IEffectData doEffect(IAlleleLeafEffect effect, IEffectData storedData, World world, int biomeid, int x, int y, int z) { + storedData = effect.validateStorage(storedData); + return effect.doEffect(getGenome(), storedData, world, x, y, z); + } + + @Override + public IEffectData[] doFX(IEffectData[] storedData, World world, int biomeid, int x, int y, int z) { + return null; + } + + /* GROWTH */ + @Override + public WorldGenerator getTreeGenerator(World world, int x, int y, int z, boolean wasBonemealed) { + return genome.getPrimary().getGenerator(this, world, x, y, z); + } + + @Override + public boolean canStay(World world, int x, int y, int z) { + Block block = world.getBlock(x, y - 1, z); + if (block == null) + return false; + + for (EnumPlantType type : getPlantTypes()) { + this.plantType = type; + if (block.canSustainPlant(world, x, y - 1, z, ForgeDirection.UP, this)) + return true; + } + + return false; + } + + private EnumPlantType plantType; + + @Override + public EnumPlantType getPlantType(IBlockAccess world, int x, int y, int z) { + return plantType; + } + + @Override + public Block getPlant(IBlockAccess world, int x, int y, int z) { + return null; + } + + @Override + public int getPlantMetadata(IBlockAccess world, int x, int y, int z) { + return 0; + } + + @Override + public boolean canGrow(World world, int x, int y, int z, int expectedGirth, int expectedHeight) { + return genome.getGrowthProvider().canGrow(genome, world, x, y, z, expectedGirth, expectedHeight); + } + + @Override + public int getRequiredMaturity() { + return genome.getMaturationTime(); + } + + @Override + public EnumGrowthConditions getGrowthCondition(World world, int x, int y, int z) { + return genome.getGrowthProvider().getGrowthConditions(getGenome(), world, x, y, z); + } + + @Override + public int getGirth(World world, int x, int y, int z) { + return genome.getGirth(); + } + + @Override + public int getResilience() { + int base = (int)(getGenome().getFertility() * getGenome().getSappiness() * 100); + return (base > 1 ? base : 1) * 10; + } + + @Override + public float getHeightModifier() { + return genome.getHeight(); + } + + @Override + public void setLeaves(World world, String owner, int x, int y, int z) { + PluginArboriculture.treeInterface.setLeaves(world, this, owner, x, y, z); + } + + @Override + public boolean allowsFruitBlocks() { + IFruitProvider provider = getGenome().getFruitProvider(); + if (!provider.requiresFruitBlocks()) + return false; + + Collection suitable = genome.getPrimary().getSuitableFruit(); + if (!suitable.contains(provider.getFamily())) + return false; + + return true; + } + + @Override + public boolean trySpawnFruitBlock(World world, int x, int y, int z) { + IFruitProvider provider = getGenome().getFruitProvider(); + Collection suitable = genome.getPrimary().getSuitableFruit(); + if (!suitable.contains(provider.getFamily())) + return false; + + return provider.trySpawnFruitBlock(getGenome(), world, x, y, z); + } + + /* INFORMATION */ + @Override + public ITreeGenome getGenome() { + return this.genome; + } + + @Override + public ITree copy() { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + this.writeToNBT(nbttagcompound); + return new Tree(nbttagcompound); + } + + @Override + public ITreeGenome getMate() { + return this.mate; + } + + @Override + public boolean isPureBred(EnumTreeChromosome chromosome) { + return genome.getActiveAllele(chromosome.ordinal()).getUID().equals(genome.getInactiveAllele(chromosome.ordinal()).getUID()); + } + + @Override + public EnumSet getPlantTypes() { + EnumSet tolerated = genome.getPlantTypes(); + tolerated.add(genome.getPrimary().getPlantType()); + return tolerated; + } + + @Override + public void addTooltip(List list) { + + // No info 4 u! + if (!isAnalyzed) { + list.add("<" + StringUtil.localize("gui.unknown") + ">"); + return; + } + + // You analyzed it? Juicy tooltip coming up! + IAlleleTreeSpecies primary = genome.getPrimary(); + IAlleleTreeSpecies secondary = genome.getSecondary(); + if (!isPureBred(EnumTreeChromosome.SPECIES)) + list.add("\u00A79" + primary.getName() + "-" + secondary.getName() + " " + StringUtil.localize("gui.hybrid")); + list.add(String.format("\u00A76S: %s, \u00A7cM: %s", genome.getActiveAllele(EnumTreeChromosome.SAPPINESS.ordinal()).getName(), genome.getActiveAllele(EnumTreeChromosome.MATURATION.ordinal()).getName())); + list.add(String.format("\u00A7dH: %s, \u00A7bG: %sx%s", genome.getActiveAllele(EnumTreeChromosome.HEIGHT.ordinal()).getName(), genome.getGirth(), genome.getGirth())); + + list.add(String.format("\u00A7eS: %s, \u00A7fY: %s", genome.getActiveAllele(EnumTreeChromosome.FERTILITY.ordinal()).getName(), genome.getActiveAllele(EnumTreeChromosome.YIELD.ordinal()).getName())); + + IAllele fruit = getGenome().getActiveAllele(EnumTreeChromosome.FRUITS.ordinal()); + if(fruit != Allele.fruitNone) { + String strike = ""; + if (!canBearFruit()) + strike = "\u00A7m"; + list.add(strike + "\u00A7aF: " + StringUtil.localize(genome.getFruitProvider().getDescription())); + } + + } + + /* REPRODUCTION */ + @Override + public ITree[] getSaplings(World world, int x, int y, int z, float modifier) { + ArrayList prod = new ArrayList(); + + float chance = genome.getFertility() * modifier; + + if (world.rand.nextFloat() <= chance) + if (this.getMate() == null) + prod.add(PluginArboriculture.treeInterface.getTree(world, new TreeGenome(genome.getChromosomes()))); + else + prod.add(createOffspring(world, x, y, z)); + + return prod.toArray(new ITree[0]); + } + + private ITree createOffspring(World world, int x, int y, int z) { + + IChromosome[] chromosomes = new IChromosome[genome.getChromosomes().length]; + IChromosome[] parent1 = genome.getChromosomes(); + IChromosome[] parent2 = mate.getChromosomes(); + + // Check for mutation. Replace one of the parents with the mutation + // template if mutation occured. + IChromosome[] mutated = mutateSpecies(world, x, y, z, genome, mate); + if (mutated == null) + mutated = mutateSpecies(world, x, y, z, mate, genome); + + if (mutated != null) + return new Tree(world, new TreeGenome(mutated)); + + for (int i = 0; i < parent1.length; i++) + if (parent1[i] != null && parent2[i] != null) + chromosomes[i] = Chromosome.inheritChromosome(world.rand, parent1[i], parent2[i]); + + return new Tree(world, new TreeGenome(chromosomes)); + } + + private IChromosome[] mutateSpecies(World world, int x, int y, int z, IGenome genomeOne, IGenome genomeTwo) { + + IChromosome[] parent1 = genomeOne.getChromosomes(); + IChromosome[] parent2 = genomeTwo.getChromosomes(); + + IGenome genome0; + IGenome genome1; + IAllele allele0; + IAllele allele1; + + if (world.rand.nextBoolean()) { + allele0 = parent1[EnumTreeChromosome.SPECIES.ordinal()].getPrimaryAllele(); + allele1 = parent2[EnumTreeChromosome.SPECIES.ordinal()].getSecondaryAllele(); + + genome0 = genomeOne; + genome1 = genomeTwo; + } else { + allele0 = parent2[EnumTreeChromosome.SPECIES.ordinal()].getPrimaryAllele(); + allele1 = parent1[EnumTreeChromosome.SPECIES.ordinal()].getSecondaryAllele(); + + genome0 = genomeTwo; + genome1 = genomeOne; + } + + for (ITreeMutation mutation : PluginArboriculture.treeInterface.getMutations(true)) { + float chance = 0; + + // Stop blacklisted species. + // if (BeeManager.breedingManager.isBlacklisted(mutation.getTemplate()[0].getUID())) { + // continue; + // } + + if ((chance = mutation.getChance(world, x, y, z, allele0, allele1, genome0, genome1)) > 0) + if (world.rand.nextFloat()*100 < chance) + // IApiaristTracker breedingTracker = BeeManager.breedingManager.getApiaristTracker(world); + // breedingTracker.registerMutation(mutation); + return PluginArboriculture.treeInterface.templateAsChromosomes(mutation.getTemplate()); + } + + return null; + } + + /* PRODUCTION */ + @Override + public boolean canBearFruit() { + return genome.getPrimary().getSuitableFruit().contains(genome.getFruitProvider().getFamily()); + } + + @Override + public ItemStack[] getProduceList() { + return genome.getFruitProvider().getProducts(); + } + + @Override + public ItemStack[] getSpecialtyList() { + return genome.getFruitProvider().getSpecialty(); + } + + @Override + public ItemStack[] produceStacks(World world, int x, int y, int z, int ripeningTime) { + return genome.getFruitProvider().getFruits(genome, world, x, y, z, ripeningTime); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeGenome.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeGenome.java new file mode 100755 index 000000000..c4a56189d --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeGenome.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import java.util.EnumSet; + +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.arboriculture.IAlleleGrowth; +import forestry.api.arboriculture.IAlleleLeafEffect; +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.api.arboriculture.IFruitProvider; +import forestry.api.arboriculture.IGrowthProvider; +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleFloat; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.genetics.Allele; +import forestry.core.genetics.AllelePlantType; +import forestry.core.genetics.Chromosome; +import forestry.core.genetics.Genome; +import forestry.plugins.PluginArboriculture; + +public class TreeGenome extends Genome implements ITreeGenome { + + public TreeGenome(IChromosome[] chromosomes) { + super(chromosomes); + } + + public TreeGenome(NBTTagCompound nbttagcompound) { + super(nbttagcompound); + } + + @Override + public IAlleleTreeSpecies getPrimary() { + return (IAlleleTreeSpecies) getActiveAllele(EnumTreeChromosome.SPECIES.ordinal()); + } + + @Override + public IAlleleTreeSpecies getSecondary() { + return (IAlleleTreeSpecies) getInactiveAllele(EnumTreeChromosome.SPECIES.ordinal()); + } + + @Override + public IFruitProvider getFruitProvider() { + return ((IAlleleFruit) getActiveAllele(EnumTreeChromosome.FRUITS.ordinal())).getProvider(); + } + + @Override + public IGrowthProvider getGrowthProvider() { + return ((IAlleleGrowth) getActiveAllele(EnumTreeChromosome.GROWTH.ordinal())).getProvider(); + } + + @Override + public float getHeight() { + return ((IAlleleFloat) getActiveAllele(EnumTreeChromosome.HEIGHT.ordinal())).getValue(); + } + + @Override + public float getFertility() { + return ((IAlleleFloat) getActiveAllele(EnumTreeChromosome.FERTILITY.ordinal())).getValue(); + } + + @Override + public float getYield() { + return ((IAlleleFloat) getActiveAllele(EnumTreeChromosome.YIELD.ordinal())).getValue(); + } + + @Override + public float getSappiness() { + // FIXME: Legacy handling. + if (getChromosomes()[EnumTreeChromosome.SAPPINESS.ordinal()] == null) + getChromosomes()[EnumTreeChromosome.SAPPINESS.ordinal()] = new Chromosome(Allele.sappinessLowest); + + IAllele allele = getActiveAllele(EnumTreeChromosome.SAPPINESS.ordinal()); + // FIXME: More legacy handling + if (allele instanceof IAlleleFloat) + return ((IAlleleFloat) allele).getValue(); + else { + getChromosomes()[EnumTreeChromosome.SAPPINESS.ordinal()] = new Chromosome(Allele.sappinessLowest); + return 0.1f; + } + } + + @Override + public EnumSet getPlantTypes() { + // / FIXME: Needs some legacy handling. + if (!(getActiveAllele(EnumTreeChromosome.PLANT.ordinal()) instanceof AllelePlantType)) + getChromosomes()[EnumTreeChromosome.PLANT.ordinal()] = new Chromosome(Allele.plantTypeNone); + + return ((AllelePlantType) getActiveAllele(EnumTreeChromosome.PLANT.ordinal())).getPlantTypes(); + } + + @Override + public int getMaturationTime() { + if (getChromosomes()[EnumTreeChromosome.MATURATION.ordinal()] == null) + getChromosomes()[EnumTreeChromosome.MATURATION.ordinal()] = new Chromosome(Allele.maturationSlowest); + + return ((IAlleleInteger) getActiveAllele(EnumTreeChromosome.MATURATION.ordinal())).getValue(); + } + + private IAllele translateGirth(int girth) { + switch (girth) { + case 2: + return Allele.int2; + case 3: + return Allele.int3; + default: + return Allele.int1; + } + } + + @Override + public int getGirth() { + if (getChromosomes()[EnumTreeChromosome.GIRTH.ordinal()] == null) + getChromosomes()[EnumTreeChromosome.GIRTH.ordinal()] = new Chromosome(translateGirth(getPrimary().getGirth()), + translateGirth(getSecondary().getGirth())); + + return ((IAlleleInteger) getActiveAllele(EnumTreeChromosome.GIRTH.ordinal())).getValue(); + } + + @Override + public IAlleleLeafEffect getEffect() { + return (IAlleleLeafEffect) getActiveAllele(EnumTreeChromosome.EFFECT.ordinal()); + } + + @Override + public ISpeciesRoot getSpeciesRoot() { + return PluginArboriculture.treeInterface; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeHelper.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeHelper.java new file mode 100755 index 000000000..5d8ce3f54 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeHelper.java @@ -0,0 +1,391 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Map.Entry; + +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import cpw.mods.fml.common.FMLCommonHandler; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.api.arboriculture.IArboristTracker; +import forestry.api.arboriculture.ILeafTickHandler; +import forestry.api.arboriculture.ITree; +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.arboriculture.ITreeMutation; +import forestry.api.arboriculture.ITreeRoot; +import forestry.api.arboriculture.ITreekeepingMode; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.arboriculture.gadgets.BlockFruitPod; +import forestry.arboriculture.gadgets.TileFruitPod; +import forestry.arboriculture.gadgets.TileLeaves; +import forestry.arboriculture.gadgets.TileSapling; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.SpeciesRoot; +import forestry.core.utils.BlockUtil; +import forestry.plugins.PluginArboriculture; + +public class TreeHelper extends SpeciesRoot implements ITreeRoot { + + public static final String UID = "rootTrees"; + public static int treeSpeciesCount = -1; + + @Override + public String getUID() { + return UID; + } + + public TreeHelper() { + setResearchSuitability(new ItemStack(Blocks.sapling, 1, Defaults.WILDCARD), 1.0f); + } + + @Override + public Class getMemberClass() { + return ITree.class; + } + + @Override + public int getSpeciesCount() { + if (treeSpeciesCount < 0) { + treeSpeciesCount = 0; + Iterator > it = AlleleManager.alleleRegistry.getRegisteredAlleles().entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + if (entry.getValue() instanceof IAlleleTreeSpecies) + if (((IAlleleTreeSpecies) entry.getValue()).isCounted()) + treeSpeciesCount++; + } + } + + return treeSpeciesCount; + } + + @Override + public boolean isMember(ItemStack itemstack) { + return getType(itemstack) != EnumGermlingType.NONE; + } + + @Override + public boolean isMember(ItemStack stack, int type) { + return getType(stack).ordinal() == type; + } + + @Override + public boolean isMember(IIndividual individual) { + return individual instanceof ITree; + } + + /* TREE SPECIFIC */ + @Override + public EnumGermlingType getType(ItemStack stack) { + if(stack == null) + return EnumGermlingType.NONE; + + if(ForestryItem.sapling.isItemEqual(stack)) + return EnumGermlingType.SAPLING; + else if(ForestryItem.pollenFertile.isItemEqual(stack)) + return EnumGermlingType.POLLEN; + + return EnumGermlingType.NONE; + } + + @Override + public ITree getTree(World world, int x, int y, int z) { + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileSapling)) + return null; + + return ((TileSapling) tile).getTree(); + } + + @Override + public ITree getMember(ItemStack itemstack) { + if (!isMember(itemstack)) + return null; + if (itemstack.getTagCompound() == null) + return null; + + return new Tree(itemstack.getTagCompound()); + } + + @Override + public ITree getMember(NBTTagCompound compound) { + return new Tree(compound); + } + + @Override + public ITree getTree(World world, ITreeGenome genome) { + return new Tree(genome); + } + + @Override + public ItemStack getMemberStack(IIndividual tree, int type) { + + Item germlingItem; + switch (EnumGermlingType.VALUES[type]) { + case SAPLING: + germlingItem = ForestryItem.sapling.item(); + break; + case POLLEN: + germlingItem = ForestryItem.pollenFertile.item(); + break; + default: + return null; + } + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + tree.writeToNBT(nbttagcompound); + + ItemStack treeStack = new ItemStack(germlingItem); + treeStack.setTagCompound(nbttagcompound); + + return treeStack; + + } + + @Override + public boolean plantSapling(World world, ITree tree, String owner, int x, int y, int z) { + + boolean placed = world.setBlock(x, y, z, ForestryBlock.saplingGE, 0, Defaults.FLAG_BLOCK_SYNCH); + if (!placed) + return false; + + if (world.getBlock(x, y, z) != ForestryBlock.saplingGE) + return false; + + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileSapling)) { + world.setBlockToAir(x, y, z); + return false; + } + + TileSapling sapling = (TileSapling) tile; + sapling.setTree(tree.copy()); + sapling.setOwner(owner); + world.markBlockForUpdate(x, y, z); + + return true; + } + + @Override + public boolean setLeaves(World world, IIndividual tree, String owner, int x, int y, int z) { + + boolean placed = world.setBlock(x, y, z, ForestryBlock.leaves, 0, Defaults.FLAG_BLOCK_SYNCH); + if (!placed) + return false; + + if (world.getBlock(x, y, z) != ForestryBlock.leaves) + return false; + + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileLeaves)) { + world.setBlockToAir(x, y, z); + return false; + } + + TileLeaves leaves = (TileLeaves) tile; + leaves.setTree((ITree) tree.copy()); + leaves.setOwner(owner); + world.markBlockForUpdate(x, y, z); + + return true; + } + + @Override + public boolean setFruitBlock(World world, IAlleleFruit allele, float sappiness, short[] indices, int x, int y, int z) { + + int direction = BlockUtil.getDirectionalMetadata(world, x, y, z); + if (direction < 0) + return false; + boolean placed = world.setBlock(x, y, z, ForestryBlock.pods, direction, Defaults.FLAG_BLOCK_SYNCH); + if (!placed) + return false; + + if (world.getBlock(x, y, z) != ForestryBlock.pods) + return false; + + TileFruitPod pod = BlockFruitPod.getPodTile(world, x, y, z); + if (pod == null) { + world.setBlockToAir(x, y, z); + return false; + } + pod.setFruit(allele, sappiness, indices); + world.markBlockForUpdate(x, y, z); + return true; + } + + /* GENOME CONVERSIONS */ + @Override + public ITreeGenome templateAsGenome(IAllele[] template) { + return new TreeGenome(templateAsChromosomes(template)); + } + + @Override + public ITreeGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive) { + return new TreeGenome(templateAsChromosomes(templateActive, templateInactive)); + } + + @Override + public ITree templateAsIndividual(IAllele[] template) { + return new Tree(templateAsGenome(template)); + } + + @Override + public ITree templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive) { + return new Tree(templateAsGenome(templateActive, templateInactive)); + } + + /* BREEDING TRACKER */ + @Override + public IArboristTracker getBreedingTracker(World world, String player) { + String filename = "ArboristTracker." + player; + ArboristTracker tracker = (ArboristTracker) world.loadItemData(ArboristTracker.class, filename); + + // Create a tracker if there is none yet. + if (tracker == null) { + tracker = new ArboristTracker(filename, player); + world.setItemData(filename, tracker); + } + + return tracker; + } + + /* BREEDING MODES */ + ArrayList treekeepingModes = new ArrayList(); + public static ITreekeepingMode activeTreekeepingMode; + + @Override + public ArrayList getTreekeepingModes() { + return this.treekeepingModes; + } + + @Override + public ITreekeepingMode getTreekeepingMode(World world) { + if (activeTreekeepingMode != null) + return activeTreekeepingMode; + + // No Treekeeping mode yet, item it. + IArboristTracker tracker = getBreedingTracker(world, "__COMMON_"); + String mode = tracker.getModeName(); + if (mode == null || mode.isEmpty()) + mode = PluginArboriculture.treekeepingMode; + + setTreekeepingMode(world, mode); + FMLCommonHandler.instance().getFMLLogger().debug("Set Treekeeping mode for a world to " + mode); + + return activeTreekeepingMode; + } + + @Override + public void registerTreekeepingMode(ITreekeepingMode mode) { + treekeepingModes.add(mode); + } + + @Override + public void setTreekeepingMode(World world, String name) { + activeTreekeepingMode = getTreekeepingMode(name); + getBreedingTracker(world, "__COMMON_").setModeName(name); + } + + @Override + public ITreekeepingMode getTreekeepingMode(String name) { + for (ITreekeepingMode mode : treekeepingModes) + if (mode.getName().equals(name) || mode.getName().equals(name.toLowerCase(Locale.ENGLISH))) + return mode; + + FMLCommonHandler.instance().getFMLLogger().debug("Failed to find a Treekeeping mode called '%s', reverting to fallback."); + return treekeepingModes.get(0); + } + + /* TEMPLATES */ + public static ArrayList treeTemplates = new ArrayList(); + + @Override + public ArrayList getIndividualTemplates() { + return treeTemplates; + } + + @Override + public void registerTemplate(String identifier, IAllele[] template) { + treeTemplates.add(new Tree(PluginArboriculture.treeInterface.templateAsGenome(template))); + speciesTemplates.put(identifier, template); + } + + @Override + public IAllele[] getDefaultTemplate() { + return TreeTemplates.getDefaultTemplate(); + } + + /* MUTATIONS */ + private static ArrayList treeMutations = new ArrayList(); + + @Override + public ArrayList getMutations(boolean shuffle) { + if (shuffle) + Collections.shuffle(treeMutations); + return treeMutations; + } + + @Override + public void registerMutation(IMutation mutation) { + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getTemplate()[0].getUID())) + return; + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getAllele0().getUID())) + return; + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getAllele1().getUID())) + return; + + treeMutations.add((ITreeMutation)mutation); + } + + /* ILEAFTICKHANDLER */ + private final LinkedList leafTickHandlers = new LinkedList(); + + @Override + public void registerLeafTickHandler(ILeafTickHandler handler) { + leafTickHandlers.add(handler); + } + + @Override + public Collection getLeafTickHandlers() { + return leafTickHandlers; + } + + @Override + public IChromosomeType[] getKaryotype() { + return EnumTreeChromosome.values(); + } + + @Override + public IChromosomeType getKaryotypeKey() { + return EnumTreeChromosome.SPECIES; + } + + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeMutation.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeMutation.java new file mode 100755 index 000000000..6d3a3d4cf --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeMutation.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.arboriculture.ITreeMutation; +import forestry.api.arboriculture.ITreeRoot; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; +import forestry.core.genetics.Mutation; +import forestry.plugins.PluginArboriculture; + +public class TreeMutation extends Mutation implements ITreeMutation { + + private ITreeRoot root; + + public TreeMutation(IAllele allele0, IAllele allele1, IAllele[] template, int chance) { + super(allele0, allele1, template, chance); + + root = (ITreeRoot)AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees"); + PluginArboriculture.treeInterface.registerMutation(this); + } + + @Override + public ITreeRoot getRoot() { + return root; + } + + @Override + public float getChance(World world, int x, int y, int z, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1) { + float processedChance = chance; + + BiomeGenBase biome = world.getWorldChunkManager().getBiomeGenAt(x, z); + if (biome.temperature < minTemperature || biome.temperature > maxTemperature) + return 0; + if (biome.rainfall < minRainfall || biome.rainfall > maxRainfall) + return 0; + + processedChance *= PluginArboriculture.treeInterface.getTreekeepingMode(world).getMutationModifier((ITreeGenome) genome0, (ITreeGenome) genome1, 1f); + + if (this.allele0.getUID().equals(allele0.getUID()) && this.allele1.getUID().equals(allele1.getUID())) + return processedChance; + if (this.allele1.getUID().equals(allele0.getUID()) && this.allele0.getUID().equals(allele1.getUID())) + return processedChance; + + return 0; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeTemplates.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeTemplates.java new file mode 100755 index 000000000..59fc9e0f5 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreeTemplates.java @@ -0,0 +1,385 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IMutation; +import forestry.core.genetics.Allele; +import forestry.core.genetics.Chromosome; + +public class TreeTemplates { + + /* MUTATIONS */ + public static IMutation larchA; + public static IMutation larchB; + public static IMutation pineA; + public static IMutation sequoiaA; + + public static IMutation limeA; + + public static IMutation cherryA; + public static IMutation cherryB; + + public static IMutation walnutA; + public static IMutation chestnutA; + public static IMutation chestnutB; + + public static IMutation teakA; + public static IMutation kapokA; + public static IMutation ebonyA; + public static IMutation mahoganyA; + + public static IMutation balsaA; + public static IMutation acaciaA; + public static IMutation wengeA; + public static IMutation baobabA; + + public static IMutation willowA; + public static IMutation willowB; + public static IMutation willowC; + + public static IMutation sipiriA; + + public static IMutation mahoeA; + + public static IMutation poplarA; + public static IMutation poplarB; + public static IMutation poplarC; + + public static IMutation lemonA; + public static IMutation plumA; + + public static IMutation mapleA; + + public static IMutation papayaA; + public static IMutation dateA; + + /* TEMPLATES */ + public static IAllele[] getDefaultTemplate() { + IAllele[] alleles = new IAllele[EnumTreeChromosome.values().length]; + + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeOak; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitNone; + alleles[EnumTreeChromosome.GROWTH.ordinal()] = Allele.growthLightlevel; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightSmall; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLower; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldLowest; + alleles[EnumTreeChromosome.PLANT.ordinal()] = Allele.plantTypeNone; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLowest; + alleles[EnumTreeChromosome.TERRITORY.ordinal()] = Allele.territoryDefault; + alleles[EnumTreeChromosome.EFFECT.ordinal()] = Allele.leavesNone; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationAverage; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int1; + + return alleles; + } + + public static IAllele[] getOakTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitApple; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsAverage; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationFaster; + return alleles; + } + + public static IAllele[] getBirchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeBirch; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsAverage; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationFaster; + return alleles; + } + + public static IAllele[] getSpruceTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeSpruce; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsAverage; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationFaster; + return alleles; + } + + public static IAllele[] getJungleTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeJungle; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitCocoa; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLarger; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationFast; + return alleles; + } + + public static IAllele[] getBalsaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeBalsa; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsHigh; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLarge; + return alleles; + } + + public static IAllele[] getSequoiaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeSequioa; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLargest; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlower; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int3; + return alleles; + } + + public static IAllele[] getGiganteumTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeGiganteum; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightGigantic; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLowest; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlowest; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int4; + return alleles; + } + + public static IAllele[] getLarchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeLarch; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLow; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + return alleles; + } + + public static IAllele[] getPineTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treePine; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLow; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + return alleles; + } + + public static IAllele[] getCherryTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeCherry; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitCherry; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLow; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldAverage; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightSmaller; + return alleles; + } + + public static IAllele[] getLimeTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeLime; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLow; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldLower; + //alleles[EnumTreeChromosome.EFFECT.ordinal()] = Allele.leavesBrimstone; + return alleles; + } + + public static IAllele[] getTeakTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeTeak; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + return alleles; + } + + public static IAllele[] getKapokTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeKapok; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLarge; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlow; + return alleles; + } + + public static IAllele[] getEbonyTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeEbony; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlower; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int3; + return alleles; + } + + public static IAllele[] getMahoganyTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeMahogany; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLarge; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlow; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getChestnutTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeChestnut; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitChestnut; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldAverage; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLarge; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getAcaciaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeAcacia; + alleles[EnumTreeChromosome.PLANT.ordinal()] = Allele.plantTypeDesert; + return alleles; + } + + public static IAllele[] getWengeTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeWenge; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLowest; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getBaobabTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeBaobab; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLarge; + alleles[EnumTreeChromosome.PLANT.ordinal()] = Allele.plantTypeDesert; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlow; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int3; + return alleles; + } + + public static IAllele[] getWalnutTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeWalnut; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitWalnut; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLower; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldAverage; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + alleles[EnumTreeChromosome.GIRTH.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getWillowTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeWillow; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationFaster; + return alleles; + } + + public static IAllele[] getSipiriTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeSipiri; + alleles[EnumTreeChromosome.GROWTH.ordinal()] = Allele.growthTropical; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightLarge; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlow; + return alleles; + } + + public static IAllele[] getMahoeTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeMahoe; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightSmall; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessHigh; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlowest; + return alleles; + } + + public static IAllele[] getPoplarTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treePoplar; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightSmall; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.MATURATION.ordinal()] = Allele.maturationSlower; + return alleles; + } + + public static IAllele[] getLemonTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeLemon; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitLemon; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldLower; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessAverage; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightSmallest; + return alleles; + } + + public static IAllele[] getPlumTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treePlum; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitPlum; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldHigh; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessAverage; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightSmallest; + return alleles; + } + + public static IAllele[] getMapleTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeMaple; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLow; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + return alleles; + } + + public static IAllele[] getPapayaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treePapaya; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitPapaya; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLow; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLower; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + return alleles; + } + + public static IAllele[] getDateTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumTreeChromosome.SPECIES.ordinal()] = Allele.treeDate; + alleles[EnumTreeChromosome.FRUITS.ordinal()] = Allele.fruitDates; + alleles[EnumTreeChromosome.FERTILITY.ordinal()] = Allele.saplingsLow; + alleles[EnumTreeChromosome.YIELD.ordinal()] = Allele.yieldLow; + alleles[EnumTreeChromosome.SAPPINESS.ordinal()] = Allele.sappinessLow; + alleles[EnumTreeChromosome.HEIGHT.ordinal()] = Allele.heightAverage; + return alleles; + } + + // / HELPER FUNCTIONS + + public static Chromosome[] templateAsChromosomes(IAllele[] template) { + Chromosome[] chromosomes = new Chromosome[template.length]; + for (int i = 0; i < template.length; i++) + if (template[i] != null) + chromosomes[i] = new Chromosome(template[i]); + + return chromosomes; + } + + public static Chromosome[] templateAsChromosomes(IAllele[] templateActive, IAllele[] templateInactive) { + Chromosome[] chromosomes = new Chromosome[templateActive.length]; + for (int i = 0; i < templateActive.length; i++) + if (templateActive[i] != null) + chromosomes[i] = new Chromosome(templateActive[i], templateInactive[i]); + + return chromosomes; + } + + public static ITreeGenome templateAsGenome(IAllele[] template) { + return new TreeGenome(templateAsChromosomes(template)); + } + + public static ITreeGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive) { + return new TreeGenome(templateAsChromosomes(templateActive, templateInactive)); + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/genetics/TreekeepingMode.java b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreekeepingMode.java new file mode 100755 index 000000000..97170e06a --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/genetics/TreekeepingMode.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.genetics; + +import java.util.ArrayList; +import java.util.Locale; +import java.util.Random; + +import forestry.api.arboriculture.ITreeGenome; +import forestry.api.arboriculture.ITreekeepingMode; + +public class TreekeepingMode implements ITreekeepingMode { + + public static ITreekeepingMode easy = new TreekeepingMode("EASY", 1.4f, 1.3f, 1.2f, 1.2f); + public static ITreekeepingMode normal = new TreekeepingMode("NORMAL", 1f, 1f, 1f, 1f); + public static ITreekeepingMode hard = new TreekeepingMode("HARD", 0.9f, 0.9f, 0.9f, 0.9f); + public static ITreekeepingMode hardcore = new TreekeepingMode("HARDCORE", 0.7f, 0.7f, 0.5f, 0.5f); + public static ITreekeepingMode insane = new TreekeepingMode("INSANE", 0.5f, 0.5f, 0.2f, 0.1f); + + final Random rand; + final String name; + private float yieldModifier; + private float sappinessModifier; + private float maturationModifier; + private float mutationModifier; + + public TreekeepingMode(String name, float yieldModifier, float sappinessModifier, float maturationModifier, float mutationModifier) { + this.rand = new Random(); + this.name = name; + this.yieldModifier = yieldModifier; + this.sappinessModifier = sappinessModifier; + this.maturationModifier = maturationModifier; + this.mutationModifier = mutationModifier; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public ArrayList getDescription() { + ArrayList ret = new ArrayList(); + ret.add("treemode." + name.toLowerCase(Locale.ENGLISH) + ".desc"); + return ret; + } + + @Override + public float getHeightModifier(ITreeGenome genome, float currentModifier) { + return 1f; + } + + @Override + public float getYieldModifier(ITreeGenome genome, float currentModifier) { + return yieldModifier; + } + + @Override + public float getSappinessModifier(ITreeGenome genome, float currentModifier) { + return sappinessModifier; + } + + @Override + public float getMaturationModifier(ITreeGenome genome, float currentModifier) { + return maturationModifier; + } + + @Override + public float getMutationModifier(ITreeGenome genome, ITreeGenome mate, float currentModifier) { + return mutationModifier; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gui/ContainerTreealyzer.java b/forestry_common/arboriculture/forestry/arboriculture/gui/ContainerTreealyzer.java new file mode 100755 index 000000000..d0b9e98a7 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gui/ContainerTreealyzer.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gui; + +import org.apache.commons.lang3.ArrayUtils; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import forestry.api.genetics.AlleleManager; +import forestry.arboriculture.items.ItemGermlingGE; +import forestry.arboriculture.items.ItemTreealyzer.TreealyzerInventory; +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.proxy.Proxies; + +public class ContainerTreealyzer extends ContainerItemInventory { + + TreealyzerInventory inventory; + + public ContainerTreealyzer(InventoryPlayer inventoryplayer, TreealyzerInventory inventory) { + super(inventory, inventoryplayer.player); + + this.inventory = inventory; + + // Energy + this.addSlot(new SlotCustom(inventory, TreealyzerInventory.SLOT_ENERGY, 172, 8, new Object[] { ForestryItem.honeydew, ForestryItem.honeyDrop })); + + // Bee to analyze + this.addSlot(new SlotCustom(inventory, TreealyzerInventory.SLOT_SPECIMEN, 172, 26, ArrayUtils.addAll(AlleleManager.ersatzSaplings.keySet().toArray(new ItemStack[0]), ItemGermlingGE.class))); + + // Analyzed bee + this.addSlot(new SlotCustom(inventory, TreealyzerInventory.SLOT_ANALYZE_1, 172, 57, new Object[] { ItemGermlingGE.class })); + this.addSlot(new SlotCustom(inventory, TreealyzerInventory.SLOT_ANALYZE_2, 172, 75, new Object[] { ItemGermlingGE.class })); + this.addSlot(new SlotCustom(inventory, TreealyzerInventory.SLOT_ANALYZE_3, 172, 93, new Object[] { ItemGermlingGE.class })); + this.addSlot(new SlotCustom(inventory, TreealyzerInventory.SLOT_ANALYZE_4, 172, 111, new Object[] { ItemGermlingGE.class })); + this.addSlot(new SlotCustom(inventory, TreealyzerInventory.SLOT_ANALYZE_5, 172, 129, new Object[] { ItemGermlingGE.class })); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSecuredSlot(inventoryplayer, l1 + i1 * 9 + 9, 18 + l1 * 18, 156 + i1 * 18); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSecuredSlot(inventoryplayer, j1, 18 + j1 * 18, 214); + + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(entityplayer.worldObj)) + return; + + // Last slot is the energy slot, so we don't save that one. + for (int i = 0; i < inventory.getSizeInventory(); i++) { + if (i == TreealyzerInventory.SLOT_ENERGY) + continue; + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + Proxies.common.dropItemPlayer(entityplayer, stack); + inventory.setInventorySlotContents(i, null); + } + + inventory.onGuiSaved(entityplayer); + + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + return true; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/gui/GuiTreealyzer.java b/forestry_common/arboriculture/forestry/arboriculture/gui/GuiTreealyzer.java new file mode 100755 index 000000000..da7fccca1 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/gui/GuiTreealyzer.java @@ -0,0 +1,343 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.gui; + +import java.util.ArrayList; +import java.util.Locale; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.IAlleleFruit; +import forestry.api.arboriculture.IAlleleGrowth; +import forestry.api.arboriculture.ITree; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleEffect; +import forestry.api.genetics.IAlleleFloat; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IFruitFamily; +import forestry.arboriculture.items.ItemGermlingGE; +import forestry.arboriculture.items.ItemTreealyzer.TreealyzerInventory; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.Allele; +import forestry.core.genetics.AllelePlantType; +import forestry.core.gui.GuiAlyzer; +import forestry.core.utils.StringUtil; +import forestry.plugins.PluginArboriculture; + +public class GuiTreealyzer extends GuiAlyzer { + + private ItemStack[] tempProductList; + + public GuiTreealyzer(EntityPlayer player, TreealyzerInventory inventory) { + super(AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees"), player, + new ContainerTreealyzer(player.inventory, inventory), inventory, 1, inventory.getSizeInventory()); + + xSize = 196; + ySize = 238; + + ArrayList treeList = new ArrayList(); + ((ItemGermlingGE) ForestryItem.sapling.item()).addCreativeItems(treeList, false); + for (ItemStack beeStack : treeList) + iconStacks.put(PluginArboriculture.treeInterface.getMember(beeStack).getIdent(), beeStack); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + int page = 0; + ITree tree = null; + for (int k = 1; k < TreealyzerInventory.SLOT_ANALYZE_5 + 1; k++) { + if (k == TreealyzerInventory.SLOT_ENERGY) + continue; + + if (inventory.getStackInSlot(k) == null) + continue; + tree = PluginArboriculture.treeInterface.getMember(inventory.getStackInSlot(k)); + if (tree == null || !tree.isAnalyzed()) + continue; + + page = k; + break; + } + + switch (page) { + case 1: + drawAnalyticsPage1(tree); + break; + case 2: + drawAnalyticsPage2(tree); + break; + case 3: + drawAnalyticsPage3(tree); + break; + case 4: + drawAnalyticsPage4(tree); + break; + case 6: + drawAnalyticsPageClassification(tree); + break; + default: + drawAnalyticsOverview(); + } + + } + + private void drawAnalyticsOverview() { + + startPage(); + + newLine(); + String title = StringUtil.localize("gui.treealyzer").toUpperCase(); + drawCenteredLine(title, 8, 158); + newLine(); + + fontRendererObj.drawSplitString(StringUtil.localize("gui.treealyzer.help"), (int) ((guiLeft + COLUMN_0 + 4) * (1 / factor)), + (int) ((guiTop + 42) * (1 / factor)), (int) (158 * (1 / factor)), fontColor.get("gui.screen")); + newLine(); + newLine(); + newLine(); + newLine(); + + drawLine(StringUtil.localize("gui.treealyzer.overview") + ":", COLUMN_0 + 4); + newLine(); + drawLine("I : " + StringUtil.localize("gui.general"), COLUMN_0 + 4); + newLine(); + drawLine("II : " + StringUtil.localize("gui.environment"), COLUMN_0 + 4); + newLine(); + drawLine("III: " + StringUtil.localize("gui.produce"), COLUMN_0 + 4); + newLine(); + drawLine("IV : " + StringUtil.localize("gui.evolution"), COLUMN_0 + 4); + + endPage(); + } + + private void drawAnalyticsPage1(ITree tree) { + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.active"), COLUMN_1); + drawLine(StringUtil.localize("gui.inactive"), COLUMN_2); + + newLine(); + newLine(); + + /* + IAlleleTreeSpecies primary = tree.getGenome().getPrimaryAsTree(); + IAlleleTreeSpecies secondary = tree.getGenome().getSecondaryAsTree(); + + drawLine(StringUtil.localize("gui.species"), COLUMN_0); + drawSplitLine(primary.getName(), COLUMN_1, COLUMN_2 - COLUMN_1 - 4, tree, EnumTreeChromosome.SPECIES, false); + drawSplitLine(secondary.getName(), COLUMN_2, COLUMN_2 - COLUMN_1 - 4, tree, EnumTreeChromosome.SPECIES, true); + + newLine(); + newLine();*/ + + drawSpeciesRow(StringUtil.localize("gui.species"), tree, EnumTreeChromosome.SPECIES); + newLine(); + + drawLine(StringUtil.localize("gui.saplings"), COLUMN_0); + drawLine(tree.getGenome().getActiveAllele(EnumTreeChromosome.FERTILITY.ordinal()).getName(), COLUMN_1, tree, EnumTreeChromosome.FERTILITY, false); + drawLine(tree.getGenome().getInactiveAllele(EnumTreeChromosome.FERTILITY.ordinal()).getName(), COLUMN_2, tree, + EnumTreeChromosome.FERTILITY, true); + + newLine(); + + drawRow(StringUtil.localize("gui.maturity"), tree.getGenome().getActiveAllele(EnumTreeChromosome.MATURATION.ordinal()).getName(), + tree.getGenome().getInactiveAllele(EnumTreeChromosome.MATURATION.ordinal()).getName(), tree, + EnumTreeChromosome.MATURATION); + + drawLine(StringUtil.localize("gui.height"), COLUMN_0); + drawLine(tree.getGenome().getActiveAllele(EnumTreeChromosome.HEIGHT.ordinal()).getName(), COLUMN_1, tree, EnumTreeChromosome.HEIGHT, false); + drawLine(tree.getGenome().getInactiveAllele(EnumTreeChromosome.HEIGHT.ordinal()).getName(), COLUMN_2, tree, + EnumTreeChromosome.HEIGHT, true); + + newLine(); + + drawLine(StringUtil.localize("gui.girth"), COLUMN_0); + drawLine(String.format("%sx%s", tree.getGenome().getGirth(), tree.getGenome().getGirth()), COLUMN_1, tree, EnumTreeChromosome.FERTILITY, false); + int secondGirth = ((IAlleleInteger) tree.getGenome().getInactiveAllele(EnumTreeChromosome.GIRTH.ordinal())).getValue(); + drawLine(String.format("%sx%s", secondGirth, secondGirth), COLUMN_2, tree, EnumTreeChromosome.FERTILITY, true); + + newLine(); + + drawLine(StringUtil.localize("gui.yield"), COLUMN_0); + drawLine(tree.getGenome().getActiveAllele(EnumTreeChromosome.YIELD.ordinal()).getName(), COLUMN_1, tree, EnumTreeChromosome.YIELD, false); + drawLine(tree.getGenome().getInactiveAllele(EnumTreeChromosome.YIELD.ordinal()).getName(), COLUMN_2, tree, + EnumTreeChromosome.YIELD, true); + + newLine(); + + drawLine(StringUtil.localize("gui.sappiness"), COLUMN_0); + drawLine(tree.getGenome().getActiveAllele(EnumTreeChromosome.SAPPINESS.ordinal()).getName(), COLUMN_1, tree, EnumTreeChromosome.SAPPINESS, false); + + // FIXME: Legacy handling + IAllele sappiness = tree.getGenome().getInactiveAllele(EnumTreeChromosome.SAPPINESS.ordinal()); + String sap; + if (sappiness instanceof IAlleleFloat) + sap = sappiness.getName(); + else + sap = Allele.saplingsLowest.getName(); + + drawLine(sap, COLUMN_2, tree, EnumTreeChromosome.SAPPINESS, true); + + newLine(); + + drawRow(StringUtil.localize("gui.effect"), StringUtil.localize(tree.getGenome().getEffect().getName()), + StringUtil.localize(((IAlleleEffect) tree.getGenome().getInactiveAllele(EnumTreeChromosome.EFFECT.ordinal())).getName()), tree, + EnumTreeChromosome.EFFECT); + + newLine(); + newLine(); + + endPage(); + } + + private void drawAnalyticsPage2(ITree tree) { + + startPage(); + + int speciesDominance0 = getColorCoding(tree.getGenome().getPrimary().isDominant()); + int speciesDominance1 = getColorCoding(tree.getGenome().getSecondary().isDominant()); + + drawLine(StringUtil.localize("gui.active"), COLUMN_1); + drawLine(StringUtil.localize("gui.inactive"), COLUMN_2); + + newLine(); + newLine(); + + drawLine(StringUtil.localize("gui.growth"), COLUMN_0); + drawLine(tree.getGenome().getGrowthProvider().getDescription(), COLUMN_1, tree, EnumTreeChromosome.GROWTH, false); + drawLine(((IAlleleGrowth) tree.getGenome().getInactiveAllele(EnumTreeChromosome.GROWTH.ordinal())).getProvider().getDescription(), COLUMN_2, tree, + EnumTreeChromosome.GROWTH, true); + + newLine(); + + drawLine(StringUtil.localize("gui.native"), COLUMN_0); + drawLine(StringUtil.localize("gui." + tree.getGenome().getPrimary().getPlantType().toString().toLowerCase(Locale.ENGLISH)), COLUMN_1, + speciesDominance0); + drawLine(StringUtil.localize("gui." + tree.getGenome().getSecondary().getPlantType().toString().toLowerCase(Locale.ENGLISH)), COLUMN_2, + speciesDominance1); + + newLine(); + + drawLine(StringUtil.localize("gui.tolerated"), COLUMN_0); + + EnumPlantType[] tolerated0 = tree.getGenome().getPlantTypes().toArray(new EnumPlantType[0]); + EnumPlantType[] tolerated1 = new EnumPlantType[0]; + IAllele allele1 = tree.getGenome().getInactiveAllele(EnumTreeChromosome.PLANT.ordinal()); + if (allele1 instanceof AllelePlantType) + tolerated1 = ((AllelePlantType) allele1).getPlantTypes().toArray(new EnumPlantType[0]); + + int max = tolerated0.length > tolerated1.length ? tolerated0.length : tolerated1.length; + for (int i = 0; i < max; i++) { + if (i > 0) + newLine(); + if(tolerated0.length > i) + drawLine(StringUtil.localize("gui." + tolerated0[i].toString().toLowerCase(Locale.ENGLISH)), COLUMN_1, tree, EnumTreeChromosome.PLANT, false); + if(tolerated1.length > i) + drawLine(StringUtil.localize("gui." + tolerated1[i].toString().toLowerCase(Locale.ENGLISH)), COLUMN_2, tree, EnumTreeChromosome.PLANT, true); + } + newLine(); + + // FRUITS + drawLine(StringUtil.localize("gui.supports"), COLUMN_0); + IFruitFamily[] families0 = tree.getGenome().getPrimary().getSuitableFruit().toArray(new IFruitFamily[0]); + IFruitFamily[] families1 = tree.getGenome().getPrimary().getSuitableFruit().toArray(new IFruitFamily[0]); + + max = families0.length > families1.length ? families0.length : families1.length; + for (int i = 0; i < max; i++) { + if (i > 0) + newLine(); + + if (families0.length > i) + drawLine(StringUtil.localize(families0[i].getName()), COLUMN_1, speciesDominance0); + if (families1.length > i) + drawLine(StringUtil.localize(families1[i].getName()), COLUMN_2, speciesDominance1); + + } + + newLine(); + newLine(); + + int fruitDominance0 = getColorCoding(tree.getGenome().getActiveAllele(EnumTreeChromosome.FRUITS.ordinal()).isDominant()); + int fruitDominance1 = getColorCoding(tree.getGenome().getInactiveAllele(EnumTreeChromosome.FRUITS.ordinal()).isDominant()); + + drawLine(StringUtil.localize("gui.fruits"), COLUMN_0); + String strike = ""; + IAllele fruit0 = tree.getGenome().getActiveAllele(EnumTreeChromosome.FRUITS.ordinal()); + if (!tree.canBearFruit() && fruit0 != Allele.fruitNone) + strike = "\u00A7m"; + drawLine(strike + StringUtil.localize(tree.getGenome().getFruitProvider().getDescription()), COLUMN_1, fruitDominance0); + + strike = ""; + IAllele fruit1 = tree.getGenome().getInactiveAllele(EnumTreeChromosome.FRUITS.ordinal()); + if (!tree.getGenome().getSecondary().getSuitableFruit().contains(((IAlleleFruit) fruit1).getProvider().getFamily()) && fruit1 != Allele.fruitNone) + strike = "\u00A7m"; + drawLine(strike + StringUtil.localize(((IAlleleFruit) fruit1).getProvider().getDescription()), COLUMN_2, fruitDominance1); + + newLine(); + + drawLine(StringUtil.localize("gui.family"), COLUMN_0); + IFruitFamily primary = tree.getGenome().getFruitProvider().getFamily(); + IFruitFamily secondary = ((IAlleleFruit) tree.getGenome().getInactiveAllele(EnumTreeChromosome.FRUITS.ordinal())).getProvider().getFamily(); + + if (primary != null) + drawLine(StringUtil.localize(primary.getName()), COLUMN_1, fruitDominance0); + if (secondary != null) + drawLine(StringUtil.localize(secondary.getName()), COLUMN_2, fruitDominance1); + + endPage(); + } + + private void drawAnalyticsPage3(ITree tree) { + + tempProductList = tree.getProduceList(); + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.beealyzer.produce") + ":", COLUMN_0); + newLine(); + + int x = COLUMN_0; + for (ItemStack stack : tempProductList) { + itemRender.renderItemIntoGUI(fontRendererObj, mc.renderEngine, stack, (int) ((guiLeft + x) * (1 / factor)), + (int) ((guiTop + getLineY()) * (1 / factor))); + x += 18; + if (x > adjustToFactor(148)) { + x = COLUMN_0; + newLine(); + } + } + + newLine(); + newLine(); + + drawLine(StringUtil.localize("gui.beealyzer.specialty") + ":", COLUMN_0); + newLine(); + + x = COLUMN_0; + for (ItemStack stack : tree.getSpecialtyList()) { + itemRender.renderItemIntoGUI(fontRendererObj, mc.renderEngine, stack, (int) ((guiLeft + x) * (1 / factor)), + (int) ((guiTop + getLineY()) * (1 / factor))); + x += 18; + if (x > adjustToFactor(148)) { + x = COLUMN_0; + newLine(); + } + } + + endPage(); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/items/ItemGermlingGE.java b/forestry_common/arboriculture/forestry/arboriculture/items/ItemGermlingGE.java new file mode 100755 index 000000000..df4f40243 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/items/ItemGermlingGE.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.items; + +import java.util.List; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.api.arboriculture.ITree; +import forestry.api.core.Tabs; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.api.recipes.IVariableFermentable; +import forestry.arboriculture.genetics.Tree; +import forestry.core.config.Config; +import forestry.core.genetics.ItemGE; +import forestry.core.network.PacketFXSignal; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.utils.Utils; +import forestry.plugins.PluginArboriculture; + +public class ItemGermlingGE extends ItemGE implements IVariableFermentable { + + private final EnumGermlingType type; + + public ItemGermlingGE(EnumGermlingType type) { + super(); + this.type = type; + setCreativeTab(Tabs.tabArboriculture); + } + + @Override + protected IIndividual getIndividual(ItemStack itemstack) { + return new Tree(itemstack.getTagCompound()); + } + + private IAlleleTreeSpecies getPrimarySpecies(ItemStack itemstack) { + ITree tree = PluginArboriculture.treeInterface.getMember(itemstack); + if (tree == null) + return (IAlleleTreeSpecies) PluginArboriculture.treeInterface.getDefaultTemplate()[EnumTreeChromosome.SPECIES.ordinal()]; + else + return tree.getGenome().getPrimary(); + } + + @Override + protected int getDefaultPrimaryColour() { + return 0; + } + + @Override + protected int getDefaultSecondaryColour() { + return 0; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (!itemstack.hasTagCompound()) + return "Unknown"; + IIndividual individual = getIndividual(itemstack); + return individual.getDisplayName() + " " + type.getName(); + } + + @SuppressWarnings("rawtypes") + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + addCreativeItems(itemList, true); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void addCreativeItems(List itemList, boolean hideSecrets) { + for (IIndividual individual : PluginArboriculture.treeInterface.getIndividualTemplates()) { + // Don't show secrets unless ordered to. + if (hideSecrets && individual.isSecret() && !Config.isDebug) + continue; + + itemList.add(PluginArboriculture.treeInterface.getMemberStack(individual, type.ordinal())); + } + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int renderPass) { + return getPrimarySpecies(itemstack).getGermlingColour(type, renderPass); + } + + /* ICONS */ + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getRenderPasses(int metadata) { + return 2;//type == EnumGermlingType.SAPLING ? 1 : 2; + } + + @Override + public int getSpriteNumber() { + return type == EnumGermlingType.SAPLING ? SpriteSheet.BLOCKS.getSheetOrdinal() : SpriteSheet.ITEMS.getSheetOrdinal(); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(ItemStack itemstack, int renderPass) { + IAlleleTreeSpecies species = getPrimarySpecies(itemstack); + return species.getGermlingIcon(type, renderPass); + } + + @Override + public boolean onItemUse(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int par7, float facingX, float facingY, float facingZ) { + + if (!Proxies.common.isSimulating(world)) + return false; + + ITree tree = PluginArboriculture.treeInterface.getMember(itemstack); + if(tree == null) + return false; + + if(type == EnumGermlingType.SAPLING) { + // x, y, z are the coordinates of the block "hit", can thus either be the soil or tall grass, etc. + int yShift; + if (!Utils.isReplaceableBlock(world, x, y, z)) { + if (!world.isAirBlock(x, y + 1, z)) + return false; + yShift = 1; + } else + yShift = 0; + + if (!tree.canStay(world, x, y + yShift, z)) + return false; + + if (PluginArboriculture.treeInterface.plantSapling(world, tree, player.getGameProfile().getId(), x, y + yShift, z)) { + Proxies.common.addBlockPlaceEffects(world, x, y, z, world.getBlock(x, y + yShift, z), 0); + if (!player.capabilities.isCreativeMode) + itemstack.stackSize--; + return true; + } else + return false; + } else if(type == EnumGermlingType.POLLEN) { + + TileEntity target = world.getTileEntity(x, y, z); + if(!(target instanceof IPollinatable)) + return false; + + IPollinatable pollinatable = (IPollinatable)target; + if(!pollinatable.canMateWith(tree)) + return false; + + pollinatable.mateWith(tree); + Proxies.common.sendFXSignal(PacketFXSignal.VisualFXType.BLOCK_DESTROY, PacketFXSignal.SoundFXType.LEAF, world, x, y, z, + world.getBlock(x, y, z), 0); + if (!player.capabilities.isCreativeMode) + itemstack.stackSize--; + return true; + + } else + return false; + } + + @Override + public float getFermentationModifier(ItemStack itemstack) { + ITree tree = PluginArboriculture.treeInterface.getMember(itemstack); + if (tree == null) + return 1.0f; + + return tree.getGenome().getSappiness() * 10; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/items/ItemGrafter.java b/forestry_common/arboriculture/forestry/arboriculture/items/ItemGrafter.java new file mode 100755 index 000000000..3ee0fb989 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/items/ItemGrafter.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.items; + +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.ForgeHooks; + +import forestry.api.arboriculture.IToolGrafter; +import forestry.api.core.Tabs; +import forestry.core.items.ItemForestry; + +public class ItemGrafter extends ItemForestry implements IToolGrafter { + + private final float efficiencyOnProperMaterial; + + public ItemGrafter(int maxDamage) { + super(); + setMaxStackSize(1); + efficiencyOnProperMaterial = 4.0F; + setMaxDamage(maxDamage); + setCreativeTab(Tabs.tabArboriculture); + } + + @Override + public float func_150893_a(ItemStack itemstack, Block block) { + return 1.0F; + } + + @Override + public float getDigSpeed(ItemStack itemstack, Block block, int md) { + if (ForgeHooks.isToolEffective(itemstack, block, md)) + return efficiencyOnProperMaterial; + + return func_150893_a(itemstack, block); + } + + @Override + public boolean onBlockDestroyed(ItemStack itemstack, World world, Block block, int j, int k, int l, EntityLivingBase entityliving) { + return true; + } + + /*@Override + public float getDamageVsEntity(Entity entity, ItemStack itemstack) { + return 1; + }*/ + + @Override + public boolean isFull3D() { + return true; + } + + @Override + public float getSaplingModifier(ItemStack stack, World world, EntityPlayer player, int x, int y, int z) { + return 100f; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/items/ItemStairs.java b/forestry_common/arboriculture/forestry/arboriculture/items/ItemStairs.java new file mode 100755 index 000000000..dc4de81f5 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/items/ItemStairs.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.items; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import forestry.arboriculture.WoodType; +import forestry.arboriculture.gadgets.TileStairs; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.items.ItemForestryBlock; +import forestry.core.utils.StringUtil; + +public class ItemStairs extends ItemForestryBlock { + + public ItemStairs(Block block) { + super(block); + } + + @Override + public boolean placeBlockAt(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ, + int metadata) { + + WoodType type = WoodType.getFromCompound(stack.getTagCompound()); + return placeStairs(world, player, stack, type, x, y, z, metadata); + + } + + private boolean placeStairs(World world, EntityPlayer player, ItemStack stack, WoodType type, int x, int y, int z, int metadata) { + + boolean placed = world.setBlock(x, y, z, ForestryBlock.stairs, metadata, Defaults.FLAG_BLOCK_SYNCH); + if (!placed) + return false; + + Block block = world.getBlock(x, y, z); + + if (block != ForestryBlock.stairs) + return false; + + block.onBlockPlacedBy(world, x, y, z, player, stack); + block.onPostBlockPlaced(world, x, y, z, metadata); + + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileStairs)) { + world.setBlockToAir(x, y, z); + return false; + } + + ((TileStairs) tile).setType(type); + return true; + } + + private String getWoodNameIS(WoodType type) { + return StringUtil.localize("wood." + type.ordinal()); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + + WoodType type = WoodType.getFromCompound(itemstack.getTagCompound()); + + return getWoodNameIS(type) + " " + StringUtil.localize(getUnlocalizedName()); + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/items/ItemTreealyzer.java b/forestry_common/arboriculture/forestry/arboriculture/items/ItemTreealyzer.java new file mode 100755 index 000000000..cb2916685 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/items/ItemTreealyzer.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; + +import forestry.api.arboriculture.ITree; +import forestry.api.core.ForestryAPI; +import forestry.api.core.Tabs; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.IHintSource; +import forestry.core.items.ItemInventoried; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ItemInventory; +import forestry.core.utils.Utils; +import forestry.plugins.PluginArboriculture; + +public class ItemTreealyzer extends ItemInventoried { + + public static class TreealyzerInventory extends ItemInventory implements IErrorSource, IHintSource { + + public final static int SLOT_SPECIMEN = 0; + public final static int SLOT_ANALYZE_1 = 1; + public final static int SLOT_ANALYZE_2 = 2; + public final static int SLOT_ANALYZE_3 = 3; + public final static int SLOT_ANALYZE_4 = 4; + public final static int SLOT_ANALYZE_5 = 6; + public final static int SLOT_ENERGY = 5; + EntityPlayer player; + + public TreealyzerInventory(EntityPlayer player) { + super(ItemTreealyzer.class, 7); + this.player = player; + } + + public TreealyzerInventory(EntityPlayer player, ItemStack itemStack) { + super(ItemTreealyzer.class, 7, itemStack); + this.player = player; + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = new NBTTagList(); + for (int i = SLOT_ENERGY; i < SLOT_ENERGY + 1; i++) { + if (inventoryStacks[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + inventoryStacks[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + } + nbttagcompound.setTag("Items", nbttaglist); + + } + + private boolean isEnergy(ItemStack itemstack) { + if (itemstack == null || itemstack.stackSize <= 0) + return false; + + return ForestryItem.honeyDrop.isItemEqual(itemstack) || ForestryItem.honeydew.isItemEqual(itemstack); + } + + private void tryAnalyze() { + + // Analyzed slot occupied, abort + if (inventoryStacks[SLOT_ANALYZE_1] != null || inventoryStacks[SLOT_ANALYZE_2] != null || inventoryStacks[SLOT_ANALYZE_3] != null + || inventoryStacks[SLOT_ANALYZE_4] != null || inventoryStacks[SLOT_ANALYZE_5] != null) + return; + + // Source slot to analyze empty + if (getStackInSlot(SLOT_SPECIMEN) == null) + return; + + if (!PluginArboriculture.treeInterface.isMember(getStackInSlot(SLOT_SPECIMEN))) { + ItemStack ersatz = Utils.convertSaplingToGeneticEquivalent(getStackInSlot(SLOT_SPECIMEN)); + if (ersatz != null) + setInventorySlotContents(SLOT_SPECIMEN, ersatz); + } + ITree tree = PluginArboriculture.treeInterface.getMember(getStackInSlot(SLOT_SPECIMEN)); + // No tree, abort + if (tree == null) + return; + + // Analyze if necessary + if (!tree.isAnalyzed()) { + + // Requires energy + if (!isEnergy(getStackInSlot(SLOT_ENERGY))) + return; + + tree.analyze(); + if (player != null) { + PluginArboriculture.treeInterface.getBreedingTracker(player.worldObj, player.getGameProfile().getId()).registerSpecies(tree.getGenome().getPrimary()); + PluginArboriculture.treeInterface.getBreedingTracker(player.worldObj, player.getGameProfile().getId()).registerSpecies(tree.getGenome().getSecondary()); + } + NBTTagCompound nbttagcompound = new NBTTagCompound(); + tree.writeToNBT(nbttagcompound); + getStackInSlot(SLOT_SPECIMEN).setTagCompound(nbttagcompound); + + // Decrease energy + decrStackSize(SLOT_ENERGY, 1); + } + + setInventorySlotContents(SLOT_ANALYZE_1, getStackInSlot(SLOT_SPECIMEN)); + setInventorySlotContents(SLOT_SPECIMEN, null); + } + + @Override + public void markDirty() { + // if (!Proxies.common.isSimulating(player.worldObj)) + // return; + tryAnalyze(); + } + + // / IHINTSOURCE + @Override + public boolean hasHints() { + return Config.hints.get("treealyzer") != null && Config.hints.get("treealyzer").length > 0; + } + + @Override + public String[] getHints() { + return Config.hints.get("treealyzer"); + } + + // / IERRORSOURCE + @Override + public boolean throwsErrors() { + return true; + } + + @Override + public EnumErrorCode getErrorState() { + if (PluginArboriculture.treeInterface.isMember(inventoryStacks[SLOT_SPECIMEN]) && !isEnergy(getStackInSlot(SLOT_ENERGY))) + return EnumErrorCode.NOHONEY; + + return EnumErrorCode.OK; + } + } + + public ItemTreealyzer() { + super(); + setMaxStackSize(1); + setCreativeTab(Tabs.tabArboriculture); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) + entityplayer.openGui(ForestryAPI.instance, GuiId.TreealyzerGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + + return itemstack; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/items/ItemWoodBlock.java b/forestry_common/arboriculture/forestry/arboriculture/items/ItemWoodBlock.java new file mode 100755 index 000000000..69f0c1020 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/items/ItemWoodBlock.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.items; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; + +import forestry.arboriculture.IWoodTyped; +import forestry.arboriculture.WoodType; +import forestry.core.items.ItemForestryBlock; +import forestry.core.utils.StringUtil; + +public class ItemWoodBlock extends ItemForestryBlock { + + public ItemWoodBlock(Block block) { + super(block); + } + + public static int getTypeFromMeta(int damage) { + return damage & 3; + } + + private String getWoodNameIS(WoodType type) { + return StringUtil.localize("wood." + type.ordinal()); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + + if (this.getBlock() instanceof IWoodTyped) { + IWoodTyped block = (IWoodTyped) getBlock(); + return getWoodNameIS(block.getWoodType(itemstack.getItemDamage())) + " " + StringUtil.localize("tile." + block.getBlockKind()); + } else + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/network/PacketLeafUpdate.java b/forestry_common/arboriculture/forestry/arboriculture/network/PacketLeafUpdate.java new file mode 100755 index 000000000..cbeab6b48 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/network/PacketLeafUpdate.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import forestry.arboriculture.gadgets.TileLeaves; +import forestry.core.network.PacketCoordinates; +import forestry.core.network.PacketIds; + +public class PacketLeafUpdate extends PacketCoordinates { + + public byte isRipeningUpdate = 0; + + private byte leafState = 0; + public short textureIndexFancy; + public short textureIndexPlain; + public short textureIndexFruit; + + public int colourLeaves; + public int colourFruits; + + public PacketLeafUpdate() { + } + + public PacketLeafUpdate(int posX, int posY, int posZ, TileLeaves leaves) { + super(PacketIds.LEAF_UPDATE, posX, posY, posZ); + + leafState = 0; + if(leaves.hasFruit()) + leafState |= 1 << 0; + if(leaves.isPollinated()) + leafState |= 1 << 1; + textureIndexFancy = leaves.determineTextureIndex(true); + textureIndexPlain = leaves.determineTextureIndex(false); + textureIndexFruit = leaves.determineOverlayIndex(); + colourLeaves = leaves.determineFoliageColour(); + colourFruits = leaves.determineFruitColour(); + } + + public PacketLeafUpdate(int posX, int posY, int posZ, int fruitColour) { + super(PacketIds.LEAF_UPDATE, posX, posY, posZ); + + isRipeningUpdate = 1; + colourFruits = fruitColour; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + super.writeData(data); + + data.writeByte(isRipeningUpdate); + + if(isRipeningUpdate()) { + data.writeInt(colourFruits); + } else { + data.writeByte(leafState); + data.writeShort(textureIndexFancy); + data.writeShort(textureIndexPlain); + data.writeShort(textureIndexFruit); + data.writeInt(colourLeaves); + data.writeInt(colourFruits); + } + } + + @Override + public void readData(DataInputStream data) throws IOException { + super.readData(data); + + isRipeningUpdate = data.readByte(); + if(isRipeningUpdate()) { + colourFruits = data.readInt(); + } else { + leafState = data.readByte(); + textureIndexFancy = data.readShort(); + textureIndexPlain = data.readShort(); + textureIndexFruit = data.readShort(); + colourLeaves = data.readInt(); + colourFruits = data.readInt(); + } + } + + public boolean isRipeningUpdate() { + return isRipeningUpdate != 0; + } + + public boolean isFruitLeaf() { + return (leafState & (1 << 0)) > 0; + } + public boolean isPollinated() { + return (leafState & (1 << 1)) > 0; + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/proxy/ClientProxyArboriculture.java b/forestry_common/arboriculture/forestry/arboriculture/proxy/ClientProxyArboriculture.java new file mode 100755 index 000000000..968aaf39c --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/proxy/ClientProxyArboriculture.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.proxy; + +import net.minecraft.item.Item; +import net.minecraft.world.ColorizerFoliage; + +import cpw.mods.fml.client.registry.RenderingRegistry; + +import net.minecraftforge.client.MinecraftForgeClient; + +import forestry.arboriculture.render.FenceRenderingHandler; +import forestry.arboriculture.render.FruitPodRenderingHandler; +import forestry.arboriculture.render.LeavesRenderingHandler; +import forestry.arboriculture.render.SaplingRenderHandler; +import forestry.arboriculture.render.StairItemRenderer; +import forestry.core.config.ForestryBlock; +import forestry.core.utils.Localization; +import forestry.plugins.PluginArboriculture; + +public class ClientProxyArboriculture extends ProxyArboriculture { + @Override + public void initializeRendering() { + PluginArboriculture.modelIdSaplings = RenderingRegistry.getNextAvailableRenderId(); + PluginArboriculture.modelIdLeaves = RenderingRegistry.getNextAvailableRenderId(); + PluginArboriculture.modelIdFences = RenderingRegistry.getNextAvailableRenderId(); + PluginArboriculture.modelIdPods = RenderingRegistry.getNextAvailableRenderId(); + + RenderingRegistry.registerBlockHandler(new SaplingRenderHandler()); + RenderingRegistry.registerBlockHandler(new LeavesRenderingHandler()); + RenderingRegistry.registerBlockHandler(new FenceRenderingHandler()); + RenderingRegistry.registerBlockHandler(new FruitPodRenderingHandler()); + + MinecraftForgeClient.registerItemRenderer(Item.getItemFromBlock(ForestryBlock.stairs), new StairItemRenderer()); + } + + @Override + public int getFoliageColorBasic() { + return ColorizerFoliage.getFoliageColorBasic(); + } + + @Override + public int getFoliageColorBirch() { + return ColorizerFoliage.getFoliageColorBirch(); + } + + @Override + public int getFoliageColorPine() { + return ColorizerFoliage.getFoliageColorPine(); + } + + @Override + public void addLocalizations() { + Localization.instance.addLocalization("/lang/forestry/arboriculture/"); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/proxy/ProxyArboriculture.java b/forestry_common/arboriculture/forestry/arboriculture/proxy/ProxyArboriculture.java new file mode 100755 index 000000000..9e3cbe1db --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/proxy/ProxyArboriculture.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.proxy; + +import net.minecraft.world.World; + +public class ProxyArboriculture { + + public void initializeRendering() { + } + + public int getFoliageColorBasic() { + return 4764952; + } + + public int getFoliageColorBirch() { + return 8431445; + } + + public int getFoliageColorPine() { + return 6396257; + } + + public int getBiomeFoliageColour(World world, int x, int z) { + return getFoliageColorBasic(); + } + + public void addLocalizations() { + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/render/FenceRenderingHandler.java b/forestry_common/arboriculture/forestry/arboriculture/render/FenceRenderingHandler.java new file mode 100755 index 000000000..60bb39e7a --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/render/FenceRenderingHandler.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.render; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockFence; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.world.IBlockAccess; + +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; + +import org.lwjgl.opengl.GL11; + +import forestry.plugins.PluginArboriculture; + +public class FenceRenderingHandler implements ISimpleBlockRenderingHandler { + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + + Tessellator tess = Tessellator.instance; + + for (int i = 0; i < 4; ++i) { + + float thickness = 0.125F; + + if (i == 0) + block.setBlockBounds(0.5F - thickness, 0.0F, 0.0F, 0.5F + thickness, 1.0F, thickness * 2.0F); + + if (i == 1) + block.setBlockBounds(0.5F - thickness, 0.0F, 1.0F - thickness * 2.0F, 0.5F + thickness, 1.0F, 1.0F); + + thickness = 0.0625F; + + if (i == 2) + block.setBlockBounds(0.5F - thickness, 1.0F - thickness * 3.0F, -thickness * 2.0F, 0.5F + thickness, 1.0F - thickness, 1.0F + thickness * 2.0F); + + if (i == 3) + block.setBlockBounds(0.5F - thickness, 0.5F - thickness * 3.0F, -thickness * 2.0F, 0.5F + thickness, 0.5F - thickness, 1.0F + thickness * 2.0F); + + renderer.setRenderBoundsFromBlock(block); + + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tess.startDrawingQuads(); + tess.setNormal(0.0F, -1.0F, 0.0F); + renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(0, metadata)); + tess.draw(); + tess.startDrawingQuads(); + tess.setNormal(0.0F, 1.0F, 0.0F); + renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(1, metadata)); + tess.draw(); + tess.startDrawingQuads(); + tess.setNormal(0.0F, 0.0F, -1.0F); + renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(2, metadata)); + tess.draw(); + tess.startDrawingQuads(); + tess.setNormal(0.0F, 0.0F, 1.0F); + renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(3, metadata)); + tess.draw(); + tess.startDrawingQuads(); + tess.setNormal(-1.0F, 0.0F, 0.0F); + renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(4, metadata)); + tess.draw(); + tess.startDrawingQuads(); + tess.setNormal(1.0F, 0.0F, 0.0F); + renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(5, metadata)); + tess.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + } + + block.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + renderer.setRenderBoundsFromBlock(block); + + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + return renderer.renderBlockFence((BlockFence) block, x, y, z); + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + return true; + } + + @Override + public int getRenderId() { + return PluginArboriculture.modelIdFences; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/render/FruitPodRenderingHandler.java b/forestry_common/arboriculture/forestry/arboriculture/render/FruitPodRenderingHandler.java new file mode 100755 index 000000000..5029221e3 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/render/FruitPodRenderingHandler.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.render; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockDirectional; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; + +import forestry.arboriculture.gadgets.BlockFruitPod; +import forestry.arboriculture.gadgets.TileFruitPod; +import forestry.plugins.PluginArboriculture; + +public class FruitPodRenderingHandler implements ISimpleBlockRenderingHandler { + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + + int maturity = 0; + + BlockFruitPod blockPod = (BlockFruitPod) block; + TileFruitPod pod = BlockFruitPod.getPodTile(world, x, y, z); + if (pod != null) + maturity = pod.getMaturity(); + + Tessellator tessellator = Tessellator.instance; + tessellator.setBrightness(blockPod.getMixedBrightnessForBlock(world, x, y, z)); + tessellator.setColorOpaque_F(1.0f, 1.0f, 1.0f); + int metadata = world.getBlockMetadata(x, y, z); + IIcon podIcon = blockPod.getIcon(world, x, y, z, metadata); + int notchDirection = BlockDirectional.getDirection(metadata); + + int k1 = 4 + maturity * 2; + int l1 = 5 + maturity * 2; + double d0 = 15.0D - k1; + double d1 = 15.0D; + double d2 = 4.0D; + double d3 = 4.0D + l1; + double d4 = (double)podIcon.getInterpolatedU(d0); + double d5 = (double)podIcon.getInterpolatedU(d1); + double d6 = (double)podIcon.getInterpolatedV(d2); + double d7 = (double)podIcon.getInterpolatedV(d3); + double d8 = 0.0D; + double d9 = 0.0D; + + switch (notchDirection) { + case 0: + d8 = 8.0D - k1 / 2; + d9 = 15.0D - k1; + break; + case 1: + d8 = 1.0D; + d9 = 8.0D - k1 / 2; + break; + case 2: + d8 = 8.0D - k1 / 2; + d9 = 1.0D; + break; + case 3: + d8 = 15.0D - k1; + d9 = 8.0D - k1 / 2; + } + + double d10 = x + d8 / 16.0D; + double d11 = x + (d8 + k1) / 16.0D; + double d12 = y + (12.0D - l1) / 16.0D; + double d13 = y + 0.75D; + double d14 = z + d9 / 16.0D; + double d15 = z + (d9 + k1) / 16.0D; + tessellator.addVertexWithUV(d10, d12, d14, d4, d7); + tessellator.addVertexWithUV(d10, d12, d15, d5, d7); + tessellator.addVertexWithUV(d10, d13, d15, d5, d6); + tessellator.addVertexWithUV(d10, d13, d14, d4, d6); + tessellator.addVertexWithUV(d11, d12, d15, d4, d7); + tessellator.addVertexWithUV(d11, d12, d14, d5, d7); + tessellator.addVertexWithUV(d11, d13, d14, d5, d6); + tessellator.addVertexWithUV(d11, d13, d15, d4, d6); + tessellator.addVertexWithUV(d11, d12, d14, d4, d7); + tessellator.addVertexWithUV(d10, d12, d14, d5, d7); + tessellator.addVertexWithUV(d10, d13, d14, d5, d6); + tessellator.addVertexWithUV(d11, d13, d14, d4, d6); + tessellator.addVertexWithUV(d10, d12, d15, d4, d7); + tessellator.addVertexWithUV(d11, d12, d15, d5, d7); + tessellator.addVertexWithUV(d11, d13, d15, d5, d6); + tessellator.addVertexWithUV(d10, d13, d15, d4, d6); + int i2 = k1; + + if (maturity >= 2) + i2 = k1 - 1; + + d4 = (double)podIcon.getMinU(); + d5 = (double)podIcon.getInterpolatedU((double)i2); + d6 = (double)podIcon.getMinV(); + d7 = (double)podIcon.getInterpolatedV((double)i2); + + tessellator.addVertexWithUV(d10, d13, d15, d4, d7); + tessellator.addVertexWithUV(d11, d13, d15, d5, d7); + tessellator.addVertexWithUV(d11, d13, d14, d5, d6); + tessellator.addVertexWithUV(d10, d13, d14, d4, d6); + tessellator.addVertexWithUV(d10, d12, d14, d4, d6); + tessellator.addVertexWithUV(d11, d12, d14, d5, d6); + tessellator.addVertexWithUV(d11, d12, d15, d5, d7); + tessellator.addVertexWithUV(d10, d12, d15, d4, d7); + d4 = (double)podIcon.getInterpolatedU(12.0D); + d5 = (double)podIcon.getMaxU(); + d6 = (double)podIcon.getMinV(); + d7 = (double)podIcon.getInterpolatedV(4.0D); + d8 = 8.0D; + d9 = 0.0D; + double d16; + + switch (notchDirection) { + case 0: + d8 = 8.0D; + d9 = 12.0D; + d16 = d4; + d4 = d5; + d5 = d16; + break; + case 1: + d8 = 0.0D; + d9 = 8.0D; + break; + case 2: + d8 = 8.0D; + d9 = 0.0D; + break; + case 3: + d8 = 12.0D; + d9 = 8.0D; + d16 = d4; + d4 = d5; + d5 = d16; + } + + d10 = x + d8 / 16.0D; + d11 = x + (d8 + 4.0D) / 16.0D; + d12 = y + 0.75D; + d13 = y + 1.0D; + d14 = z + d9 / 16.0D; + d15 = z + (d9 + 4.0D) / 16.0D; + + if (notchDirection != 2 && notchDirection != 0) { + if (notchDirection == 1 || notchDirection == 3) { + tessellator.addVertexWithUV(d11, d12, d14, d4, d7); + tessellator.addVertexWithUV(d10, d12, d14, d5, d7); + tessellator.addVertexWithUV(d10, d13, d14, d5, d6); + tessellator.addVertexWithUV(d11, d13, d14, d4, d6); + tessellator.addVertexWithUV(d10, d12, d14, d5, d7); + tessellator.addVertexWithUV(d11, d12, d14, d4, d7); + tessellator.addVertexWithUV(d11, d13, d14, d4, d6); + tessellator.addVertexWithUV(d10, d13, d14, d5, d6); + } + } else { + tessellator.addVertexWithUV(d10, d12, d14, d5, d7); + tessellator.addVertexWithUV(d10, d12, d15, d4, d7); + tessellator.addVertexWithUV(d10, d13, d15, d4, d6); + tessellator.addVertexWithUV(d10, d13, d14, d5, d6); + tessellator.addVertexWithUV(d10, d12, d15, d4, d7); + tessellator.addVertexWithUV(d10, d12, d14, d5, d7); + tessellator.addVertexWithUV(d10, d13, d14, d5, d6); + tessellator.addVertexWithUV(d10, d13, d15, d4, d6); + } + + return true; + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + return false; + } + + @Override + public int getRenderId() { + return PluginArboriculture.modelIdPods; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/render/LeavesRenderingHandler.java b/forestry_common/arboriculture/forestry/arboriculture/render/LeavesRenderingHandler.java new file mode 100755 index 000000000..4589694e5 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/render/LeavesRenderingHandler.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.render; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +import forestry.arboriculture.gadgets.BlockLeaves; +import forestry.arboriculture.gadgets.TileLeaves; +import forestry.core.render.OverlayRenderingHandler; +import forestry.plugins.PluginArboriculture; + +/** + * Ugly but serviceable renderer for leaves, taking fruits into account. + */ +public class LeavesRenderingHandler extends OverlayRenderingHandler { + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + + // Render the plain leaf block. + renderer.renderStandardBlock(block, x, y, z); + + // Render overlay for fruit leaves. + TileLeaves tile = BlockLeaves.getLeafTile(world, x, y, z); + IIcon fruitIcon = null; + int fruitColor = 0xffffff; + if (tile != null) { + fruitIcon = tile.getFruitTexture(); + fruitColor = tile.getFruitColour(); + } + + if (fruitIcon != null) + renderFruitOverlay(world, block, x, y, z, renderer, fruitIcon, fruitColor); + + return true; + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + return false; + } + + @Override + public int getRenderId() { + return PluginArboriculture.modelIdLeaves; + } + + private boolean renderFruitOverlay(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, IIcon texture, int multiplier) { + + float mR = (multiplier >> 16 & 255) / 255.0F; + float mG = (multiplier >> 8 & 255) / 255.0F; + float mB = (multiplier & 255) / 255.0F; + + if (EntityRenderer.anaglyphEnable) { + mR = (mR * 30.0F + mG * 59.0F + mB * 11.0F) / 100.0F; + mG = (mR * 30.0F + mG * 70.0F) / 100.0F; + mB = (mR * 30.0F + mB * 70.0F) / 100.0F; + } + + return renderFruitOverlayWithColorMultiplier(world, block, x, y, z, mR, mG, mB, renderer, texture); + } + + private boolean renderFruitOverlayWithColorMultiplier(IBlockAccess world, Block block, int x, int y, int z, float r, float g, float b, + RenderBlocks renderer, IIcon texture) { + + int mixedBrightness = block.getMixedBrightnessForBlock(world, x, y, z); + + float adjR = 0.5f * r; + float adjG = 0.5f * g; + float adjB = 0.5f * b; + + // Bottom + renderBottomFace(world, block, x, y, z, renderer, texture, mixedBrightness, adjR, adjG, adjB); + renderTopFace(world, block, x, y, z, renderer, texture, mixedBrightness, adjR, adjG, adjB); + renderEastFace(world, block, x, y, z, renderer, texture, mixedBrightness, adjR, adjG, adjB); + renderWestFace(world, block, x, y, z, renderer, texture, mixedBrightness, adjR, adjG, adjB); + renderNorthFace(world, block, x, y, z, renderer, texture, mixedBrightness, adjR, adjG, adjB); + renderSouthFace(world, block, x, y, z, renderer, texture, mixedBrightness, adjR, adjG, adjB); + + return true; + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/render/SaplingRenderHandler.java b/forestry_common/arboriculture/forestry/arboriculture/render/SaplingRenderHandler.java new file mode 100755 index 000000000..9f916beaa --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/render/SaplingRenderHandler.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.render; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.IAlleleTreeSpecies; +import forestry.arboriculture.gadgets.BlockSapling; +import forestry.arboriculture.gadgets.TileSapling; +import forestry.plugins.PluginArboriculture; + +public class SaplingRenderHandler implements ISimpleBlockRenderingHandler { + + public static int renderLayer = 0; + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + + if (modelId != this.getRenderId()) + return false; + + TileSapling tile = BlockSapling.getSaplingTile(world, x, y, z); + + IAlleleTreeSpecies species = (IAlleleTreeSpecies) PluginArboriculture.treeInterface.getDefaultTemplate()[0]; + if (tile == null || tile.getTree() == null) + return true; + species = tile.getTree().getGenome().getPrimary(); + + renderCrossedSquares(species, world, block, x, y, z); + renderLayer = 1; + renderCrossedSquares(species, world, block, x, y, z); + renderLayer = 0; + return true; + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + return false; + } + + @Override + public int getRenderId() { + return PluginArboriculture.modelIdSaplings; + } + + protected boolean renderCrossedSquares(IAlleleTreeSpecies species, IBlockAccess world, Block block, int x, int y, int z) { + + Tessellator tess = Tessellator.instance; + + tess.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z)); + int colourMultiplier = species.getGermlingColour(EnumGermlingType.SAPLING, renderLayer); + float r = (colourMultiplier >> 16 & 255) / 255.0F; + float g = (colourMultiplier >> 8 & 255) / 255.0F; + float b = (colourMultiplier & 255) / 255.0F; + + if (EntityRenderer.anaglyphEnable) { + + r = (r * 30.0F + g * 59.0F + b * 11.0F) / 100.0F; + g = (r * 30.0F + g * 70.0F) / 100.0F; + b = (r * 30.0F + b * 70.0F) / 100.0F; + } + + tess.setColorOpaque_F(r, g, b); + drawCrossedSquares(world, species, block, x, y, z, x, y, z, 1.0f); + return true; + } + + protected void drawCrossedSquares(IBlockAccess world, IAlleleTreeSpecies species, Block block, int x, int y, int z, double par3, double par5, double par7, float mod) { + + Tessellator tess = Tessellator.instance; + IIcon icon = species.getGermlingIcon(EnumGermlingType.SAPLING, renderLayer); + + double d3 = (double)icon.getMinU(); + double d4 = (double)icon.getMinV(); + double d5 = (double)icon.getMaxU(); + double d6 = (double)icon.getMaxV(); + double d7 = 0.45D * mod; + double d8 = par3 + 0.5D - d7; + double d9 = par3 + 0.5D + d7; + double d10 = par7 + 0.5D - d7; + double d11 = par7 + 0.5D + d7; + tess.addVertexWithUV(d8, par5 + mod, d10, d3, d4); + tess.addVertexWithUV(d8, par5 + 0.0D, d10, d3, d6); + tess.addVertexWithUV(d9, par5 + 0.0D, d11, d5, d6); + tess.addVertexWithUV(d9, par5 + mod, d11, d5, d4); + tess.addVertexWithUV(d9, par5 + mod, d11, d3, d4); + tess.addVertexWithUV(d9, par5 + 0.0D, d11, d3, d6); + tess.addVertexWithUV(d8, par5 + 0.0D, d10, d5, d6); + tess.addVertexWithUV(d8, par5 + mod, d10, d5, d4); + tess.addVertexWithUV(d8, par5 + mod, d11, d3, d4); + tess.addVertexWithUV(d8, par5 + 0.0D, d11, d3, d6); + tess.addVertexWithUV(d9, par5 + 0.0D, d10, d5, d6); + tess.addVertexWithUV(d9, par5 + mod, d10, d5, d4); + tess.addVertexWithUV(d9, par5 + mod, d10, d3, d4); + tess.addVertexWithUV(d9, par5 + 0.0D, d10, d3, d6); + tess.addVertexWithUV(d8, par5 + 0.0D, d11, d5, d6); + tess.addVertexWithUV(d8, par5 + mod, d11, d5, d4); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/render/StairItemRenderer.java b/forestry_common/arboriculture/forestry/arboriculture/render/StairItemRenderer.java new file mode 100755 index 000000000..b3657a682 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/render/StairItemRenderer.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.render; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import net.minecraftforge.client.IItemRenderer; + +import org.lwjgl.opengl.GL11; + +import forestry.arboriculture.WoodType; +import forestry.core.utils.StackUtils; + +public class StairItemRenderer implements IItemRenderer { + + private void renderStairBlock(RenderBlocks renderBlocks, ItemStack item, float f, float g, float h) { + + Tessellator tessellator = Tessellator.instance; + Block block = StackUtils.getBlock(item); + + IIcon texture = WoodType.getFromCompound(item.getTagCompound()).getPlankIcon(); + + for (int i = 0; i < 2; ++i) { + if (i == 0) + renderBlocks.setRenderBounds(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.5D); + + if (i == 1) + renderBlocks.setRenderBounds(0.0D, 0.0D, 0.5D, 1.0D, 0.5D, 1.0D); + + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + renderBlocks.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, texture); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 1.0F, 0.0F); + renderBlocks.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, texture); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, -1.0F); + renderBlocks.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, texture); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, 1.0F); + renderBlocks.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, texture); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(-1.0F, 0.0F, 0.0F); + renderBlocks.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, texture); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(1.0F, 0.0F, 0.0F); + renderBlocks.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, texture); + tessellator.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + } + + } + + @Override + public boolean handleRenderType(ItemStack item, ItemRenderType type) { + switch (type) { + case ENTITY: + case EQUIPPED_FIRST_PERSON: + case EQUIPPED: + case INVENTORY: + return true; + default: + return false; + } + } + + @Override + public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) { + return true; + } + + @Override + public void renderItem(ItemRenderType type, ItemStack item, Object... data) { + switch (type) { + case ENTITY: + renderStairBlock((RenderBlocks) data[0], item, -0.5f, -0.5f, -0.5f); + break; + case EQUIPPED: + case EQUIPPED_FIRST_PERSON: + renderStairBlock((RenderBlocks) data[0], item, 0f, 0.0f, 0.0f); + break; + case INVENTORY: + renderStairBlock((RenderBlocks) data[0], item, -0.5f, -0.5f, -0.5f); + break; + default: + } + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeLeaf.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeLeaf.java new file mode 100755 index 000000000..a79423cf8 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeLeaf.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import net.minecraft.world.World; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class BlockTypeLeaf extends BlockType { + + private String owner; + + public BlockTypeLeaf(String owner) { + super(ForestryBlock.leaves, 0); + } + + @Override + public void setBlock(World world, ITreeGenData tree, int x, int y, int z) { + tree.setLeaves(world, owner, x, y, z); + } +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeVoid.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeVoid.java new file mode 100755 index 000000000..235b395cc --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/BlockTypeVoid.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import net.minecraft.init.Blocks; +import net.minecraft.world.World; + +import forestry.api.world.ITreeGenData; +import forestry.core.worldgen.BlockType; + +public class BlockTypeVoid extends BlockType { + + public BlockTypeVoid() { + super(Blocks.air, 0); + } + + @Override + public void setBlock(World world, ITreeGenData tree, int x, int y, int z) { + world.setBlockToAir(x, y, z); + if (world.getTileEntity(x, y, z) != null) + world.removeTileEntity(x, y, z); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenAcacia.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenAcacia.java new file mode 100755 index 000000000..e5f1e606a --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenAcacia.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenAcacia extends WorldGenTree { + + public WorldGenAcacia(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + float rnd = world.rand.nextFloat(); + int offset = 0; + if(rnd > 0.6f) + offset = rand.nextInt(girth); + else if(rnd > 0.3) + offset = -rand.nextInt(girth); + + + generateAdjustedCylinder(leafSpawn--, offset, 0, 1, leaf, EnumReplaceMode.NONE); + generateAdjustedCylinder(leafSpawn--, offset, 1.5f, 1, leaf, EnumReplaceMode.NONE); + + if (rand.nextBoolean()) + generateAdjustedCylinder(leafSpawn--, offset, 3.9f, 1, leaf, EnumReplaceMode.NONE); + else + generateAdjustedCylinder(leafSpawn--, offset, 2.9f, 1, leaf, EnumReplaceMode.NONE); + } + + @Override + public void preGenerate() { + height = determineHeight(5, 2); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log1, 2); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenArboriculture.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenArboriculture.java new file mode 100755 index 000000000..9496eced8 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenArboriculture.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.TileEntity; + +import forestry.api.world.ITreeGenData; +import forestry.arboriculture.gadgets.TileSapling; +import forestry.core.config.Config; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; +import forestry.core.worldgen.BlockType; +import forestry.core.worldgen.WorldGenBase; + +public abstract class WorldGenArboriculture extends WorldGenBase { + + protected ITreeGenData tree; + protected int startX; + protected int startY; + protected int startZ; + + protected boolean spawnPods = false; + protected int minPodHeight = 3; + + public WorldGenArboriculture(ITreeGenData tree) { + this.tree = tree; + } + + @Override + public boolean subGenerate(int x, int y, int z) { + this.startX = x; + this.startY = y; + this.startZ = z; + + this.spawnPods = tree.allowsFruitBlocks(); + this.leaf = getLeaf(getOwner()); + this.wood = getWood(); + + preGenerate(); + if (!canGrow()) + return false; + else { + generate(); + return true; + } + + } + + private String getOwner() { + TileEntity tile = world.getTileEntity(startX, startY, startZ); + if (!(tile instanceof TileSapling)) + return Config.fakeUserLogin; + + return ((TileSapling) tile).getOwnerName(); + } + + public abstract void preGenerate(); + + public abstract void generate(); + + public abstract boolean canGrow(); + + public abstract BlockType getLeaf(String owner); + + public abstract BlockType getWood(); + + BlockType leaf; + BlockType wood; + BlockType vine = new BlockType(Blocks.vine, 0); + BlockType air = new BlockTypeVoid(); + + public final Vect getStartVector() { + return new Vect(startX, startY, startZ); + } + + protected void generateTreeTrunk(int height, int girth) { + generateTreeTrunk(height, girth, 0); + } + + protected void generateTreeTrunk(int height, int girth, float vines) { + int offset = (girth - 1) / 2; + for (int x = 0; x < girth; x++) + for (int y = 0; y < girth; y++) + for (int i = 0; i < height; i++) { + addWood(x - offset, i, y - offset, EnumReplaceMode.ALL); + + if (rand.nextFloat() < vines) + addVine(x - offset - 1, i, y - offset); + if (rand.nextFloat() < vines) + addVine(x - offset + 1, i, y - offset); + if (rand.nextFloat() < vines) + addVine(x - offset, i, y - offset - 1); + if (rand.nextFloat() < vines) + addVine(x - offset, i, y - offset + 1); + } + + if (!spawnPods) + return; + + for (int y = minPodHeight; y < height; y++) + for (int x = 0; x < girth; x++) + for (int z = 0; z < girth; z++) { + + if ((x > 0 && x < girth) && (z > 0 && z < girth)) + continue; + + tree.trySpawnFruitBlock(world, startX + x + 1, startY + y, startZ + z); + tree.trySpawnFruitBlock(world, startX + x - 1, startY + y, startZ + z); + tree.trySpawnFruitBlock(world, startX + x, startY + y, startZ + z + 1); + tree.trySpawnFruitBlock(world, startX + x, startY + y, startZ + z - 1); + } + + } + + protected void generateSupportStems(int height, int girth, float chance, float maxHeight) { + + int offset = 1; + + for (int x = -offset; x < girth + offset; x++) + for (int z = -offset; z < girth + offset; z++) { + + if (x == -offset && z == -offset) + continue; + if (x == girth + offset && z == girth + offset) + continue; + if (x == -offset && z == girth + offset) + continue; + if (x == girth + offset && z == -offset) + continue; + + int stemHeight = rand.nextInt(Math.round(height * maxHeight)); + if (rand.nextFloat() < chance) + for (int i = 0; i < stemHeight; i++) + addWood(x, i, z, EnumReplaceMode.SOFT); + } + + } + + @Override + protected void addBlock(int x, int y, int z, BlockType type, EnumReplaceMode replace) { + if (replace == EnumReplaceMode.ALL + || replace == EnumReplaceMode.SOFT && Utils.isReplaceableBlock(world, startX + x, startY + y, startZ + z) + || world.isAirBlock(startX + x, startY + y, startZ + z)) + type.setBlock(world, tree, startX + x, startY + y, startZ + z); + } + + protected final void clearBlock(int x, int y, int z) { + air.setBlock(world, tree, startX + x, startY + y, startZ + z); + } + + protected final void addWood(int x, int y, int z, EnumReplaceMode replace) { + addBlock(x, y, z, wood, replace); + } + + protected final void addLeaf(int x, int y, int z, EnumReplaceMode replace) { + addBlock(x, y, z, leaf, replace); + } + + protected final void addVine(int x, int y, int z) { + addBlock(x, y, z, vine, EnumReplaceMode.NONE); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBalsa.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBalsa.java new file mode 100755 index 000000000..7120a4638 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBalsa.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenBalsa extends WorldGenTree { + + public WorldGenBalsa(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height; + + addLeaf(0, leafSpawn--, 0, EnumReplaceMode.NONE); + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + + if (height > 10) + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + + leafSpawn--; + + while (leafSpawn > 6) { + generateAdjustedCylinder(leafSpawn, 0, 1, leaf); + leafSpawn--; + } + + } + + @Override + public void preGenerate() { + height = determineHeight(6, 6); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log3, 3); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBaobab.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBaobab.java new file mode 100755 index 000000000..bb62d5431 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBaobab.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenBaobab extends WorldGenTree { + + public WorldGenBaobab(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height - 1, girth); + + if (rand.nextFloat() < 0.3f) + generateCylinder(new Vector(0, height - 1, 0), girth, 1, wood, EnumReplaceMode.NONE); + else if (rand.nextBoolean()) + generateCylinder(new Vector(0, height - 1, 0), girth - 1, 1, wood, EnumReplaceMode.NONE); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1f, 1, leaf); + + // Add tree top + for (int times = 0; times < height / 2; times++) { + int h = height - 1 + rand.nextInt(4); + if (rand.nextBoolean() && h < height / 2) + h = height / 2 + rand.nextInt(height / 2); + + int x_off = -girth + rand.nextInt(2 * girth); + int y_off = -girth + rand.nextInt(2 * girth); + generateSphere(new Vector(x_off, h, y_off), 1 + (girth > 1 ? rand.nextInt(girth - 1) : 0), leaf, EnumReplaceMode.NONE); + } + + // Add some smaller twigs below for flavour + for (int times = 0; times < height / 4; times++) { + int delim = modifyByHeight(6, 0, height); + int h = delim + (delim < height ? rand.nextInt(height - delim) : 0); + if (rand.nextBoolean() && h < height / 2) + h = height / 2 + rand.nextInt(height / 2); + int x_off = -1 + rand.nextInt(3); + int y_off = -1 + rand.nextInt(3); + generateSphere(new Vector(x_off, h, y_off), 1 + rand.nextInt(2), leaf, EnumReplaceMode.NONE); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(6, 6); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log2, 2); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBirch.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBirch.java new file mode 100755 index 000000000..e106ba986 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenBirch.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import net.minecraft.init.Blocks; + +import forestry.api.world.ITreeGenData; +import forestry.core.worldgen.BlockType; + +public class WorldGenBirch extends WorldGenTree { + + public WorldGenBirch(ITreeGenData tree) { + super(tree); + } + + @Override + public BlockType getWood() { + return new BlockType(Blocks.log, 2); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenCherry.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenCherry.java new file mode 100755 index 000000000..400214d58 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenCherry.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenCherry extends WorldGenTree { + + public WorldGenCherry(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + while (leafSpawn > 2) { + generateAdjustedCylinder(leafSpawn--, 2, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(4, 4); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log4, 3); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenChestnut.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenChestnut.java new file mode 100755 index 000000000..eb0f7b2b6 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenChestnut.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenChestnut extends WorldGenTree { + + public WorldGenChestnut(ITreeGenData tree) { + super(tree); + + minHeight = 7; + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + while (leafSpawn > 4) + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + if (rand.nextBoolean()) + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + + } + + @Override + public void preGenerate() { + height = determineHeight(7, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log2, 0); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenDate.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenDate.java new file mode 100755 index 000000000..846f16dce --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenDate.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenDate extends WorldGenTree { + + public WorldGenDate(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log5, 2); + } + + @Override + public void preGenerate() { + height = determineHeight(6, 2); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenEbony.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenEbony.java new file mode 100755 index 000000000..39f280146 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenEbony.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenEbony extends WorldGenTree { + + public WorldGenEbony(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + + int offset = (girth - 1) / 2; + int trunksgenerated = 0; + + for (int x = -offset; x < -offset + girth; x++) + for (int z = -offset; z < -offset + girth; z++) + if (rand.nextFloat() < 0.6f) { + for (int i = 0; i < height; i++) { + addWood(x, i, z, EnumReplaceMode.ALL); + if (i > height / 2 && rand.nextFloat() < 0.1f * (10 / height)) + break; + } + trunksgenerated++; + } else + for (int i = 0; i < 1; i++) + clearBlock(x, i, z); + + // Generate backup trunk, if we failed to generate any. + if (trunksgenerated <= 0) + generateTreeTrunk(height, 1, 0.6f); + + // Add tree top + for (int times = 0; times < 2 * height; times++) { + int h = 2 * girth + rand.nextInt(height - girth); + if (rand.nextBoolean() && h < height / 2) + h = height / 2 + rand.nextInt(height / 2); + + int x_off = -(girth) + rand.nextInt(2 * girth); + int y_off = -(girth) + rand.nextInt(2 * girth); + generateSphere(new Vector(x_off, h, y_off), 1 + rand.nextInt(girth), leaf, EnumReplaceMode.NONE); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(10, 4); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log3, 1); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGiganteum.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGiganteum.java new file mode 100755 index 000000000..925a208a2 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGiganteum.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenGiganteum extends WorldGenSequoia { + + public WorldGenGiganteum(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + super.generate(); + //generateSupportStems(height, girth, 0.8f, 0.6f); + } + + @Override + public void preGenerate() { + height = determineHeight(35, 15); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log7, 0); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGreenheart.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGreenheart.java new file mode 100755 index 000000000..68097da23 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenGreenheart.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenGreenheart extends WorldGenTree { + + public WorldGenGreenheart(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + + generateTreeTrunk(height, girth, 0.4f); + generateSupportStems(height, girth, 0.1f, 0.2f); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + + while (leafSpawn > height - 4) + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + // Add some smaller twigs below for flavour + for (int times = 0; times < height / 4; times++) { + int h = 10 + rand.nextInt(height - 10); + if (rand.nextBoolean() && h < height / 2) + h = height / 2 + rand.nextInt(height / 2); + int x_off = -1 + rand.nextInt(3); + int y_off = -1 + rand.nextInt(3); + generateSphere(new Vector(x_off, h, y_off), 1 + rand.nextInt(1), leaf, EnumReplaceMode.NONE); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(10, 8); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log4, 2); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenJungle.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenJungle.java new file mode 100755 index 000000000..7ac7a3f82 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenJungle.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import net.minecraft.init.Blocks; + +import forestry.api.world.ITreeGenData; +import forestry.core.worldgen.BlockType; + +/** + * This is a dummy and needs to be replaced with something proper. + */ +public class WorldGenJungle extends WorldGenTree { + + public WorldGenJungle(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + + } + + @Override + public BlockType getWood() { + return new BlockType(Blocks.log, 3); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenKapok.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenKapok.java new file mode 100755 index 000000000..de0ea2467 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenKapok.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenKapok extends WorldGenTree { + + public WorldGenKapok(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + + generateTreeTrunk(height, girth, 0.6f); + generateSupportStems(height, girth, 0.2f, 0.2f); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + + while (leafSpawn > height - 4) + generateAdjustedCylinder(leafSpawn--, 2.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + + // Add some smaller twigs below for flavour + for (int times = 0; times < height / 4; times++) { + int h = 10 + rand.nextInt(Math.max(1, height - 10)); + if (rand.nextBoolean() && h < height / 2) + h = height / 2 + rand.nextInt(height / 2); + int x_off = -1 + rand.nextInt(3); + int y_off = -1 + rand.nextInt(3); + generateSphere(new Vector(x_off, h, y_off), 1 + rand.nextInt(1), leaf, EnumReplaceMode.NONE); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(10, 8); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log3, 0); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLarch.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLarch.java new file mode 100755 index 000000000..1a565ae48 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLarch.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenLarch extends WorldGenTree { + + public WorldGenLarch(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + + while (leafSpawn > 2) { + generateAdjustedCylinder(leafSpawn--, 2, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(6, 5); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log1, 0); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLemon.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLemon.java new file mode 100755 index 000000000..146a97544 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLemon.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenLemon extends WorldGenTree { + + public WorldGenLemon(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int yCenter = height - girth; + yCenter = yCenter > 2 ? yCenter : 3; + generateSphere(getCenteredAt(yCenter, 0), 2 + rand.nextInt(girth), leaf, EnumReplaceMode.NONE); + + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log6, 3); + } + + @Override + public void preGenerate() { + height = determineHeight(6, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLime.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLime.java new file mode 100755 index 000000000..d9caceb9d --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenLime.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenLime extends WorldGenTree { + + public WorldGenLime(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + while (leafSpawn > 1) + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + + } + + @Override + public void preGenerate() { + height = determineHeight(6, 4); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log1, 3); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahoe.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahoe.java new file mode 100755 index 000000000..57602019e --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahoe.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenMahoe extends WorldGenTree { + + public WorldGenMahoe(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int yCenter = height - girth; + yCenter = yCenter > 3 ? yCenter : 4; + generateSphere(getCenteredAt(yCenter, 0), 3 + rand.nextInt(girth), leaf, EnumReplaceMode.NONE); + + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log5, 0); + } + + @Override + public void preGenerate() { + height = determineHeight(6, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahogany.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahogany.java new file mode 100755 index 000000000..4576507c5 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMahogany.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenMahogany extends WorldGenTree { + + public WorldGenMahogany(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth, 0.6f); + generateSupportStems(height, girth, 0.4f, 0.4f); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 3f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 3f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + + } + + @Override + public void preGenerate() { + height = determineHeight(12, 6); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log3, 2); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMaple.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMaple.java new file mode 100755 index 000000000..3ea6333ea --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenMaple.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenMaple extends WorldGenTree { + + public WorldGenMaple(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + float diameterchange = (float) 1 / height; + int leafSpawned = 2; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + + while (leafSpawn > 1) { + generateAdjustedCylinder(leafSpawn--, 3 * diameterchange * leafSpawned, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 2 * diameterchange * leafSpawned, 1, leaf); + leafSpawned += 2; + } + + } + + @Override + public void preGenerate() { + height = determineHeight(7, 5); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log6, 2); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenOak.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenOak.java new file mode 100755 index 000000000..a1b5f0a4d --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenOak.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import net.minecraft.init.Blocks; + +import forestry.api.world.ITreeGenData; +import forestry.core.worldgen.BlockType; + +public class WorldGenOak extends WorldGenTree { + + public WorldGenOak(ITreeGenData tree) { + super(tree); + } + + @Override + public BlockType getWood() { + return new BlockType(Blocks.log, 0); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPapaya.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPapaya.java new file mode 100755 index 000000000..4df4d813c --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPapaya.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenPapaya extends WorldGenTree { + + public WorldGenPapaya(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int yCenter = height - girth; + yCenter = yCenter > 3 ? yCenter : 4; + generateSphere(getCenteredAt(yCenter, 0), 2 + rand.nextInt(girth), leaf, EnumReplaceMode.NONE); + + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log5, 3); + } + + @Override + public void preGenerate() { + height = determineHeight(7, 2); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPine.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPine.java new file mode 100755 index 000000000..78ff6864b --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPine.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenPine extends WorldGenTree { + + public WorldGenPine(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + float diameterchange = (float) 1 / height; + int leafSpawned = 2; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + + while (leafSpawn > 1) { + generateAdjustedCylinder(leafSpawn--, 3 * diameterchange * leafSpawned, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 2 * diameterchange * leafSpawned, 1, leaf); + leafSpawned += 2; + } + + } + + @Override + public void preGenerate() { + height = determineHeight(6, 4); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log6, 0); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPlum.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPlum.java new file mode 100755 index 000000000..68207c395 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPlum.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenPlum extends WorldGenTree { + + public WorldGenPlum(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int yCenter = height - girth; + yCenter = yCenter > 2 ? yCenter : 3; + generateSphere(getCenteredAt(yCenter, 0), 2 + rand.nextInt(girth), leaf, EnumReplaceMode.NONE); + + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log6, 1); + } + + @Override + public void preGenerate() { + height = determineHeight(6, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPoplar.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPoplar.java new file mode 100755 index 000000000..dd7bd2cdb --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenPoplar.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenPoplar extends WorldGenTree { + + public WorldGenPoplar(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + while (leafSpawn > girth - 1) + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log5, 1); + } + + @Override + public void preGenerate() { + height = determineHeight(8, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSequoia.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSequoia.java new file mode 100755 index 000000000..2e424389b --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSequoia.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenSequoia extends WorldGenTree { + + public WorldGenSequoia(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int topLength = height / 4; + + int topHeight = height - topLength + rand.nextInt(height / 4); + + int leafSpawn = height + 2; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + + while (leafSpawn > topHeight) + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + + for (int times = 0; times < height / 4; times++) { + int h = (height/3) + rand.nextInt(height - (height/3)); + if (rand.nextBoolean() && h < height / 3) + h = height / 2 + rand.nextInt(height / 3); + int x_off = -1 + rand.nextInt(3); + int y_off = -1 + rand.nextInt(3); + generateSphere(new Vector(x_off, h, y_off), 1 + rand.nextInt(2), leaf, EnumReplaceMode.NONE); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(20, 5); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log2, 3); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSpruce.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSpruce.java new file mode 100755 index 000000000..4554f29a7 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenSpruce.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import net.minecraft.init.Blocks; + +import forestry.api.world.ITreeGenData; +import forestry.core.worldgen.BlockType; + +public class WorldGenSpruce extends WorldGenTree { + + public WorldGenSpruce(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + + while (leafSpawn > 2) { + generateAdjustedCylinder(leafSpawn--, 2, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1, 1, leaf); + } + + } + + @Override + public void preGenerate() { + height = determineHeight(5, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(Blocks.log, 1); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTeak.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTeak.java new file mode 100755 index 000000000..23b410258 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTeak.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenTeak extends WorldGenTree { + + public WorldGenTeak(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + if (rand.nextBoolean()) + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + } + + @Override + public void preGenerate() { + height = determineHeight(6, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log1, 1); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTree.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTree.java new file mode 100755 index 000000000..54b948fce --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenTree.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.worldgen.BlockType; +import forestry.plugins.PluginArboriculture; + +public abstract class WorldGenTree extends WorldGenArboriculture { + + protected int girth; + protected int height; + + protected int minHeight = 4; + protected int maxHeight = 80; + + public WorldGenTree(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf, EnumReplaceMode.NONE); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf, EnumReplaceMode.NONE); + + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf, EnumReplaceMode.NONE); + generateAdjustedCylinder(leafSpawn--, 1.9f, 1, leaf, EnumReplaceMode.NONE); + + } + + protected Vector getCenteredAt(int yCenter, int offset) { + float cent = girth % 2 == 0 ? 0.5f : 0f; + return new Vector(cent + offset, yCenter, cent + offset); + } + + protected void generateAdjustedCylinder(int yCenter, float radius, int height, BlockType block) { + generateAdjustedCylinder(yCenter, 0, radius, height, block, EnumReplaceMode.NONE); + } + + protected void generateAdjustedCylinder(int yCenter, float radius, int height, BlockType block, EnumReplaceMode replace) { + generateAdjustedCylinder(yCenter, 0, radius, height, block, replace); + } + + protected void generateAdjustedCylinder(int yCenter, int offset, float radius, int height, BlockType block, EnumReplaceMode replace) { + generateCylinder(getCenteredAt(yCenter, offset), radius + girth, height, block, replace); + } + + @Override + public boolean canGrow() { + return tree.canGrow(world, startX, startY, startZ, tree.getGirth(world, startX, startY, startZ), height); + + } + + @Override + public void preGenerate() { + height = determineHeight(5, 2); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + protected int determineGirth(int base) { + return base; + } + + protected int modifyByHeight(int val, int min, int max) { + int determined = Math.round(val * tree.getHeightModifier() * PluginArboriculture.treeInterface.getTreekeepingMode(world).getHeightModifier(null, 1f)); + return determined < min ? min : determined > max ? max : determined; + } + + // TODO: Get access to the tree genome for the treekeeping mode + protected int determineHeight(int required, int variation) { + int determined = Math.round((required + rand.nextInt(variation)) * tree.getHeightModifier() + * PluginArboriculture.treeInterface.getTreekeepingMode(world).getHeightModifier(null, 1f)); + return determined < minHeight ? minHeight : determined > maxHeight ? maxHeight : determined; + } + + @Override + public BlockType getLeaf(String owner) { + return new BlockTypeLeaf(owner); + } + + @Override + public abstract BlockType getWood(); + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWalnut.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWalnut.java new file mode 100755 index 000000000..0a2e5676b --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWalnut.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenWalnut extends WorldGenTree { + + public WorldGenWalnut(ITreeGenData tree) { + super(tree); + + minHeight = 7; + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + + while (leafSpawn > 3) + generateAdjustedCylinder(leafSpawn--, 3f, 1, leaf); + if (rand.nextBoolean()) + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + + } + + @Override + public void preGenerate() { + height = determineHeight(7, 3); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log4, 1); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWenge.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWenge.java new file mode 100755 index 000000000..4f7acaaaa --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWenge.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenWenge extends WorldGenTree { + + public WorldGenWenge(ITreeGenData tree) { + super(tree); + minHeight = 6; + } + + @Override + public void generate() { + generateTreeTrunk(height, girth); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 0.5f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 2f, 1, leaf); + + while (leafSpawn > 1) + generateAdjustedCylinder(leafSpawn--, 3f, 1, leaf); + + } + + @Override + public void preGenerate() { + height = determineHeight(6, 2); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log2, 1); + } + +} diff --git a/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWillow.java b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWillow.java new file mode 100755 index 000000000..9ece73043 --- /dev/null +++ b/forestry_common/arboriculture/forestry/arboriculture/worldgen/WorldGenWillow.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.arboriculture.worldgen; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.ForestryBlock; +import forestry.core.worldgen.BlockType; + +public class WorldGenWillow extends WorldGenTree { + + public WorldGenWillow(ITreeGenData tree) { + super(tree); + } + + @Override + public void generate() { + + generateTreeTrunk(height, girth, 0.8f); + generateSupportStems(height, girth, 0.2f, 0.2f); + + int leafSpawn = height + 1; + + generateAdjustedCylinder(leafSpawn--, 0, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 1.5f, 1, leaf); + + generateAdjustedCylinder(leafSpawn--, 2.5f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 3f, 1, leaf); + generateAdjustedCylinder(leafSpawn--, 3f, 1, leaf); + while (leafSpawn > 2) + generateCircle(new Vector(0f, leafSpawn--, 0f), 4f, 2, 1, leaf, EnumReplaceMode.NONE); + generateCircle(new Vector(0f, leafSpawn--, 0f), 4f, 1, 1, leaf, EnumReplaceMode.NONE); + generateCircle(new Vector(0f, leafSpawn--, 0f), 4f, 1, 1, leaf, EnumReplaceMode.NONE); + generateCircle(new Vector(0f, leafSpawn--, 0f), 4f, 1, 1, leaf, 0.4f, EnumReplaceMode.NONE); + + } + + @Override + public void preGenerate() { + height = determineHeight(5, 2); + girth = determineGirth(tree.getGirth(world, startX, startY, startZ)); + } + + @Override + public BlockType getWood() { + return new BlockType(ForestryBlock.log4, 0); + } + +} diff --git a/forestry_common/arboriculture/forestry/plugins/PluginArboriculture.java b/forestry_common/arboriculture/forestry/plugins/PluginArboriculture.java new file mode 100755 index 000000000..48cf4b833 --- /dev/null +++ b/forestry_common/arboriculture/forestry/plugins/PluginArboriculture.java @@ -0,0 +1,1130 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.command.ICommand; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.WeightedRandomChestContent; + +import cpw.mods.fml.common.IFuelHandler; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInterModComms; +import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.common.registry.GameData; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.common.registry.VillagerRegistry; + +import net.minecraftforge.common.ChestGenHooks; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.oredict.OreDictionary; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.ITree; +import forestry.api.arboriculture.ITreeRoot; +import forestry.api.arboriculture.TreeManager; +import forestry.api.core.PluginInfo; +import forestry.api.core.Tabs; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IClassification.EnumClassLevel; +import forestry.api.genetics.IFruitFamily; +import forestry.api.recipes.RecipeManagers; +import forestry.api.storage.BackpackManager; +import forestry.arboriculture.CommandSpawnForest; +import forestry.arboriculture.CommandSpawnTree; +import forestry.arboriculture.CommandTreekeepingMode; +import forestry.arboriculture.EventHandlerArboriculture; +import forestry.arboriculture.FruitProviderNone; +import forestry.arboriculture.FruitProviderPod; +import forestry.arboriculture.FruitProviderPod.EnumPodType; +import forestry.arboriculture.FruitProviderRandom; +import forestry.arboriculture.FruitProviderRipening; +import forestry.arboriculture.GuiHandlerArboriculture; +import forestry.arboriculture.PacketHandlerArboriculture; +import forestry.arboriculture.VillageHandlerArboriculture; +import forestry.arboriculture.WoodType; +import forestry.arboriculture.gadgets.BlockArbFence; +import forestry.arboriculture.gadgets.BlockArbFence.FenceCat; +import forestry.arboriculture.gadgets.BlockArbStairs; +import forestry.arboriculture.gadgets.BlockFruitPod; +import forestry.arboriculture.gadgets.BlockLeaves; +import forestry.arboriculture.gadgets.BlockLog; +import forestry.arboriculture.gadgets.BlockLog.LogCat; +import forestry.arboriculture.gadgets.BlockPlanks; +import forestry.arboriculture.gadgets.BlockPlanks.PlankCat; +import forestry.arboriculture.gadgets.BlockSapling; +import forestry.arboriculture.gadgets.BlockSlab; +import forestry.arboriculture.gadgets.BlockSlab.SlabCat; +import forestry.arboriculture.gadgets.TileArboristChest; +import forestry.arboriculture.gadgets.TileFruitPod; +import forestry.arboriculture.gadgets.TileLeaves; +import forestry.arboriculture.gadgets.TileSapling; +import forestry.arboriculture.gadgets.TileStairs; +import forestry.arboriculture.genetics.AlleleFruit; +import forestry.arboriculture.genetics.AlleleGrowth; +import forestry.arboriculture.genetics.AlleleLeafEffectNone; +import forestry.arboriculture.genetics.AlleleTreeSpecies; +import forestry.arboriculture.genetics.BranchTrees; +import forestry.arboriculture.genetics.GrowthProvider; +import forestry.arboriculture.genetics.GrowthProviderTropical; +import forestry.arboriculture.genetics.Tree; +import forestry.arboriculture.genetics.TreeHelper; +import forestry.arboriculture.genetics.TreeMutation; +import forestry.arboriculture.genetics.TreeTemplates; +import forestry.arboriculture.genetics.TreekeepingMode; +import forestry.arboriculture.items.ItemGermlingGE; +import forestry.arboriculture.items.ItemGrafter; +import forestry.arboriculture.items.ItemStairs; +import forestry.arboriculture.items.ItemTreealyzer; +import forestry.arboriculture.items.ItemWoodBlock; +import forestry.arboriculture.proxy.ProxyArboriculture; +import forestry.arboriculture.worldgen.WorldGenAcacia; +import forestry.arboriculture.worldgen.WorldGenBalsa; +import forestry.arboriculture.worldgen.WorldGenBaobab; +import forestry.arboriculture.worldgen.WorldGenBirch; +import forestry.arboriculture.worldgen.WorldGenCherry; +import forestry.arboriculture.worldgen.WorldGenChestnut; +import forestry.arboriculture.worldgen.WorldGenDate; +import forestry.arboriculture.worldgen.WorldGenEbony; +import forestry.arboriculture.worldgen.WorldGenGiganteum; +import forestry.arboriculture.worldgen.WorldGenGreenheart; +import forestry.arboriculture.worldgen.WorldGenJungle; +import forestry.arboriculture.worldgen.WorldGenKapok; +import forestry.arboriculture.worldgen.WorldGenLarch; +import forestry.arboriculture.worldgen.WorldGenLemon; +import forestry.arboriculture.worldgen.WorldGenLime; +import forestry.arboriculture.worldgen.WorldGenMahoe; +import forestry.arboriculture.worldgen.WorldGenMahogany; +import forestry.arboriculture.worldgen.WorldGenMaple; +import forestry.arboriculture.worldgen.WorldGenOak; +import forestry.arboriculture.worldgen.WorldGenPapaya; +import forestry.arboriculture.worldgen.WorldGenPine; +import forestry.arboriculture.worldgen.WorldGenPlum; +import forestry.arboriculture.worldgen.WorldGenPoplar; +import forestry.arboriculture.worldgen.WorldGenSequoia; +import forestry.arboriculture.worldgen.WorldGenSpruce; +import forestry.arboriculture.worldgen.WorldGenTeak; +import forestry.arboriculture.worldgen.WorldGenWalnut; +import forestry.arboriculture.worldgen.WorldGenWenge; +import forestry.arboriculture.worldgen.WorldGenWillow; +import forestry.core.GameMode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.BlockBase; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.genetics.Allele; +import forestry.core.genetics.FruitFamily; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.items.ItemForestryBlock; +import forestry.core.items.ItemFruit.EnumFruit; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.RecipeUtil; +import forestry.core.utils.ShapedRecipeCustom; + +@PluginInfo(pluginID = "Arboriculture", name = "Arboriculture", author = "Binnie & SirSengir", url = Defaults.URL, description = "Adds additional tree species and products.") +public class PluginArboriculture extends NativePlugin implements IFuelHandler { + + @SidedProxy(clientSide = "forestry.arboriculture.proxy.ClientProxyArboriculture", serverSide = "forestry.arboriculture.proxy.ProxyArboriculture") + public static ProxyArboriculture proxy; + public static String treekeepingMode = "NORMAL"; + public static int modelIdSaplings; + public static int modelIdLeaves; + public static int modelIdFences; + public static int modelIdPods; + public static ITreeRoot treeInterface; + public static MachineDefinition definitionChest; + public static List validFences = new ArrayList(); + + @Override + public boolean isAvailable() { + return !Config.disableArboriculture; + } + + @Override + public void preInit() { + super.preInit(); + + ForestryBlock.log1 = new BlockLog(LogCat.CAT0).setBlockName("for.log1"); + Proxies.common.registerBlock(ForestryBlock.log1, ItemWoodBlock.class); + ForestryBlock.log1.setHarvestLevel("axe", 0); + + // Send to BC for facades + for (int i = 0; i < 4; i++) { + FMLInterModComms.sendMessage("BuildCraft|Transport", "add-facade", + GameData.blockRegistry.getNameForObject(ForestryBlock.log1) + "@" + i); + } + + ForestryBlock.log2 = new BlockLog(LogCat.CAT1).setBlockName("for.log2"); + Proxies.common.registerBlock(ForestryBlock.log2, ItemWoodBlock.class); + ForestryBlock.log2.setHarvestLevel("axe", 0); + + for (int i = 0; i < 4; i++) { + FMLInterModComms.sendMessage("BuildCraft|Transport", "add-facade", + GameData.blockRegistry.getNameForObject(ForestryBlock.log2) + "@" + i); + } + + ForestryBlock.log3 = new BlockLog(LogCat.CAT2).setBlockName("for.log3"); + Proxies.common.registerBlock(ForestryBlock.log3, ItemWoodBlock.class); + ForestryBlock.log3.setHarvestLevel("axe", 0); + + for (int i = 0; i < 4; i++) { + FMLInterModComms.sendMessage("BuildCraft|Transport", "add-facade", + GameData.blockRegistry.getNameForObject(ForestryBlock.log3) + "@" + i); + } + + ForestryBlock.log4 = new BlockLog(LogCat.CAT3).setBlockName("for.log4"); + Proxies.common.registerBlock(ForestryBlock.log4, ItemWoodBlock.class); + ForestryBlock.log4.setHarvestLevel("axe", 0); + + for (int i = 0; i < 4; i++) { + FMLInterModComms.sendMessage("BuildCraft|Transport", "add-facade", + GameData.blockRegistry.getNameForObject(ForestryBlock.log4) + "@" + i); + } + + ForestryBlock.log5 = new BlockLog(LogCat.CAT4).setBlockName("for.log5"); + Proxies.common.registerBlock(ForestryBlock.log5, ItemWoodBlock.class); + ForestryBlock.log5.setHarvestLevel("axe", 0); + + for (int i = 0; i < 4; i++) { + FMLInterModComms.sendMessage("BuildCraft|Transport", "add-facade", + GameData.blockRegistry.getNameForObject(ForestryBlock.log5) + "@" + i); + } + + ForestryBlock.log6 = new BlockLog(LogCat.CAT5).setBlockName("for.log6"); + Proxies.common.registerBlock(ForestryBlock.log6, ItemWoodBlock.class); + ForestryBlock.log6.setHarvestLevel("axe", 0); + + for (int i = 0; i < 4; i++) { + FMLInterModComms.sendMessage("BuildCraft|Transport", "add-facade", + GameData.blockRegistry.getNameForObject(ForestryBlock.log6) + "@" + i); + } + + ForestryBlock.log7 = new BlockLog(LogCat.CAT6).setBlockName("for.log7"); + Proxies.common.registerBlock(ForestryBlock.log7, ItemWoodBlock.class); + ForestryBlock.log7.setHarvestLevel("axe", 0); + + // Register as workableLogs + OreDictionary.registerOre("logWood", + new ItemStack(ForestryBlock.log1, 1, Defaults.WILDCARD)); + OreDictionary.registerOre("logWood", + new ItemStack(ForestryBlock.log2, 1, Defaults.WILDCARD)); + OreDictionary.registerOre("logWood", + new ItemStack(ForestryBlock.log3, 1, Defaults.WILDCARD)); + OreDictionary.registerOre("logWood", + new ItemStack(ForestryBlock.log4, 1, Defaults.WILDCARD)); + OreDictionary.registerOre("logWood", + new ItemStack(ForestryBlock.log5, 1, Defaults.WILDCARD)); + OreDictionary.registerOre("logWood", + new ItemStack(ForestryBlock.log6, 1, Defaults.WILDCARD)); + OreDictionary.registerOre("logWood", + new ItemStack(ForestryBlock.log7, 1, Defaults.WILDCARD)); + + // Register smelting + FurnaceRecipes.smelting().func_151393_a(ForestryBlock.log1, + new ItemStack(Items.coal, 1, 1), 0.15F); + FurnaceRecipes.smelting().func_151393_a(ForestryBlock.log2, + new ItemStack(Items.coal, 1, 1), 0.15F); + FurnaceRecipes.smelting().func_151393_a(ForestryBlock.log3, + new ItemStack(Items.coal, 1, 1), 0.15F); + FurnaceRecipes.smelting().func_151393_a(ForestryBlock.log4, + new ItemStack(Items.coal, 1, 1), 0.15F); + FurnaceRecipes.smelting().func_151393_a(ForestryBlock.log5, + new ItemStack(Items.coal, 1, 1), 0.15F); + FurnaceRecipes.smelting().func_151393_a(ForestryBlock.log6, + new ItemStack(Items.coal, 1, 1), 0.15F); + + ForestryBlock.planks1 = new BlockPlanks(PlankCat.CAT0).setBlockName("for.planks"); + Proxies.common.registerBlock(ForestryBlock.planks1, ItemWoodBlock.class); + ForestryBlock.planks1.setHarvestLevel("axe", 0); + + ForestryBlock.planks2 = new BlockPlanks(PlankCat.CAT1).setBlockName("for.planks2"); + Proxies.common.registerBlock(ForestryBlock.planks2, ItemWoodBlock.class); + ForestryBlock.planks2.setHarvestLevel("axe", 0); + + // Register as craftablePlanks + OreDictionary.registerOre("plankWood", new ItemStack(ForestryBlock.planks1, 1, + Defaults.WILDCARD)); + OreDictionary.registerOre("plankWood", new ItemStack(ForestryBlock.planks2, 1, + Defaults.WILDCARD)); + + // Send to BC for facades + for (int i = 0; i < 16; i++) { + FMLInterModComms.sendMessage("BuildCraft|Transport", "add-facade", + GameData.blockRegistry.getNameForObject(ForestryBlock.planks1) + "@" + i); + } + + ForestryBlock.slabs1 = new BlockSlab(SlabCat.CAT0).setBlockName("for.slabs1"); + Proxies.common.registerBlock(ForestryBlock.slabs1, ItemWoodBlock.class); + ForestryBlock.slabs1.setHarvestLevel("axe", 0); + + ForestryBlock.slabs2 = new BlockSlab(SlabCat.CAT1).setBlockName("for.slabs2"); + Proxies.common.registerBlock(ForestryBlock.slabs2, ItemWoodBlock.class); + ForestryBlock.slabs2.setHarvestLevel("axe", 0); + + ForestryBlock.slabs3 = new BlockSlab(SlabCat.CAT2).setBlockName("for.slabs3"); + Proxies.common.registerBlock(ForestryBlock.slabs3, ItemWoodBlock.class); + ForestryBlock.slabs3.setHarvestLevel("axe", 0); + + OreDictionary.registerOre("slabWood", new ItemStack(ForestryBlock.slabs1, 1, + Defaults.WILDCARD)); + OreDictionary.registerOre("slabWood", new ItemStack(ForestryBlock.slabs2, 1, + Defaults.WILDCARD)); + OreDictionary.registerOre("slabWood", new ItemStack(ForestryBlock.slabs3, 1, + Defaults.WILDCARD)); + + // Fences + ForestryBlock.fences1 = new BlockArbFence(FenceCat.CAT0).setBlockName("for.fences"); + Proxies.common.registerBlock(ForestryBlock.fences1, ItemWoodBlock.class); + ForestryBlock.fences1.setHarvestLevel("axe", 0); + + ForestryBlock.fences2 = new BlockArbFence(FenceCat.CAT1).setBlockName("for.fences2"); + Proxies.common.registerBlock(ForestryBlock.fences2, ItemWoodBlock.class); + ForestryBlock.fences2.setHarvestLevel("axe", 0); + + // Stairs + ForestryBlock.stairs = new BlockArbStairs(ForestryBlock.planks1, 0) .setBlockName("for.stairs"); + Proxies.common.registerBlock(ForestryBlock.stairs, ItemStairs.class); + ForestryBlock.stairs.setHarvestLevel("axe", 0); + + // Saplings + ForestryBlock.saplingGE = new BlockSapling().setBlockName("saplingGE"); + Proxies.common.registerBlock(ForestryBlock.saplingGE, ItemForestryBlock.class); + + // Leaves + ForestryBlock.leaves = new BlockLeaves().setBlockName("leaves"); + Proxies.common.registerBlock(ForestryBlock.leaves, ItemForestryBlock.class); + + // Pods + ForestryBlock.pods = new BlockFruitPod().setBlockName("for.pods"); + Proxies.common.registerBlock(ForestryBlock.pods, ItemForestryBlock.class); + + // Machines + ForestryBlock.arboriculture = new BlockBase(Material.iron); + ForestryBlock.arboriculture.setBlockName("for.arboriculture").setCreativeTab(Tabs.tabArboriculture); + Proxies.common.registerBlock(ForestryBlock.arboriculture, ItemForestryBlock.class); + + definitionChest = ForestryBlock.arboriculture.addDefinition(new MachineDefinition(Defaults.DEFINITION_ARBCHEST_META, + "forestry.ArbChest", TileArboristChest.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.arboriculture, + 1, Defaults.DEFINITION_ARBCHEST_META), new Object[] { " # ", "XYX", "XXX", '#', + Blocks.glass, 'X', "treeSapling", 'Y', Blocks.chest })).setFaces(0, 1, 2, 3, 4, 4, 0, 7)); + + + + // Init tree interface + AlleleManager.alleleRegistry + .registerSpeciesRoot(PluginArboriculture.treeInterface = TreeManager.treeInterface = new TreeHelper()); + + // Init rendering + proxy.initializeRendering(); + + // Create alleles + createAlleles(); + + // Register vanilla and forestry fence ids + validFences.add(ForestryBlock.fences1); + validFences.add(ForestryBlock.fences2); + validFences.add(Blocks.fence); + validFences.add(Blocks.fence_gate); + validFences.add(Blocks.nether_brick_fence); + + } + + @Override + public void doInit() { + super.doInit(); + + proxy.addLocalizations(); + + GameRegistry.registerTileEntity(TileSapling.class, "forestry.Sapling"); + GameRegistry.registerTileEntity(TileLeaves.class, "forestry.Leaves"); + GameRegistry.registerTileEntity(TileStairs.class, "forestry.Stairs"); + GameRegistry.registerTileEntity(TileFruitPod.class, "forestry.Pods"); + definitionChest.register(); + + createMutations(); + registerTemplates(); + registerErsatzGenomes(); + + PluginArboriculture.treeInterface.registerTreekeepingMode(TreekeepingMode.easy); + PluginArboriculture.treeInterface.registerTreekeepingMode(TreekeepingMode.normal); + PluginArboriculture.treeInterface.registerTreekeepingMode(TreekeepingMode.hard); + PluginArboriculture.treeInterface.registerTreekeepingMode(TreekeepingMode.hardcore); + PluginArboriculture.treeInterface.registerTreekeepingMode(TreekeepingMode.insane); + + MinecraftForge.EVENT_BUS.register(new EventHandlerArboriculture()); + + VillagerRegistry.instance().registerVillagerId(Defaults.ID_VILLAGER_LUMBERJACK); + Proxies.render.registerVillagerSkin(Defaults.ID_VILLAGER_LUMBERJACK, Defaults.TEXTURE_SKIN_LUMBERJACK); + VillagerRegistry.instance().registerVillageTradeHandler(Defaults.ID_VILLAGER_LUMBERJACK, + new VillageHandlerArboriculture()); + } + + @Override + public void postInit() { + super.postInit(); + registerDungeonLoot(); + + } + + @Override + protected void registerItems() { + + ForestryItem.sapling.registerItem(new ItemGermlingGE(EnumGermlingType.SAPLING), "sapling"); + OreDictionary.registerOre("treeSapling", ForestryItem.sapling.getItemStack(1, -1)); + + ForestryItem.pollenFertile.registerItem(new ItemGermlingGE(EnumGermlingType.POLLEN), "pollenFertile"); + + ForestryItem.treealyzer.registerItem(new ItemTreealyzer(), "treealyzer"); + ForestryItem.grafter.registerItem(new ItemGrafter(4), "grafter"); + ForestryItem.grafterProven.registerItem(new ItemGrafter(149), "grafterProven"); + + } + + @Override + protected void registerBackpackItems() { + if (BackpackManager.backpackItems == null) + return; + + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryBlock.log1, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryBlock.log2, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryBlock.log3, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryBlock.log4, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryBlock.log5, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryBlock.log6, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryBlock.log7, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryItem.sapling.item(), 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("forester").addValidItem(new ItemStack(ForestryItem.fruits.item(), 1, Defaults.WILDCARD)); + + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.stairs, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.slabs1, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.slabs2, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.slabs3, 1, Defaults.WILDCARD)); + // BackpackManager.definitions.item("builder").addValidItem(new + // ItemStack(ForestryBlock.slabs4, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.fences1, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.fences2, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.planks1, 1, Defaults.WILDCARD)); + BackpackManager.definitions.get("builder").addValidItem( + new ItemStack(ForestryBlock.planks2, 1, Defaults.WILDCARD)); + } + + @Override + protected void registerCrates() { + } + + @Override + protected void registerRecipes() { + + // / Plank recipes + for (int i = 0; i < 4; i++) { + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.planks1, 4, i), + new ItemStack(ForestryBlock.log1, 1, i)); + } + for (int i = 0; i < 4; i++) { + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.planks1, 4, 4 + i), + new ItemStack(ForestryBlock.log2, 1, i)); + } + for (int i = 0; i < 4; i++) { + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.planks1, 4, 8 + i), + new ItemStack(ForestryBlock.log3, 1, i)); + } + for (int i = 0; i < 4; i++) { + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.planks1, 4, 12 + i), + new ItemStack(ForestryBlock.log4, 1, i)); + } + for (int i = 0; i < 4; i++) { + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.planks2, 4, i), + new ItemStack(ForestryBlock.log5, 1, i)); + } + for (int i = 0; i < 4; i++) { + Proxies.common.addShapelessRecipe(new ItemStack(ForestryBlock.planks2, 4, 4 + i), + new ItemStack(ForestryBlock.log6, 1, i)); + } + + // Slab recipes + for (int i = 0; i < 8; i++) { + Proxies.common.addPriorityRecipe(new ItemStack(ForestryBlock.slabs1, 6, i), "###", '#', new ItemStack(ForestryBlock.planks1, 1, i)); + } + for (int i = 0; i < 8; i++) { + Proxies.common.addPriorityRecipe(new ItemStack(ForestryBlock.slabs2, 6, i), "###", '#', new ItemStack(ForestryBlock.planks1, 1, 8 + i)); + } + for (int i = 0; i < 8; i++) { + Proxies.common.addPriorityRecipe(new ItemStack(ForestryBlock.slabs3, 6, i), "###", '#', new ItemStack(ForestryBlock.planks2, 1, i)); + } + + // Fence recipes + for (int i = 0; i < 16; i++) { + Proxies.common.addRecipe(new ItemStack(ForestryBlock.fences1, 4, i), "###", "# #", '#', new ItemStack(ForestryBlock.planks1, 1, i)); + } + for (int i = 0; i < 8; i++) { + Proxies.common.addRecipe(new ItemStack(ForestryBlock.fences2, 4, i), "###", "# #", '#', new ItemStack(ForestryBlock.planks2, 1, i)); + } + + // Treealyzer + RecipeManagers.carpenterManager.addRecipe(100, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 2000), null, ForestryItem.treealyzer.getItemStack(), new Object[] { + "X#X", "X#X", "RDR", + '#', Blocks.glass_pane, + 'X', "ingotCopper", + 'R', Items.redstone, + 'D', Items.diamond }); + + // SQUEEZER RECIPES + RecipeManagers.squeezerManager.addRecipe(20, new ItemStack[] { ForestryItem.fruits.getItemStack(1, EnumFruit.CHERRY.ordinal()) }, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, 5 * GameMode.getGameMode().getIntegerSetting("squeezer.liquid.seed")), ForestryItem.mulch.getItemStack(), 5); + RecipeManagers.squeezerManager.addRecipe(60, new ItemStack[] { ForestryItem.fruits.getItemStack(1, EnumFruit.WALNUT.ordinal()) }, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, 18 * GameMode.getGameMode().getIntegerSetting("squeezer.liquid.seed")), ForestryItem.mulch.getItemStack(), 5); + RecipeManagers.squeezerManager.addRecipe(70, new ItemStack[] { ForestryItem.fruits.getItemStack(1, EnumFruit.CHESTNUT.ordinal()) }, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, 22 * GameMode.getGameMode().getIntegerSetting("squeezer.liquid.seed")), ForestryItem.mulch.getItemStack(), 2); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.fruits.getItemStack(1, EnumFruit.LEMON.ordinal()) }, LiquidHelper.getLiquid(Defaults.LIQUID_JUICE, GameMode.getGameMode().getIntegerSetting("squeezer.liquid.apple") * 2), ForestryItem.mulch.getItemStack(), (int) Math.floor(GameMode.getGameMode().getIntegerSetting("squeezer.mulch.apple") * 0.5f)); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.fruits.getItemStack(1, EnumFruit.PLUM.ordinal()) }, LiquidHelper.getLiquid(Defaults.LIQUID_JUICE, (int) Math.floor(GameMode.getGameMode().getIntegerSetting("squeezer.liquid.apple") * 0.5f)), ForestryItem.mulch.getItemStack(), GameMode.getGameMode().getIntegerSetting("squeezer.mulch.apple") * 3); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.fruits.getItemStack(1, EnumFruit.PAPAYA.ordinal()) }, LiquidHelper.getLiquid(Defaults.LIQUID_JUICE, GameMode.getGameMode().getIntegerSetting("squeezer.liquid.apple") * 3), ForestryItem.mulch.getItemStack(), (int) Math.floor(GameMode.getGameMode().getIntegerSetting("squeezer.mulch.apple") * 0.5f)); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.fruits.getItemStack(1, EnumFruit.DATES.ordinal()) }, LiquidHelper.getLiquid(Defaults.LIQUID_JUICE, (int) Math.floor(GameMode.getGameMode().getIntegerSetting("squeezer.liquid.apple") * 0.25)), ForestryItem.mulch.getItemStack(), (int) Math.floor(GameMode.getGameMode().getIntegerSetting("squeezer.mulch.apple"))); + + RecipeUtil.injectLeveledRecipe(ForestryItem.sapling.getItemStack(), GameMode.getGameMode().getIntegerSetting("fermenter.yield.sapling"), Defaults.LIQUID_BIOMASS); + + // Stairs + for (int i = 0; i < 16; i++) { + WoodType type = WoodType.VALUES[i]; + NBTTagCompound compound = new NBTTagCompound(); + type.saveToCompound(compound); + + ItemStack stairs = new ItemStack(ForestryBlock.stairs, 4, 0); + stairs.setTagCompound(compound); + Proxies.common.addPriorityRecipe(stairs, new Object[] { "# ", "## ", "###", '#', + new ItemStack(ForestryBlock.planks1, 1, i) }); + } + for (int i = 0; i < 8; i++) { + WoodType type = WoodType.VALUES[16 + i]; + NBTTagCompound compound = new NBTTagCompound(); + type.saveToCompound(compound); + + ItemStack stairs = new ItemStack(ForestryBlock.stairs, 4, 0); + stairs.setTagCompound(compound); + Proxies.common.addPriorityRecipe(stairs, new Object[] { "# ", "## ", "###", '#', + new ItemStack(ForestryBlock.planks2, 1, i) }); + } + + // Grafter + Proxies.common.addRecipe(ForestryItem.grafter.getItemStack(), " B", " # ", "# ", 'B', "ingotBronze", '#', Items.stick); + } + + private void createAlleles() { + + // Divisions + IClassification angiosperms = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.DIVISION, "angiosperms", "Angiosperms"); + AlleleManager.alleleRegistry.getClassification("kingdom.plantae").addMemberGroup( + angiosperms); + IClassification pinophyta = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.DIVISION, "pinophyta", "Pinophyta"); + AlleleManager.alleleRegistry.getClassification("kingdom.plantae").addMemberGroup(pinophyta); + IClassification magnoliophyta = AlleleManager.alleleRegistry + .createAndRegisterClassification(EnumClassLevel.DIVISION, "magnoliophyta", + "Magnoliophyta"); + AlleleManager.alleleRegistry.getClassification("kingdom.plantae").addMemberGroup( + magnoliophyta); + + // Classes + IClassification rosids = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.CLASS, "rosids", "Rosids"); + angiosperms.addMemberGroup(rosids); + IClassification asterids = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.CLASS, "asterids", "Asterids"); + angiosperms.addMemberGroup(asterids); + IClassification pinopsida = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.CLASS, "pinopsida", "Pinopsida"); + pinophyta.addMemberGroup(pinopsida); + IClassification magnoliopsida = AlleleManager.alleleRegistry + .createAndRegisterClassification(EnumClassLevel.CLASS, "magnoliopsida", + "Magnoliopsida"); + pinophyta.addMemberGroup(magnoliopsida); + + // Orders + IClassification fabales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "fabales", "Fabales"); + rosids.addMemberGroup(fabales); + IClassification rosales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "rosales", "Rosales"); + rosids.addMemberGroup(rosales); + IClassification fagales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "fagales", "Fagales"); + rosids.addMemberGroup(fagales); + IClassification malvales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "malvales", "Malvales"); + rosids.addMemberGroup(malvales); + IClassification malpighiales = AlleleManager.alleleRegistry + .createAndRegisterClassification(EnumClassLevel.ORDER, "malpighiales", + "Malpighiales"); + rosids.addMemberGroup(malpighiales); + + IClassification ericales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "ericales", "Ericales"); + asterids.addMemberGroup(ericales); + IClassification lamiales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "lamiales", "Lamiales"); + asterids.addMemberGroup(lamiales); + + IClassification pinales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "pinales", "Pinales"); + pinopsida.addMemberGroup(pinales); + + IClassification laurales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "laurales", "Laurales"); + rosids.addMemberGroup(laurales); + IClassification sapindales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "sapindales", "Sapindales"); + rosids.addMemberGroup(sapindales); + IClassification brassicales = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.ORDER, "brassicales", "Brassicales"); + rosids.addMemberGroup(brassicales); + + // Families + IClassification betulaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "betulaceae", "Betulaceae"); + fagales.addMemberGroup(betulaceae); + IClassification fagaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "fagaceae", "Fagaceae"); + fagales.addMemberGroup(fagaceae); + IClassification juglandaceae = AlleleManager.alleleRegistry + .createAndRegisterClassification(EnumClassLevel.FAMILY, "juglandaceae", + "Juglandaceae"); + fagales.addMemberGroup(juglandaceae); + + IClassification malvaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "malvaceae", "Malvaceae"); + malvales.addMemberGroup(malvaceae); + IClassification dipterocarpaceae = AlleleManager.alleleRegistry + .createAndRegisterClassification(EnumClassLevel.FAMILY, "dipterocarpaceae", + "Dipterocarpaceae"); + malvales.addMemberGroup(dipterocarpaceae); + + IClassification pinaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "pinaceae", "Pinaceae"); + pinales.addMemberGroup(pinaceae); + IClassification cupressaceae = AlleleManager.alleleRegistry + .createAndRegisterClassification(EnumClassLevel.FAMILY, "cupressaceae", + "Cupressaceae"); + pinales.addMemberGroup(cupressaceae); + + IClassification lamiaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "lamiaceae", "Lamiaceae"); + lamiales.addMemberGroup(lamiaceae); + + IClassification ebenaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "ebenaceae", "Ebenaceae"); + ericales.addMemberGroup(ebenaceae); + + IClassification fabaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "fabaceae", "Fabaceae"); + ericales.addMemberGroup(fabaceae); + + IClassification rosaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "rosaceae", "Rosaceae"); + rosales.addMemberGroup(rosaceae); + + IClassification salicaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "salicaceae", "Salicaceae"); + malpighiales.addMemberGroup(salicaceae); + + IClassification lauraceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "lauraceae", "Lauraceae"); + malpighiales.addMemberGroup(lauraceae); + + IClassification rutaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "rutaceae", "Rutaceae"); + sapindales.addMemberGroup(rutaceae); + IClassification sapindaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "sapindaceae", "Sapindaceae"); + sapindales.addMemberGroup(sapindaceae); + + IClassification caricaceae = AlleleManager.alleleRegistry.createAndRegisterClassification( + EnumClassLevel.FAMILY, "caricaceae", "Caricaceae"); + brassicales.addMemberGroup(caricaceae); + + // Genii + IClassification quercus = new BranchTrees("quercus", "Quercus"); + fagaceae.addMemberGroup(quercus); + IClassification castanea = new BranchTrees("castanea", "Castanea"); + fagaceae.addMemberGroup(castanea); + + IClassification betula = new BranchTrees("betula", "Betula"); + betulaceae.addMemberGroup(betula); + + IClassification tilia = new BranchTrees("tilia", "Tilia"); + malvaceae.addMemberGroup(tilia); + IClassification ceiba = new BranchTrees("ceiba", "Ceiba"); + malvaceae.addMemberGroup(ceiba); + IClassification adansonia = new BranchTrees("adansonia", "Adansonia"); + malvaceae.addMemberGroup(adansonia); + + IClassification picea = new BranchTrees("picea", "Picea"); + pinaceae.addMemberGroup(picea); + IClassification pinus = new BranchTrees("pinus", "Pinus"); + pinaceae.addMemberGroup(pinus); + IClassification larix = new BranchTrees("larix", "Larix"); + pinaceae.addMemberGroup(larix); + + IClassification juglans = new BranchTrees("juglans", "Juglans"); + juglandaceae.addMemberGroup(juglans); + + IClassification sequoia = new BranchTrees("sequoia", "Sequoia"); + cupressaceae.addMemberGroup(sequoia); + IClassification sequoiadendron = new BranchTrees("sequoiadendron", "Sequoiadendron"); + cupressaceae.addMemberGroup(sequoiadendron); + + IClassification tectona = new BranchTrees("tectona", "Tectona"); + lamiaceae.addMemberGroup(tectona); + + IClassification diospyros = new BranchTrees("ebony", "Diospyros"); + ebenaceae.addMemberGroup(diospyros); + + IClassification shorea = new BranchTrees("mahogany", "Shorea"); + dipterocarpaceae.addMemberGroup(shorea); + + IClassification acacia = new BranchTrees("acacia", "Acacia"); + fabaceae.addMemberGroup(acacia); + IClassification millettia = new BranchTrees("millettia", "Millettia"); + fabaceae.addMemberGroup(millettia); + + IClassification ochroma = new BranchTrees("ochroma", "Ochroma"); + malvaceae.addMemberGroup(ochroma); + + IClassification prunus = new BranchTrees("prunus", "Prunus"); + rosaceae.addMemberGroup(prunus); + + IClassification salix = new BranchTrees("salix", "Salix"); + salicaceae.addMemberGroup(salix); + + IClassification chlorocardium = new BranchTrees("chlorocardium", "Chlorocardium"); + salicaceae.addMemberGroup(chlorocardium); + + IClassification talipariti = new BranchTrees("talipariti", "Talipariti"); + malvaceae.addMemberGroup(talipariti); + + IClassification populus = new BranchTrees("populus", "Populus"); + salicaceae.addMemberGroup(populus); + + IClassification citrus = new BranchTrees("citrus", "Citrus"); + rutaceae.addMemberGroup(citrus); + IClassification acer = new BranchTrees("acer", "Acer"); + sapindaceae.addMemberGroup(acer); + + IClassification tropical = new BranchTrees("Tropical", ""); + + IClassification carica = new BranchTrees("carica", "Carica"); + + IFruitFamily prunes = new FruitFamily("prunes", "Prunus domestica"); + IFruitFamily pomes = new FruitFamily("pomes", "Pomum"); + IFruitFamily jungle = new FruitFamily("jungle", "Tropicus"); + IFruitFamily nux = new FruitFamily("nuts", "Nux"); + + // Deciduous + Allele.treeOak = new AlleleTreeSpecies("treeOak", false, "Apple Oak", quercus, "robur", + proxy.getFoliageColorBasic(), WorldGenOak.class, new ItemStack(Blocks.log, 1, 0)).addFruitFamily(pomes) + .setVanillaMap(0).setIsSecret(); + Allele.treeBirch = new AlleleTreeSpecies("treeBirch", false, "Silver Birch", betula, + "pendula", proxy.getFoliageColorBirch(), 0xb0c648, WorldGenBirch.class, new ItemStack(Blocks.log, 1, 2)) + .setVanillaMap(2).setIsSecret(); + Allele.treeLime = new AlleleTreeSpecies("treeLime", true, "Silver Lime", tilia, + "tomentosa", 0x5ea107, WorldGenLime.class, new ItemStack(ForestryBlock.log1, 1, 3)).addFruitFamily(nux) + .addFruitFamily(prunes).addFruitFamily(pomes); + + // Nucifera + Allele.treeWalnut = new AlleleTreeSpecies("treeWalnut", true, "Common Walnut", juglans, + "regia", 0x798c55, 0xb0c648, WorldGenWalnut.class, new ItemStack(ForestryBlock.log4, 1, 1)).addFruitFamily(nux) + .addFruitFamily(prunes).addFruitFamily(pomes).setGirth(2); + Allele.treeChestnut = new AlleleTreeSpecies("treeChestnut", true, "Sweet Chestnut", + castanea, "sativa", 0x5ea107, 0xb0c648, WorldGenChestnut.class, new ItemStack(ForestryBlock.log2, 1, 0)).addFruitFamily(nux) + .addFruitFamily(prunes).addFruitFamily(pomes).setGirth(2); + + // Prunus & Citrus + // fructifer, annifer, bifer, aurifer = bearing fruit, + // bearing fruit year round, bearing fruit twice a year, bearing golden + // fruit + Allele.treeCherry = new AlleleTreeSpecies("treeCherry", true, "Hill Cherry", prunus, + "serrulata", 0xe691da, 0xe63e59, WorldGenCherry.class, new ItemStack(ForestryBlock.log4, 1, 3)).addFruitFamily(prunes) + .addFruitFamily(pomes); + Allele.treeLemon = new AlleleTreeSpecies("treeLemon", true, "Lemon", citrus, "limon", + 0x88af54, 0xa3b850, WorldGenLemon.class, new ItemStack(ForestryBlock.log6, 1, 3)).addFruitFamily(pomes).addFruitFamily( + prunes); + Allele.treePlum = new AlleleTreeSpecies("treePlum", true, "Plum", prunus, "domestica", + 0x589246, 0xa3b850, WorldGenPlum.class, new ItemStack(ForestryBlock.log6, 1, 1)).addFruitFamily(pomes) + .addFruitFamily(prunes); + + // Maples + Allele.treeMaple = new AlleleTreeSpecies("treeMaple", true, "Sugar Maple", acer, + "saccharum", 0xd4f425, 0x619a3c, WorldGenMaple.class, new ItemStack(ForestryBlock.log6, 1, 2)).addFruitFamily(prunes) + .addFruitFamily(pomes).setLeafIndices("maple"); + + Allele.treeSpruce = new AlleleTreeSpecies("treeSpruce", false, "Red Spruce", picea, + "abies", proxy.getFoliageColorPine(), 0x539d12, WorldGenSpruce.class, new ItemStack(Blocks.log, 1, 1)) + .setLeafIndices("conifers").setVanillaMap(1).setIsSecret(); + Allele.treeLarch = new AlleleTreeSpecies("treeLarch", true, "Mundane Larch", larix, + "decidua", 0x698f90, 0x569896, WorldGenLarch.class, new ItemStack(ForestryBlock.log1, 1, 0)).setLeafIndices("conifers"); + Allele.treePine = new AlleleTreeSpecies("treePine", true, "Bull Pine", pinus, "sabiniana", + 0xfeff8f, 0xffd98f, WorldGenPine.class, new ItemStack(ForestryBlock.log6, 1, 0)).setLeafIndices("conifers"); + + Allele.treeSequioa = new AlleleTreeSpecies("treeSequioa", false, "Coast Sequoia", sequoia, + "sempervirens", 0x418e71, 0x569896, WorldGenSequoia.class, new ItemStack(ForestryBlock.log2, 1, 3)).setLeafIndices( + "conifers").setGirth(3); + Allele.treeGiganteum = new AlleleTreeSpecies("treeGigant", false, "Giant Sequoia", + sequoiadendron, "giganteum", 0x738434, WorldGenGiganteum.class, new ItemStack(ForestryBlock.log2, 1, 3)).setLeafIndices( + "conifers").setGirth(4); + + // Jungle + Allele.treeJungle = new AlleleTreeSpecies("treeJungle", false, "Jungle", tropical, + "tectona", proxy.getFoliageColorBasic(), 0x539d12, WorldGenJungle.class, new ItemStack(Blocks.log, 1, 3)) + .addFruitFamily(jungle).setLeafIndices("jungle").setVanillaMap(3).setIsSecret(); + Allele.treeTeak = new AlleleTreeSpecies("treeTeak", true, "Teak", tectona, "grandis", + 0xfeff8f, 0xffd98f, WorldGenTeak.class, new ItemStack(ForestryBlock.log1, 1, 3)).addFruitFamily(jungle).setLeafIndices( + "jungle"); + Allele.treeKapok = new AlleleTreeSpecies("treeKapok", true, "Kapok", ceiba, "pentandra", + 0x89987b, 0x89aa9e, WorldGenKapok.class, new ItemStack(ForestryBlock.log3, 1, 0)).addFruitFamily(jungle) + .addFruitFamily(prunes).setLeafIndices("jungle"); + + // Ebony + Allele.treeEbony = new AlleleTreeSpecies("treeEbony", true, "Myrtle Ebony", diospyros, + "pentamera", 0xa2d24a, 0xc4d24a, WorldGenEbony.class, new ItemStack(ForestryBlock.log3, 1, 1)).addFruitFamily(jungle) + .addFruitFamily(prunes).setGirth(3).setLeafIndices("jungle"); + + // Diospyros mespiliformis, the Jackalberry (also known as African Ebony + // The Gaub Tree, Malabar ebony, Black-and-white Ebony or Pale Moon + // Ebony (Diospyros malabarica) + // Diospyros fasciculosa, is a rainforest tree in the Ebony family. + // Usually seen as a medium sized tree, but it may grow to 30 metres + // tall. + // http://en.wikipedia.org/wiki/Diospyros_ebenum + // http://en.wikipedia.org/wiki/Diospyros_crassiflora - + // "The wood this particular tree produces is believed to be the blackest of all timber-producing Diospyros species" + // Coromandel Ebony or East Indian Ebony (Diospyros melanoxylon) - + // " locally it is known as temburini or by its Hindi name tendu. In Orissa and Jharkhand it known as kendu." + + // Mahogany + Allele.treeMahogany = new AlleleTreeSpecies("treeMahogony", true, "Yellow Meranti", shorea, + "gibbosa", 0x8ab154, 0xa9b154, WorldGenMahogany.class, new ItemStack(ForestryBlock.log3, 1, 2)).addFruitFamily(jungle) + .setGirth(2).setLeafIndices("jungle"); + + // 80+ meters tall: + // Shorea argentifolia (also called Dark Red Meranti) + // Shorea gibbosa (also called Yellow Meranti) + // Shorea smithiana (also called Light Red Meranti) + // Shorea superba + + // Malva + Allele.treeAcacia = new AlleleTreeSpecies("treeAcacia", true, "Desert Acacia", acacia, + "erioloba", 0x616101, 0xb3b302, WorldGenAcacia.class, new ItemStack(ForestryBlock.log1, 1, 2)).addFruitFamily(jungle) + .addFruitFamily(nux); + Allele.treeBalsa = new AlleleTreeSpecies("treeBalsa", true, "Balsa", ochroma, "pyramidale", + 0x59ac00, 0xfeff8f, WorldGenBalsa.class, new ItemStack(ForestryBlock.log3, 1, 3)).addFruitFamily(jungle).addFruitFamily(nux); + Allele.treeWenge = new AlleleTreeSpecies("treeWenge", true, "Wenge", millettia, + "laurentii", 0xada157, 0xad8a57, WorldGenWenge.class, new ItemStack(ForestryBlock.log2, 1, 1)).addFruitFamily(jungle) + .addFruitFamily(nux).setGirth(2); + Allele.treeBaobab = new AlleleTreeSpecies("treeBaobab", true, "Grandidier's Baobab", + adansonia, "digitata", 0xfeff8f, 0xffd98f, WorldGenBaobab.class, new ItemStack(ForestryBlock.log2, 1, 2)) + .addFruitFamily(jungle).addFruitFamily(nux).setGirth(3); + Allele.treeMahoe = new AlleleTreeSpecies("treeMahoe", true, "Blue Mahoe", talipariti, + "elatum", 0xa0ba1b, 0x79a175, WorldGenMahoe.class, new ItemStack(ForestryBlock.log5, 1, 0)).addFruitFamily(jungle) + .addFruitFamily(pomes).addFruitFamily(prunes); + + // Willows + Allele.treeWillow = new AlleleTreeSpecies("treeWillow", true, "White Willow", salix, + "alba", 0xa3b8a5, 0xa3b850, WorldGenWillow.class, new ItemStack(ForestryBlock.log4, 1, 0)).addFruitFamily(nux) + .addFruitFamily(prunes).addFruitFamily(pomes).setLeafIndices("willow"); + + // Lauraceae + Allele.treeSipiri = new AlleleTreeSpecies("treeSipiri", true, "Sipiri", chlorocardium, + "rodiei", 0x678911, 0x79a175, WorldGenGreenheart.class, new ItemStack(ForestryBlock.log3, 1, 2)).addFruitFamily(jungle); + + // Unclassified + Allele.treePapaya = new AlleleTreeSpecies("treePapaya", true, "Papaya", carica, "papaya", + 0x6d9f58, 0x9ee67f, WorldGenPapaya.class, new ItemStack(ForestryBlock.log5, 1, 3)).addFruitFamily(jungle) + .addFruitFamily(nux).setLeafIndices("palm"); + Allele.treeDate = new AlleleTreeSpecies("treeDate", true, "Date Palm", null, "dactylifera", + 0xcbcd79, 0xf0f38f, WorldGenDate.class, new ItemStack(ForestryBlock.log4, 1, 2)).addFruitFamily(jungle).addFruitFamily(nux) + .setLeafIndices("palm"); + + Allele.treePoplar = new AlleleTreeSpecies("treePoplar", true, "White Poplar", populus, + "alba", 0xa3b8a5, 0x539d12, WorldGenPoplar.class, new ItemStack(ForestryBlock.log5, 1, 1)).addFruitFamily(pomes) + .addFruitFamily(prunes); + + // FRUITS + Allele.fruitNone = new AlleleFruit("fruitNone", new FruitProviderNone("none", null)); + Allele.fruitApple = new AlleleFruit("fruitApple", new FruitProviderRandom("apple", pomes, new ItemStack(Items.apple), 1.0f).setColour(0xff2e2e).setOverlay("pomes")); + Allele.fruitCocoa = new AlleleFruit("fruitCocoa", new FruitProviderPod("cocoa", jungle, EnumPodType.COCOA)); + // .setColours(0xecdca5, 0xc4d24a), true); + Allele.fruitChestnut = new AlleleFruit("fruitChestnut", new FruitProviderRipening("chestnut", nux, ForestryItem.fruits.getItemStack(1, EnumFruit.CHESTNUT.ordinal()), 1.0f).setRipeningPeriod(6).setColours(0x7f333d, 0xc4d24a).setOverlay("nuts"), true); + Allele.fruitWalnut = new AlleleFruit("fruitWalnut", new FruitProviderRipening("walnut", nux, ForestryItem.fruits.getItemStack(1, EnumFruit.WALNUT.ordinal()), 1.0f).setRipeningPeriod(8).setColours(0xfba248, 0xc4d24a).setOverlay("nuts"), true); + Allele.fruitCherry = new AlleleFruit("fruitCherry", new FruitProviderRipening("cherry", prunes, ForestryItem.fruits.getItemStack(1, EnumFruit.CHERRY.ordinal()), 1.0f).setColours(0xff2e2e, 0xc4d24a).setOverlay("berries"), true); + Allele.fruitDates = new AlleleFruit("fruitDates", new FruitProviderPod("dates", jungle, EnumPodType.DATES, ForestryItem.fruits.getItemStack(4, EnumFruit.DATES.ordinal()))); + Allele.fruitPapaya = new AlleleFruit("fruitPapaya", new FruitProviderPod("papaya", jungle, EnumPodType.PAPAYA, ForestryItem.fruits.getItemStack(1, EnumFruit.PAPAYA.ordinal()))); + // Allele.fruitCoconut = new AlleleFruit("fruitCoconut", new + // FruitProviderPod("coconut", jungle, EnumPodType.COCONUT, new + // ItemStack[] { new ItemStack( + // ForestryItem.fruits, 1, EnumFruit.COCONUT.ordinal()) })); + Allele.fruitLemon = new AlleleFruit("fruitLemon", new FruitProviderRipening("lemon", prunes, ForestryItem.fruits.getItemStack(1, EnumFruit.LEMON.ordinal()), 1.0f).setColours(0xeeee00, 0x99ff00).setOverlay("citrus"), true); + Allele.fruitPlum = new AlleleFruit("fruitPlum", new FruitProviderRipening("plum", prunes, ForestryItem.fruits.getItemStack(1, EnumFruit.PLUM.ordinal()), 1.0f).setColours(0x663446, 0xeeff1a).setOverlay("plums"), true); + + // / TREES // GROWTH PROVIDER 1350 - 1399 + Allele.growthLightlevel = new AlleleGrowth("growthLightlevel", new GrowthProvider()); + Allele.growthAcacia = new AlleleGrowth("growthAcacia", new GrowthProvider()); + Allele.growthTropical = new AlleleGrowth("growthTropical", new GrowthProviderTropical()); + + // / TREES // EFFECTS 1900 - 1999 + Allele.leavesNone = new AlleleLeafEffectNone("leavesNone"); + + } + + private void registerTemplates() { + treeInterface.registerTemplate(TreeTemplates.getOakTemplate()); + treeInterface.registerTemplate(TreeTemplates.getBirchTemplate()); + treeInterface.registerTemplate(TreeTemplates.getSpruceTemplate()); + treeInterface.registerTemplate(TreeTemplates.getJungleTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getLimeTemplate()); + treeInterface.registerTemplate(TreeTemplates.getCherryTemplate()); + treeInterface.registerTemplate(TreeTemplates.getChestnutTemplate()); + treeInterface.registerTemplate(TreeTemplates.getWalnutTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getLarchTemplate()); + treeInterface.registerTemplate(TreeTemplates.getPineTemplate()); + treeInterface.registerTemplate(TreeTemplates.getSequoiaTemplate()); + treeInterface.registerTemplate(TreeTemplates.getGiganteumTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getBalsaTemplate()); + treeInterface.registerTemplate(TreeTemplates.getAcaciaTemplate()); + treeInterface.registerTemplate(TreeTemplates.getWengeTemplate()); + treeInterface.registerTemplate(TreeTemplates.getBaobabTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getTeakTemplate()); + treeInterface.registerTemplate(TreeTemplates.getKapokTemplate()); + treeInterface.registerTemplate(TreeTemplates.getEbonyTemplate()); + treeInterface.registerTemplate(TreeTemplates.getMahoganyTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getWillowTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getSipiriTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getMahoeTemplate()); + treeInterface.registerTemplate(TreeTemplates.getPoplarTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getLemonTemplate()); + treeInterface.registerTemplate(TreeTemplates.getPlumTemplate()); + treeInterface.registerTemplate(TreeTemplates.getMapleTemplate()); + + treeInterface.registerTemplate(TreeTemplates.getPapayaTemplate()); + treeInterface.registerTemplate(TreeTemplates.getDateTemplate()); + } + + private void registerErsatzGenomes() { + AlleleManager.ersatzSpecimen.put(new ItemStack(Blocks.leaves, 1, 0), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getOakTemplate()))); + AlleleManager.ersatzSpecimen.put(new ItemStack(Blocks.leaves, 1, 1), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getSpruceTemplate()))); + AlleleManager.ersatzSpecimen.put(new ItemStack(Blocks.leaves, 1, 2), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getBirchTemplate()))); + AlleleManager.ersatzSpecimen.put(new ItemStack(Blocks.leaves, 1, 3), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getJungleTemplate()))); + + AlleleManager.ersatzSaplings.put(new ItemStack(Blocks.sapling, 1, 0), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getOakTemplate()))); + AlleleManager.ersatzSaplings.put(new ItemStack(Blocks.sapling, 1, 1), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getSpruceTemplate()))); + AlleleManager.ersatzSaplings.put(new ItemStack(Blocks.sapling, 1, 2), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getBirchTemplate()))); + AlleleManager.ersatzSaplings.put(new ItemStack(Blocks.sapling, 1, 3), new Tree( + TreeTemplates.templateAsGenome(TreeTemplates.getJungleTemplate()))); + } + + private void createMutations() { + + // Decidious + TreeTemplates.limeA = new TreeMutation(Allele.treeBirch, Allele.treeOak, + TreeTemplates.getLimeTemplate(), 15); + TreeTemplates.mapleA = new TreeMutation(Allele.treeLime, Allele.treeLarch, + TreeTemplates.getMapleTemplate(), 5); + + // Fructifera + TreeTemplates.cherryA = new TreeMutation(Allele.treeLime, Allele.treeOak, + TreeTemplates.getCherryTemplate(), 10); + TreeTemplates.cherryB = new TreeMutation(Allele.treeLime, Allele.treeBirch, + TreeTemplates.getCherryTemplate(), 10); + TreeTemplates.lemonA = new TreeMutation(Allele.treeLime, Allele.treeCherry, + TreeTemplates.getLemonTemplate(), 5); + TreeTemplates.plumA = new TreeMutation(Allele.treeLemon, Allele.treeCherry, + TreeTemplates.getPlumTemplate(), 5); + + // Nucifera + TreeTemplates.walnutA = new TreeMutation(Allele.treeLime, Allele.treeCherry, + TreeTemplates.getWalnutTemplate(), 10); + TreeTemplates.chestnutA = new TreeMutation(Allele.treeWalnut, Allele.treeLime, + TreeTemplates.getChestnutTemplate(), 10); + TreeTemplates.chestnutB = new TreeMutation(Allele.treeWalnut, Allele.treeCherry, + TreeTemplates.getChestnutTemplate(), 10); + + // Conifera + TreeTemplates.larchA = new TreeMutation(Allele.treeSpruce, Allele.treeBirch, + TreeTemplates.getLarchTemplate(), 10); + TreeTemplates.larchB = new TreeMutation(Allele.treeSpruce, Allele.treeOak, + TreeTemplates.getLarchTemplate(), 10); + TreeTemplates.pineA = new TreeMutation(Allele.treeSpruce, Allele.treeLarch, + TreeTemplates.getPineTemplate(), 10); + TreeTemplates.sequoiaA = new TreeMutation(Allele.treeLarch, Allele.treePine, + TreeTemplates.getSequoiaTemplate(), 5); + + // Tropical + TreeTemplates.teakA = new TreeMutation(Allele.treeLime, Allele.treeJungle, + TreeTemplates.getTeakTemplate(), 10); + TreeTemplates.kapokA = new TreeMutation(Allele.treeJungle, Allele.treeTeak, + TreeTemplates.getKapokTemplate(), 10); + TreeTemplates.ebonyA = new TreeMutation(Allele.treeKapok, Allele.treeTeak, + TreeTemplates.getEbonyTemplate(), 10); + TreeTemplates.mahoganyA = new TreeMutation(Allele.treeKapok, Allele.treeEbony, + TreeTemplates.getMahoganyTemplate(), 10); + + TreeTemplates.papayaA = new TreeMutation(Allele.treeJungle, Allele.treeCherry, + TreeTemplates.getPapayaTemplate(), 5); + TreeTemplates.dateA = new TreeMutation(Allele.treeJungle, Allele.treePapaya, + TreeTemplates.getDateTemplate(), 5); + + // Malva + TreeTemplates.balsaA = new TreeMutation(Allele.treeTeak, Allele.treeLime, + TreeTemplates.getBalsaTemplate(), 10); + TreeTemplates.acaciaA = new TreeMutation(Allele.treeTeak, Allele.treeBalsa, + TreeTemplates.getAcaciaTemplate(), 10); + TreeTemplates.wengeA = new TreeMutation(Allele.treeAcacia, Allele.treeBalsa, + TreeTemplates.getWengeTemplate(), 10); + TreeTemplates.baobabA = new TreeMutation(Allele.treeBalsa, Allele.treeWenge, + TreeTemplates.getBaobabTemplate(), 10); + TreeTemplates.mahoeA = new TreeMutation(Allele.treeBirch, Allele.treeAcacia, + TreeTemplates.getMahoeTemplate(), 5); + + TreeTemplates.willowA = new TreeMutation(Allele.treeOak, Allele.treeBirch, + TreeTemplates.getWillowTemplate(), 10).setTemperatureRainfall(0.7f, 1.5f, 0.9f, + 2.0f); + TreeTemplates.willowB = new TreeMutation(Allele.treeOak, Allele.treeLime, + TreeTemplates.getWillowTemplate(), 10).setTemperatureRainfall(0.7f, 1.5f, 0.9f, + 2.0f); + TreeTemplates.willowC = new TreeMutation(Allele.treeLime, Allele.treeBirch, + TreeTemplates.getWillowTemplate(), 10).setTemperatureRainfall(0.7f, 1.5f, 0.9f, + 2.0f); + + TreeTemplates.sipiriA = new TreeMutation(Allele.treeKapok, Allele.treeMahogany, + TreeTemplates.getSipiriTemplate(), 10).setTemperatureRainfall(0.9f, 1.9f, 0.9f, + 2.0f); + + TreeTemplates.poplarA = new TreeMutation(Allele.treeBirch, Allele.treeWillow, + TreeTemplates.getPoplarTemplate(), 5); + TreeTemplates.poplarB = new TreeMutation(Allele.treeOak, Allele.treeWillow, + TreeTemplates.getPoplarTemplate(), 5); + TreeTemplates.poplarB = new TreeMutation(Allele.treeLime, Allele.treeWillow, + TreeTemplates.getPoplarTemplate(), 5); + + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerArboriculture(); + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } + + @Override + public ICommand[] getConsoleCommands() { + return new ICommand[] { new CommandSpawnTree(), new CommandSpawnForest(), + new CommandTreekeepingMode() }; + } + + @Override + public int getBurnTime(ItemStack fuel) { + if (ForestryItem.sapling.isItemEqual(fuel)) + return 100; + + return 0; + } + + @Override + public IPacketHandler getPacketHandler() { + return new PacketHandlerArboriculture(); + } + + @Override + public boolean processIMCMessage(IMCMessage message) { + if (message.key.equals("add-fence-block") && message.isStringMessage()) { + Block block = GameData.blockRegistry.getObject(message.getStringValue()); + + if (block == null || block == Blocks.air) { + Proxies.log.warning("invalid add-fence-block IMC: can't resolve block name %s.", message.getStringValue()); + } else { + validFences.add(block); + } + } + return super.processIMCMessage(message); + } + + private void registerDungeonLoot() { + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(ForestryItem.grafter.getItemStack(), 1, 1, 8)); + + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getOakTemplate(), EnumGermlingType.SAPLING), 2, 3, 6)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getSpruceTemplate(), EnumGermlingType.SAPLING), 2, 3, 6)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getBirchTemplate(), EnumGermlingType.SAPLING), 2, 3, 6)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getLarchTemplate(), EnumGermlingType.SAPLING), 1, 2, 4)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getLimeTemplate(), EnumGermlingType.SAPLING), 1, 2, 4)); + + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getOakTemplate(), EnumGermlingType.POLLEN), 2, 3, 4)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getSpruceTemplate(), EnumGermlingType.POLLEN), 2, 3, 4)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getBirchTemplate(), EnumGermlingType.POLLEN), 2, 3, 4)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getLarchTemplate(), EnumGermlingType.POLLEN), 1, 2, 3)); + ChestGenHooks.addItem(Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST, new WeightedRandomChestContent(this.getTreeItemFromTemplate(TreeTemplates.getLimeTemplate(), EnumGermlingType.POLLEN), 1, 2, 3)); + } + + private ItemStack getTreeItemFromTemplate(IAllele[] template, EnumGermlingType type) { + ITree tree = new Tree(PluginArboriculture.treeInterface.templateAsGenome(template)); + ItemStack treeItem; + switch (type) { + default: + case POLLEN: + treeItem = ForestryItem.pollenFertile.getItemStack(); + break; + case SAPLING: + treeItem = ForestryItem.sapling.getItemStack(); + } + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + tree.writeToNBT(nbtTagCompound); + treeItem.setTagCompound(nbtTagCompound); + return treeItem; + } +} diff --git a/forestry_common/core/forestry/Forestry.java b/forestry_common/core/forestry/Forestry.java new file mode 100755 index 000000000..5a80b8c35 --- /dev/null +++ b/forestry_common/core/forestry/Forestry.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry; + +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.Mod.EventHandler; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLInterModComms.IMCEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.event.FMLServerStartingEvent; + +import forestry.api.fuels.EngineBronzeFuel; +import forestry.api.fuels.EngineCopperFuel; +import forestry.api.fuels.FermenterFuel; +import forestry.api.fuels.FuelManager; +import forestry.api.fuels.MoistenerFuel; +import forestry.api.fuels.RainSubstrate; +import forestry.core.ForestryCore; +import forestry.core.config.Defaults; +import forestry.core.config.Version; +import forestry.core.network.PacketHandler; +import forestry.core.utils.FluidMap; +import forestry.core.utils.ItemStackMap; + +/** + * Forestry Minecraft Mod + * + * @author SirSengir + */ +@Mod( + modid = Defaults.MOD, + name = "Forestry", + version = Version.VERSION, + dependencies = "" + + "after:Buildcraft|Core;" + + "after:ExtrabiomesXL;" + + "after:BiomesOPlenty;" + + "after:IC2") +//, certificateFingerprint = Version.FINGERPRINT) +public class Forestry { + + @Mod.Instance(Defaults.MOD) + public static Forestry instance; + + public Forestry() { + FuelManager.fermenterFuel = new ItemStackMap(); + FuelManager.moistenerResource = new ItemStackMap(); + FuelManager.rainSubstrate = new ItemStackMap(); + FuelManager.bronzeEngineFuel = new FluidMap(); + FuelManager.copperEngineFuel = new ItemStackMap(); + } + @SidedProxy(clientSide = "forestry.core.ForestryClient", serverSide = "forestry.core.ForestryCore") + public static ForestryCore core = new ForestryCore(); + public static PacketHandler packetHandler; + + @EventHandler + public void preInit(FMLPreInitializationEvent event) { + packetHandler = new PacketHandler(); + + core.preInit(event.getSourceFile(), this); + } + + @EventHandler + public void init(FMLInitializationEvent event) { + core.init(this); + } + + @EventHandler + public void postInit(FMLPostInitializationEvent event) { + core.postInit(); + } + + @EventHandler + public void serverStarting(FMLServerStartingEvent event) { + core.serverStarting(event.getServer()); + } + + /*@EventHandler + public void fingerprintWarning(FMLFingerprintViolationEvent event) { + Proxies.log.info("Fingerprint of the mod jar is invalid. The jar file was tampered with."); + FMLInterModComms.sendMessage("Railcraft", "securityViolation", "Fingerprint of jar file did not match."); + FMLInterModComms.sendMessage("Thaumcraft", "securityViolation", "Fingerprint of jar file did not match."); + FMLInterModComms.sendMessage("IC2", "securityViolation", "Fingerprint of jar file did not match."); + }*/ + @EventHandler + public void processIMCMessages(IMCEvent event) { + core.processIMCMessages(event.getMessages()); + } +} diff --git a/forestry_common/core/forestry/api/apiculture/BeeManager.java b/forestry_common/core/forestry/api/apiculture/BeeManager.java new file mode 100755 index 000000000..7b65c0451 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/BeeManager.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IMutation; +/** + * + * Some miscellaneous lists and settings for bees. + * + * @author SirSengir + */ +public class BeeManager { + + /** + * Get your own reference to this via AlleleManager.alleleRegistry.getSpeciesRoot("rootBees") and save it somewhere. + */ + @Deprecated + public static IBeeRoot beeInterface; + + /** + * Species templates for bees that can drop from hives. + * + * 0 - Forest 1 - Meadows 2 - Desert 3 - Jungle 4 - End 5 - Snow 6 - Swamp + * + * see {@link IMutation} for template format + */ + public static ArrayList[] hiveDrops; + + /** + * 0 - Common Village Bees 1 - Uncommon Village Bees (20 % of spawns) + */ + public static ArrayList[] villageBees; + + /** + * List of items that can induce swarming. Integer denotes x in 1000 chance. + */ + public static HashMap inducers = new HashMap(); +} diff --git a/forestry_common/core/forestry/api/apiculture/EnumBeeChromosome.java b/forestry_common/core/forestry/api/apiculture/EnumBeeChromosome.java new file mode 100755 index 000000000..f1d3031e4 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/EnumBeeChromosome.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleArea; +import forestry.api.genetics.IAlleleBoolean; +import forestry.api.genetics.IAlleleFloat; +import forestry.api.genetics.IAlleleFlowers; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IAlleleTolerance; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.ISpeciesRoot; + +/** + * Enum representing the order of chromosomes in a bee's genome and what they control. + * + * @author SirSengir + */ +public enum EnumBeeChromosome implements IChromosomeType { + /** + * Species of the bee. Alleles here must implement {@link IAlleleBeeSpecies}. + */ + SPECIES(IAlleleBeeSpecies.class), + /** + * (Production) Speed of the bee. + */ + SPEED(IAlleleFloat.class), + /** + * Lifespan of the bee. + */ + LIFESPAN(IAlleleInteger.class), + /** + * Fertility of the bee. Determines number of offspring. + */ + FERTILITY(IAlleleInteger.class), + /** + * Temperature difference to its native supported one the bee can tolerate. + */ + TEMPERATURE_TOLERANCE(IAlleleTolerance.class), + /** + * Slightly incorrectly named. If true, a naturally dirunal bee can work during the night. If true, a naturally nocturnal bee can work during the day. + */ + NOCTURNAL(IAlleleBoolean.class), + /** + * Not used / superseded by fixed values for the species. Probably going to be replaced with a boolean for FIRE_RESIST. + */ + @Deprecated + HUMIDITY(IAllele.class), + /** + * Humidity difference to its native supported one the bee can tolerate. + */ + HUMIDITY_TOLERANCE(IAlleleTolerance.class), + /** + * If true the bee can work during rain. + */ + TOLERANT_FLYER(IAlleleBoolean.class), + /** + * If true, the bee can work without a clear view of the sky. + */ + CAVE_DWELLING(IAlleleBoolean.class), + /** + * Contains the supported flower provider. + */ + FLOWER_PROVIDER(IAlleleFlowers.class), + /** + * Determines pollination speed. + */ + FLOWERING(IAlleleInteger.class), + /** + * Determines the size of the bee's territory. + */ + TERRITORY(IAlleleArea.class), + /** + * Determines the bee's effect. + */ + EFFECT(IAlleleBeeEffect.class); + + Class clss; + + EnumBeeChromosome(Class clss) { + this.clss = clss; + } + + @Override + public Class getAlleleClass() { + return clss; + } + + @Override + public String getName() { + return this.toString().toLowerCase(); + } + + @Override + public ISpeciesRoot getSpeciesRoot() { + return AlleleManager.alleleRegistry.getSpeciesRoot("rootBees"); + } +} diff --git a/forestry_common/core/forestry/api/apiculture/EnumBeeType.java b/forestry_common/core/forestry/api/apiculture/EnumBeeType.java new file mode 100755 index 000000000..a3d22e5a5 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/EnumBeeType.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.Locale; + +public enum EnumBeeType { + DRONE, PRINCESS, QUEEN, LARVAE, NONE; + + public static final EnumBeeType[] VALUES = values(); + + String name; + + private EnumBeeType() { + this.name = "bees." + this.toString().toLowerCase(Locale.ENGLISH); + } + + public String getName() { + return name; + } +} diff --git a/forestry_common/core/forestry/api/apiculture/FlowerManager.java b/forestry_common/core/forestry/api/apiculture/FlowerManager.java new file mode 100755 index 000000000..144852121 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/FlowerManager.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IFlowerProvider; + +public class FlowerManager { + /** + * ItemStacks representing simple flower blocks. Meta-sensitive, processed by the basic {@link IFlowerProvider}. + */ + public static ArrayList plainFlowers = new ArrayList(); +} diff --git a/forestry_common/core/forestry/api/apiculture/IAlleleBeeEffect.java b/forestry_common/core/forestry/api/apiculture/IAlleleBeeEffect.java new file mode 100755 index 000000000..dd568bba5 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IAlleleBeeEffect.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.IAlleleEffect; +import forestry.api.genetics.IEffectData; + +public interface IAlleleBeeEffect extends IAlleleEffect { + + /** + * Called by apiaries to cause an effect in the world. + * + * @param genome + * Genome of the bee queen causing this effect + * @param storedData + * Object containing the stored effect data for the apiary/hive the bee is in. + * @param housing {@link IBeeHousing} the bee currently resides in. + * @return storedData, may have been manipulated. + */ + IEffectData doEffect(IBeeGenome genome, IEffectData storedData, IBeeHousing housing); + + /** + * Is called to produce bee effects. + * + * @param genome + * @param storedData + * Object containing the stored effect data for the apiary/hive the bee is in. + * @param housing {@link IBeeHousing} the bee currently resides in. + * @return storedData, may have been manipulated. + */ + IEffectData doFX(IBeeGenome genome, IEffectData storedData, IBeeHousing housing); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IAlleleBeeSpecies.java b/forestry_common/core/forestry/api/apiculture/IAlleleBeeSpecies.java new file mode 100755 index 000000000..54f5fad42 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IAlleleBeeSpecies.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.genetics.IAlleleSpecies; + +public interface IAlleleBeeSpecies extends IAlleleSpecies { + + /** + * @return the IBeeRoot + */ + IBeeRoot getRoot(); + + /** + * @return true if this species is only active at night. + */ + boolean isNocturnal(); + + /** + * @return Map of possible products with the chance for drop each bee cycle. (0 - 100) + */ + Map getProducts(); + + /** + * @return Map of possible specialities with the chance for drop each bee cycle. (0 - 100) + */ + Map getSpecialty(); + + /** + * Only jubilant bees produce specialities. + * @return true if the bee is jubilant, false otherwise. + */ + boolean isJubilant(IBeeGenome genome, IBeeHousing housing); + + @SideOnly(Side.CLIENT) + IIcon getIcon(EnumBeeType type, int renderPass); + + /** + * @return Path of the texture to use for entity rendering. + */ + String getEntityTexture(); +} diff --git a/forestry_common/core/forestry/api/apiculture/IAlvearyComponent.java b/forestry_common/core/forestry/api/apiculture/IAlvearyComponent.java new file mode 100755 index 000000000..29bf153cb --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IAlvearyComponent.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.core.ITileStructure; + +/** + * Needs to be implemented by TileEntities that want to be part of an alveary. + */ +public interface IAlvearyComponent extends ITileStructure { + + void registerBeeModifier(IBeeModifier modifier); + + void removeBeeModifier(IBeeModifier modifier); + + void registerBeeListener(IBeeListener event); + + void removeBeeListener(IBeeListener event); + + void addTemperatureChange(float change, float boundaryDown, float boundaryUp); + + void addHumidityChange(float change, float boundaryDown, float boundaryUp); + + /** + * @return true if this TE has a function other than a plain alveary block. Returning true prevents the TE from becoming master. + */ + boolean hasFunction(); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IApiaristTracker.java b/forestry_common/core/forestry/api/apiculture/IApiaristTracker.java new file mode 100755 index 000000000..d4657c01a --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IApiaristTracker.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IIndividual; + +/** + * Can be used to garner information on bee breeding. See {@link forestry.api.genetics.ISpeciesRoot} for retrieval functions. + * + * @author SirSengir + */ +public interface IApiaristTracker extends IBreedingTracker { + + /** + * Register the birth of a queen. Will mark species as discovered. + * + * @param queen + * Created queen. + */ + void registerQueen(IIndividual queen); + + /** + * @return Amount of queens bred with this tracker. + */ + int getQueenCount(); + + /** + * Register the birth of a princess. Will mark species as discovered. + * + * @param princess + * Created princess. + */ + void registerPrincess(IIndividual princess); + + /** + * @return Amount of princesses bred with this tracker. + */ + int getPrincessCount(); + + /** + * Register the birth of a drone. Will mark species as discovered. + * + * @param drone + * Created drone. + */ + void registerDrone(IIndividual drone); + + /** + * @return Amount of drones bred with this tracker. + */ + int getDroneCount(); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IArmorApiarist.java b/forestry_common/core/forestry/api/apiculture/IArmorApiarist.java new file mode 100755 index 000000000..8033a79da --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IArmorApiarist.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +/** + * When implemented by armor piece items, allows them to act as apiarist's armor. + */ +public interface IArmorApiarist { + /** + * Called when the apiarist's armor acts as protection against an attack. + * + * @param player + * Player being attacked + * @param armor + * Armor item + * @param cause + * Optional cause of attack, such as a bee effect identifier + * @param doProtect + * Whether or not to actually do the side effects of protection + * @return Whether or not the armor should protect the player from that attack + */ + public boolean protectPlayer(EntityPlayer player, ItemStack armor, String cause, boolean doProtect); +} diff --git a/forestry_common/core/forestry/api/apiculture/IBee.java b/forestry_common/core/forestry/api/apiculture/IBee.java new file mode 100755 index 000000000..45042c416 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBee.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IEffectData; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IIndividualLiving; + +/** + * Other implementations than Forestry's default one are not supported. + * + * @author SirSengir + */ +public interface IBee extends IIndividualLiving { + + /** + * @return Bee's genetic information. + */ + IBeeGenome getGenome(); + + /** + * @return Genetic information of the bee's mate, null if unmated. + */ + IBeeGenome getMate(); + + /** + * @return true if the individual is originally of natural origin. + */ + boolean isNatural(); + + /** + * @return generation this individual is removed from the original individual. + */ + int getGeneration(); + + /** + * Set the natural flag on this bee. + * @param flag + */ + void setIsNatural(boolean flag); + + /** + * @return true if the bee is mated with another whose isNatural() doesn't match. + */ + boolean isIrregularMating(); + + IEffectData[] doEffect(IEffectData[] storedData, IBeeHousing housing); + + IEffectData[] doFX(IEffectData[] storedData, IBeeHousing housing); + + /** + * @return true if the bee may spawn offspring + */ + boolean canSpawn(); + + /** + * Determines whether the queen can work. + * + * @param housing the {@link IBeeHousing} the bee currently resides in. + * @return Ordinal of the error code encountered. 0 - EnumErrorCode.OK + */ + int isWorking(IBeeHousing housing); + + boolean hasFlower(IBeeHousing housing); + + ArrayList getSuitableBiomeIds(); + + ItemStack[] getProduceList(); + + ItemStack[] getSpecialtyList(); + + ItemStack[] produceStacks(IBeeHousing housing); + + IBee spawnPrincess(IBeeHousing housing); + + IBee[] spawnDrones(IBeeHousing housing); + + void plantFlowerRandom(IBeeHousing housing); + + IIndividual retrievePollen(IBeeHousing housing); + + boolean pollinateRandom(IBeeHousing housing, IIndividual pollen); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeeGenome.java b/forestry_common/core/forestry/api/apiculture/IBeeGenome.java new file mode 100755 index 000000000..1142a6619 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeeGenome.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IGenome; + +/** + * Only the default implementation is supported. + * + * @author SirSengir + * + */ +public interface IBeeGenome extends IGenome { + + IAlleleBeeSpecies getPrimary(); + + IAlleleBeeSpecies getSecondary(); + + float getSpeed(); + + int getLifespan(); + + int getFertility(); + + EnumTolerance getToleranceTemp(); + + EnumTolerance getToleranceHumid(); + + boolean getNocturnal(); + + boolean getTolerantFlyer(); + + boolean getCaveDwelling(); + + IFlowerProvider getFlowerProvider(); + + int getFlowering(); + + int[] getTerritory(); + + IAlleleBeeEffect getEffect(); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeeHousing.java b/forestry_common/core/forestry/api/apiculture/IBeeHousing.java new file mode 100755 index 000000000..3a9456464 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeeHousing.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IHousing; + +public interface IBeeHousing extends IBeeModifier, IBeeListener, IHousing { + + ItemStack getQueen(); + + ItemStack getDrone(); + + void setQueen(ItemStack itemstack); + + void setDrone(ItemStack itemstack); + + /** + * @return true if princesses and drones can (currently) mate in this housing to generate queens. + */ + boolean canBreed(); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeeListener.java b/forestry_common/core/forestry/api/apiculture/IBeeListener.java new file mode 100755 index 000000000..a5cdcbd63 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeeListener.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IIndividual; + +public interface IBeeListener { + + /** + * Called on queen update. + * + * @param queen + */ + void onQueenChange(ItemStack queen); + + /** + * Called when the bees wear out the housing's equipment. + * + * @param amount + * Integer indicating the amount worn out. + */ + void wearOutEquipment(int amount); + + /** + * Called just before the children are generated, and the queen removed. + * + * @param queen + */ + void onQueenDeath(IBee queen); + + /** + * Called after the children have been spawned, but before the queen appears + * + * @param queen + */ + void onPostQueenDeath(IBee queen); + + boolean onPollenRetrieved(IBee queen, IIndividual pollen, boolean isHandled); + + boolean onEggLaid(IBee queen); +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeeModifier.java b/forestry_common/core/forestry/api/apiculture/IBeeModifier.java new file mode 100755 index 000000000..3fc996493 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeeModifier.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +public interface IBeeModifier { + + /** + * @param genome Genome of the bee this modifier is called for. + * @param currentModifier Current modifier. + * @return Float used to modify the base territory. + */ + float getTerritoryModifier(IBeeGenome genome, float currentModifier); + + /** + * @param genome Genome of the bee this modifier is called for. + * @param mate + * @param currentModifier Current modifier. + * @return Float used to modify the base mutation chance. + */ + float getMutationModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier); + + /** + * @param genome Genome of the bee this modifier is called for. + * @param currentModifier Current modifier. + * @return Float used to modify the life span of queens. + */ + float getLifespanModifier(IBeeGenome genome, IBeeGenome mate, float currentModifier); + + /** + * @param genome Genome of the bee this modifier is called for. + * @param currentModifier Current modifier. + * @return Float modifying the production speed of queens. + */ + float getProductionModifier(IBeeGenome genome, float currentModifier); + + /** + * @param genome Genome of the bee this modifier is called for. + * @return Float modifying the flowering of queens. + */ + float getFloweringModifier(IBeeGenome genome, float currentModifier); + + /** + * @param genome Genome of the bee this modifier is called for. + * @return Float modifying the chance for a swarmer queen to die off. + */ + float getGeneticDecay(IBeeGenome genome, float currentModifier); + + /** + * @return Boolean indicating if housing can ignore rain + */ + boolean isSealed(); + + /** + * @return Boolean indicating if housing can ignore darkness/night + */ + boolean isSelfLighted(); + + /** + * @return Boolean indicating if housing can ignore not seeing the sky + */ + boolean isSunlightSimulated(); + + /** + * @return Boolean indicating whether this housing simulates the nether + */ + boolean isHellish(); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeeMutation.java b/forestry_common/core/forestry/api/apiculture/IBeeMutation.java new file mode 100755 index 000000000..50409be09 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeeMutation.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; +import forestry.api.genetics.IMutation; + +public interface IBeeMutation extends IMutation { + + IBeeRoot getRoot(); + + /** + * @param housing + * @param allele0 + * @param allele1 + * @param genome0 + * @param genome1 + * @return float representing the chance for mutation to occur. note that this is 0 - 100 based, since it was an integer previously! + */ + float getChance(IBeeHousing housing, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1); +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeeRoot.java b/forestry_common/core/forestry/api/apiculture/IBeeRoot.java new file mode 100755 index 000000000..d88c71904 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeeRoot.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.core.IStructureLogic; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.ISpeciesRoot; + +public interface IBeeRoot extends ISpeciesRoot { + + /** + * @return true if passed item is a Forestry bee. Equal to getType(ItemStack stack) != EnumBeeType.NONE + */ + boolean isMember(ItemStack stack); + + /** + * @return {@link IBee} pattern parsed from the passed stack's nbt data. + */ + IBee getMember(ItemStack stack); + + IBee getMember(NBTTagCompound compound); + + /* GENOME CONVERSION */ + IBee templateAsIndividual(IAllele[] template); + + IBee templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive); + + IBeeGenome templateAsGenome(IAllele[] template); + + IBeeGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive); + + /* BREEDING TRACKER */ + /** + * @param world + * @return {@link IApiaristTracker} associated with the passed world. + */ + IApiaristTracker getBreedingTracker(World world, String player); + + /* BEE SPECIFIC */ + /** + * @return type of bee encoded on the itemstack. EnumBeeType.NONE if it isn't a bee. + */ + EnumBeeType getType(ItemStack stack); + + /** + * @return true if passed item is a drone. Equal to getType(ItemStack stack) == EnumBeeType.DRONE + */ + boolean isDrone(ItemStack stack); + + /** + * @return true if passed item is mated (i.e. a queen) + */ + boolean isMated(ItemStack stack); + + /** + * @param genome + * Valid {@link IBeeGenome} + * @return {@link IBee} from the passed genome + */ + IBee getBee(World world, IBeeGenome genome); + + /** + * Creates an IBee suitable for a queen containing the necessary second genome for the mate. + * + * @param genome + * Valid {@link IBeeGenome} + * @param mate + * Valid {@link IBee} representing the mate. + * @return Mated {@link IBee} from the passed genomes. + */ + IBee getBee(World world, IBeeGenome genome, IBee mate); + + /* TEMPLATES */ + ArrayList getIndividualTemplates(); + + /* MUTATIONS */ + Collection getMutations(boolean shuffle); + + /* GAME MODE */ + void resetBeekeepingMode(); + + ArrayList getBeekeepingModes(); + + IBeekeepingMode getBeekeepingMode(World world); + + IBeekeepingMode getBeekeepingMode(String name); + + void registerBeekeepingMode(IBeekeepingMode mode); + + void setBeekeepingMode(World world, String name); + + /* MISC */ + /** + * @param housing + * Object implementing IBeeHousing. + * @return IBeekeepingLogic + */ + IBeekeepingLogic createBeekeepingLogic(IBeeHousing housing); + + /** + * TileEntities wanting to function as alveary components need to implement structure logic for validation. + * + * @return IStructureLogic for alvearies. + */ + IStructureLogic createAlvearyStructureLogic(IAlvearyComponent structure); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeekeepingLogic.java b/forestry_common/core/forestry/api/apiculture/IBeekeepingLogic.java new file mode 100755 index 000000000..dbcd71bb9 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeekeepingLogic.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.core.INBTTagable; +import forestry.api.genetics.IEffectData; + +public interface IBeekeepingLogic extends INBTTagable { + + /* STATE INFORMATION */ + int getBreedingTime(); + + int getTotalBreedingTime(); + + IBee getQueen(); + + IBeeHousing getHousing(); + + IEffectData[] getEffectData(); + + /* UPDATING */ + void update(); + +} diff --git a/forestry_common/core/forestry/api/apiculture/IBeekeepingMode.java b/forestry_common/core/forestry/api/apiculture/IBeekeepingMode.java new file mode 100755 index 000000000..d9545a720 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IBeekeepingMode.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; + +import net.minecraft.world.World; + +public interface IBeekeepingMode extends IBeeModifier { + + /** + * @return Localized name of this beekeeping mode. + */ + String getName(); + + /** + * @return Localized list of strings outlining the behaviour of this beekeeping mode. + */ + ArrayList getDescription(); + + /** + * @return Float used to modify the wear on comb frames. + */ + float getWearModifier(); + + /** + * @param queen + * @return fertility taking into account the birthing queen and surroundings. + */ + int getFinalFertility(IBee queen, World world, int x, int y, int z); + + /** + * @param queen + * @return true if the queen is genetically "fatigued" and should not be reproduced anymore. + */ + boolean isFatigued(IBee queen, IBeeHousing housing); + + /** + * @param queen + * @param housing + * @return true if the queen is being overworked in the bee housing (with chance). will trigger a negative effect. + */ + boolean isOverworked(IBee queen, IBeeHousing housing); + + /** + * + * @param queen + * @param offspring + * @param housing + * @return true if the genetic structure of the queen is breaking down during spawning of the offspring (with chance). will trigger a negative effect. + */ + boolean isDegenerating(IBee queen, IBee offspring, IBeeHousing housing); + + /** + * @param queen + * @return true if an offspring of this queen is considered a natural + */ + boolean isNaturalOffspring(IBee queen); + + /** + * @param queen + * @return true if this mode allows the passed queen or princess to be multiplied + */ + boolean mayMultiplyPrincess(IBee queen); + + +} diff --git a/forestry_common/core/forestry/api/apiculture/IHiveDrop.java b/forestry_common/core/forestry/api/apiculture/IHiveDrop.java new file mode 100755 index 000000000..95e6d467d --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IHiveDrop.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * Bees can be seeded either as hive drops or as mutation results. + * + * Add IHiveDrops to BeeManager.hiveDrops + * + * @author SirSengir + */ +public interface IHiveDrop { + + ItemStack getPrincess(World world, int x, int y, int z, int fortune); + + Collection getDrones(World world, int x, int y, int z, int fortune); + + Collection getAdditional(World world, int x, int y, int z, int fortune); + + /** + * Chance to drop. Default drops have 80 (= 80 %). + * + * @param world Minecraft world this is called for. + * @param x x-Coordinate of the broken hive. + * @param y y-Coordinate of the broken hive. + * @param z z-Coordinate of the broken hive. + * @return Chance for drop as an integer of 0 - 100. + */ + int getChance(World world, int x, int y, int z); +} diff --git a/forestry_common/core/forestry/api/apiculture/IHiveFrame.java b/forestry_common/core/forestry/api/apiculture/IHiveFrame.java new file mode 100755 index 000000000..f1f6d3082 --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/IHiveFrame.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.apiculture; + +import net.minecraft.item.ItemStack; + +public interface IHiveFrame extends IBeeModifier { + + /** + * Wears out a frame. + * + * @param housing + * IBeeHousing the frame is contained in. + * @param frame + * ItemStack containing the actual frame. + * @param queen + * Current queen in the caller. + * @param wear + * Integer denoting the amount worn out. The wear modifier of the current beekeeping mode has already been taken into account. + * @return ItemStack containing the actual frame with adjusted damage. + */ + ItemStack frameUsed(IBeeHousing housing, ItemStack frame, IBee queen, int wear); + +} diff --git a/forestry_common/core/forestry/api/apiculture/package-info.java b/forestry_common/core/forestry/api/apiculture/package-info.java new file mode 100755 index 000000000..38dfe392f --- /dev/null +++ b/forestry_common/core/forestry/api/apiculture/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|apiculture") +package forestry.api.apiculture; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/arboriculture/EnumGermlingType.java b/forestry_common/core/forestry/api/arboriculture/EnumGermlingType.java new file mode 100755 index 000000000..bf7244881 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/EnumGermlingType.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +public enum EnumGermlingType { + SAPLING("Sapling"), BLOSSOM("Blossom"), POLLEN("Pollen"), GERMLING("Germling"), NONE("None"); + + public static final EnumGermlingType[] VALUES = values(); + + String name; + + private EnumGermlingType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + +} diff --git a/forestry_common/core/forestry/api/arboriculture/EnumGrowthConditions.java b/forestry_common/core/forestry/api/arboriculture/EnumGrowthConditions.java new file mode 100755 index 000000000..fdb1bb6c7 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/EnumGrowthConditions.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +public enum EnumGrowthConditions { + HOSTILE, PALTRY, NORMAL, GOOD, EXCELLENT +} diff --git a/forestry_common/core/forestry/api/arboriculture/EnumTreeChromosome.java b/forestry_common/core/forestry/api/arboriculture/EnumTreeChromosome.java new file mode 100755 index 000000000..6478353db --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/EnumTreeChromosome.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleArea; +import forestry.api.genetics.IAlleleFloat; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IAllelePlantType; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.IFruitFamily; +import forestry.api.genetics.ISpeciesRoot; + +public enum EnumTreeChromosome implements IChromosomeType { + + /** + * Determines the following: - WorldGen, including the used wood blocks - {@link IFruitFamily}s supported. Limits which {@link IFruitProvider} + * will actually yield fruit with this species. - Native {@link EnumPlantType} for this tree. Combines with the PLANT chromosome. + */ + SPECIES(IAlleleTreeSpecies.class), + /** + * {@link IGrowthProvider}, determines conditions required by the tree to grow. + */ + GROWTH(IAlleleGrowth.class), + /** + * A float modifying the height of the tree. Taken into account at worldgen. + */ + HEIGHT(IAlleleFloat.class), + /** + * Chance for saplings. + */ + FERTILITY(IAlleleFloat.class), + /** + * {@link IFruitProvider}, determines if and what fruits are grown on the tree. Limited by the {@link IFruitFamily}s the species supports. + */ + FRUITS(IAlleleFruit.class), + /** + * Chance for fruit leaves and/or drops. + */ + YIELD(IAlleleFloat.class), + /** + * May add additional tolerances for {@link EnumPlantTypes}. + */ + PLANT(IAllelePlantType.class), + /** + * Determines the speed at which fruit will ripen on this tree. + */ + SAPPINESS(IAlleleFloat.class), + /** + * Territory for leaf effects. Unused. + */ + TERRITORY(IAlleleArea.class), + /** + * Leaf effect. Unused. + */ + EFFECT(IAlleleLeafEffect.class), + /** + * Amount of random ticks which need to elapse before a sapling will grow into a tree. + */ + MATURATION(IAlleleInteger.class), + + GIRTH(IAlleleInteger.class), + ; + + Class clss; + + EnumTreeChromosome(Class clss) { + this.clss = clss; + } + + @Override + public Class getAlleleClass() { + return clss; + } + + @Override + public String getName() { + return this.toString().toLowerCase(); + } + + @Override + public ISpeciesRoot getSpeciesRoot() { + return AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees"); + } + +} diff --git a/forestry_common/core/forestry/api/arboriculture/IAlleleFruit.java b/forestry_common/core/forestry/api/arboriculture/IAlleleFruit.java new file mode 100755 index 000000000..00e96bf83 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IAlleleFruit.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import forestry.api.genetics.IAllele; + +/** + * Simple allele encapsulating an {@link IFruitProvider}. + */ +public interface IAlleleFruit extends IAllele { + + IFruitProvider getProvider(); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/IAlleleGrowth.java b/forestry_common/core/forestry/api/arboriculture/IAlleleGrowth.java new file mode 100755 index 000000000..63704d3f5 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IAlleleGrowth.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import forestry.api.genetics.IAllele; + +/** + * Simple allele encapsulating an {@link IGrowthProvider}. + */ +public interface IAlleleGrowth extends IAllele { + + IGrowthProvider getProvider(); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/IAlleleLeafEffect.java b/forestry_common/core/forestry/api/arboriculture/IAlleleLeafEffect.java new file mode 100755 index 000000000..8ecd3fe1f --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IAlleleLeafEffect.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraft.world.World; + +import forestry.api.genetics.IAlleleEffect; +import forestry.api.genetics.IEffectData; + +/** + * Simple allele encapsulating a leaf effect. (Not implemented) + */ +public interface IAlleleLeafEffect extends IAlleleEffect { + + IEffectData doEffect(ITreeGenome genome, IEffectData storedData, World world, int x, int y, int z); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/IAlleleTreeSpecies.java b/forestry_common/core/forestry/api/arboriculture/IAlleleTreeSpecies.java new file mode 100755 index 000000000..624e1a409 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IAlleleTreeSpecies.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IFruitFamily; + +public interface IAlleleTreeSpecies extends IAlleleSpecies { + + ITreeRoot getRoot(); + + /** + * @return Native plant type of this species. + */ + EnumPlantType getPlantType(); + + /** + * @return List of all {@link IFruitFamily}s which can grow on leaves generated by this species. + */ + Collection getSuitableFruit(); + + /** + * @return Trunk girth. 1 = 1x1, 2 = 2x2, etc. + */ + @Deprecated + int getGirth(); + + /** + * @param tree + * @param world + * @param x + * @param y + * @param z + * @return Tree generator for the tree at the given location. + */ + WorldGenerator getGenerator(ITree tree, World world, int x, int y, int z); + + /** + * @return All available generator classes for this species. + */ + Class[] getGeneratorClasses(); + + /* TEXTURES AND OVERRIDES */ + int getLeafColour(ITree tree); + + short getLeafIconIndex(ITree tree, boolean fancy); + + @SideOnly(Side.CLIENT) + IIcon getGermlingIcon(EnumGermlingType type, int renderPass); + + @SideOnly(Side.CLIENT) + int getGermlingColour(EnumGermlingType type, int renderPass); + + /** + * + * @return Array of ItemStacks representing logs that these tree produces, the first one being the primary one + */ + ItemStack[] getLogStacks(); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/IArboristTracker.java b/forestry_common/core/forestry/api/arboriculture/IArboristTracker.java new file mode 100755 index 000000000..a0b8ed7ac --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IArboristTracker.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import forestry.api.genetics.IBreedingTracker; + +public interface IArboristTracker extends IBreedingTracker { + +} diff --git a/forestry_common/core/forestry/api/arboriculture/IFruitProvider.java b/forestry_common/core/forestry/api/arboriculture/IFruitProvider.java new file mode 100755 index 000000000..a8c6e62ca --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IFruitProvider.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.genetics.IFruitFamily; + +public interface IFruitProvider { + + IFruitFamily getFamily(); + + int getColour(ITreeGenome genome, IBlockAccess world, int x, int y, int z, int ripeningTime); + + boolean markAsFruitLeaf(ITreeGenome genome, World world, int x, int y, int z); + + int getRipeningPeriod(); + + // / Products, Chance + ItemStack[] getProducts(); + + // / Specialty, Chance + ItemStack[] getSpecialty(); + + ItemStack[] getFruits(ITreeGenome genome, World world, int x, int y, int z, int ripeningTime); + + /** + * @return Short, human-readable identifier used in the treealyzer. + */ + String getDescription(); + + /* TEXTURE OVERLAY */ + /** + * @param genome + * @param world + * @param x + * @param y + * @param z + * @param ripeningTime + * Elapsed ripening time for the fruit. + * @param fancy + * @return IIcon index of the texture to overlay on the leaf block. + */ + short getIconIndex(ITreeGenome genome, IBlockAccess world, int x, int y, int z, int ripeningTime, boolean fancy); + + /** + * @return true if this fruit provider requires fruit blocks to spawn, false otherwise. + */ + boolean requiresFruitBlocks(); + + /** + * Tries to spawn a fruit block at the potential position when the tree generates. + * + * @param genome + * @param world + * @param x + * @param y + * @param z + * @return true if a fruit block was spawned, false otherwise. + */ + boolean trySpawnFruitBlock(ITreeGenome genome, World world, int x, int y, int z); + + @SideOnly(Side.CLIENT) + void registerIcons(IIconRegister register); +} diff --git a/forestry_common/core/forestry/api/arboriculture/IGrowthProvider.java b/forestry_common/core/forestry/api/arboriculture/IGrowthProvider.java new file mode 100755 index 000000000..74f02d631 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IGrowthProvider.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraft.world.World; + +public interface IGrowthProvider { + + /** + * Check to see whether a sapling at the given location with the given genome can grow into a tree. + * + * @param genome Genome of the tree this is called for. + * @param world Minecraft world the tree will inhabit. + * @param xPos x-Coordinate to attempt growth at. + * @param yPos y-Coordinate to attempt growth at. + * @param zPos z-Coordinate to attempt growth at. + * @param expectedGirth Trunk size of the tree to generate. + * @param expectedHeight Height of the tree to generate. + * @return true if the tree can grow at the given coordinates, false otherwise. + */ + boolean canGrow(ITreeGenome genome, World world, int xPos, int yPos, int zPos, int expectedGirth, int expectedHeight); + + EnumGrowthConditions getGrowthConditions(ITreeGenome genome, World world, int xPos, int yPos, int zPos); + + /** + * @return Short, human-readable identifier used in the treealyzer. + */ + String getDescription(); + + /** + * @return Detailed description of growth behaviour used in the treealyzer. + */ + String[] getInfo(); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/ILeafTickHandler.java b/forestry_common/core/forestry/api/arboriculture/ILeafTickHandler.java new file mode 100755 index 000000000..4711e1b7d --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/ILeafTickHandler.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraft.world.World; + +public interface ILeafTickHandler { + boolean onRandomLeafTick(ITree tree, World world, int biomeId, int x, int y, int z, boolean isDestroyed); +} diff --git a/forestry_common/core/forestry/api/arboriculture/IToolGrafter.java b/forestry_common/core/forestry/api/arboriculture/IToolGrafter.java new file mode 100755 index 000000000..9c3f51c3f --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/IToolGrafter.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IToolGrafter { + /** + * Called by leaves to determine the increase in sapling droprate. + * + * @param stack ItemStack containing the grafter. + * @param world Minecraft world the player and the target block inhabit. + * @param x x-Coordinate of the broken leaf block. + * @param y y-Coordinate of the broken leaf block. + * @param z z-Coordinate of the broken leaf block. + * @return Float representing the factor the usual drop chance is to be multiplied by. + */ + float getSaplingModifier(ItemStack stack, World world, EntityPlayer player, int x, int y, int z); +} diff --git a/forestry_common/core/forestry/api/arboriculture/ITree.java b/forestry_common/core/forestry/api/arboriculture/ITree.java new file mode 100755 index 000000000..3a492eb9f --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/ITree.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import java.util.EnumSet; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IEffectData; +import forestry.api.genetics.IIndividual; + +public interface ITree extends IIndividual { + + void mate(ITree other); + + IEffectData[] doEffect(IEffectData[] storedData, World world, int biomeid, int x, int y, int z); + + IEffectData[] doFX(IEffectData[] storedData, World world, int biomeid, int x, int y, int z); + + ITreeGenome getGenome(); + + ITreeGenome getMate(); + + EnumSet getPlantTypes(); + + ITree[] getSaplings(World world, int x, int y, int z, float modifier); + + ItemStack[] getProduceList(); + + ItemStack[] getSpecialtyList(); + + ItemStack[] produceStacks(World world, int x, int y, int z, int ripeningTime); + + /** + * + * @param world + * @param x + * @param y + * @param z + * @return Boolean indicating whether a sapling can stay planted at the given position. + */ + boolean canStay(World world, int x, int y, int z); + + /** + * + * @param world + * @param x + * @param y + * @param z + * @return Boolean indicating whether a sapling at the given position can grow into a tree. + */ + boolean canGrow(World world, int x, int y, int z, int expectedGirth, int expectedHeight); + + /** + * @return Integer denoting the maturity (block ticks) required for a sapling to attempt to grow into a tree. + */ + int getRequiredMaturity(); + + /** + * @return Integer denoting how resilient leaf blocks are against adverse influences (i.e. caterpillars). + */ + int getResilience(); + + /** + * @param world + * @param x + * @param y + * @param z + * @return Integer denoting the size of the tree trunk. + */ + int getGirth(World world, int x, int y, int z); + + + + /** + * + * @param world + * @param x + * @param y + * @param z + * @return Growth conditions at the given position. + */ + EnumGrowthConditions getGrowthCondition(World world, int x, int y, int z); + + WorldGenerator getTreeGenerator(World world, int x, int y, int z, boolean wasBonemealed); + + ITree copy(); + + boolean isPureBred(EnumTreeChromosome chromosome); + + boolean canBearFruit(); +} diff --git a/forestry_common/core/forestry/api/arboriculture/ITreeGenome.java b/forestry_common/core/forestry/api/arboriculture/ITreeGenome.java new file mode 100755 index 000000000..971307506 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/ITreeGenome.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import java.util.EnumSet; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IGenome; + +public interface ITreeGenome extends IGenome { + + IAlleleTreeSpecies getPrimary(); + + IAlleleTreeSpecies getSecondary(); + + IFruitProvider getFruitProvider(); + + IGrowthProvider getGrowthProvider(); + + float getHeight(); + + float getFertility(); + + /** + * @return Determines either a) how many fruit leaves there are or b) the chance for any fruit leave to drop a sapling. Exact usage determined by the + * IFruitProvider + */ + float getYield(); + + float getSappiness(); + + EnumSet getPlantTypes(); + + /** + * @return Amount of random block ticks required for a sapling to mature into a fully grown tree. + */ + int getMaturationTime(); + + int getGirth(); + + IAlleleLeafEffect getEffect(); +} diff --git a/forestry_common/core/forestry/api/arboriculture/ITreeModifier.java b/forestry_common/core/forestry/api/arboriculture/ITreeModifier.java new file mode 100755 index 000000000..9eb559070 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/ITreeModifier.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +public interface ITreeModifier { + + /** + * + * @param genome + * @return Float used to modify the height. + */ + float getHeightModifier(ITreeGenome genome, float currentModifier); + + /** + * + * @param genome + * @return Float used to modify the yield. + */ + float getYieldModifier(ITreeGenome genome, float currentModifier); + + /** + * + * @param genome + * @return Float used to modify the sappiness. + */ + float getSappinessModifier(ITreeGenome genome, float currentModifier); + + /** + * + * @param genome + * @return Float used to modify the maturation. + */ + float getMaturationModifier(ITreeGenome genome, float currentModifier); + + /** + * @param genome0 + * @param genome1 + * @return Float used to modify the base mutation chance. + */ + float getMutationModifier(ITreeGenome genome0, ITreeGenome genome1, float currentModifier); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/ITreeMutation.java b/forestry_common/core/forestry/api/arboriculture/ITreeMutation.java new file mode 100755 index 000000000..1c0e3b7d4 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/ITreeMutation.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraft.world.World; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; +import forestry.api.genetics.IMutation; +import forestry.api.genetics.ISpeciesRoot; + +public interface ITreeMutation extends IMutation { + + /** + * @return {@link ISpeciesRoot} this mutation is associated with. + */ + ITreeRoot getRoot(); + + /** + * @param world + * @param x + * @param y + * @param z + * @param allele0 + * @param allele1 + * @param genome0 + * @param genome1 + * @return float representing the chance for mutation to occur. note that this is 0 - 100 based, since it was an integer previously! + */ + float getChance(World world, int x, int y, int z, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1); +} diff --git a/forestry_common/core/forestry/api/arboriculture/ITreeRoot.java b/forestry_common/core/forestry/api/arboriculture/ITreeRoot.java new file mode 100755 index 000000000..02ede2c61 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/ITreeRoot.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.ISpeciesRoot; + +public interface ITreeRoot extends ISpeciesRoot { + + boolean isMember(ItemStack itemstack); + + ITree getMember(ItemStack itemstack); + + ITree getMember(NBTTagCompound compound); + + ITreeGenome templateAsGenome(IAllele[] template); + + ITreeGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive); + + /** + * @param world + * @return {@link IArboristTracker} associated with the passed world. + */ + IArboristTracker getBreedingTracker(World world, String player); + + /* TREE SPECIFIC */ + /** + * Register a leaf tick handler. + * @param handler the {@link ILeafTickHandler} to register. + */ + void registerLeafTickHandler(ILeafTickHandler handler); + + Collection getLeafTickHandlers(); + + /** + * @return type of tree encoded on the itemstack. EnumBeeType.NONE if it isn't a tree. + */ + EnumGermlingType getType(ItemStack stack); + + ITree getTree(World world, int x, int y, int z); + + ITree getTree(World world, ITreeGenome genome); + + boolean plantSapling(World world, ITree tree, String owner, int x, int y, int z); + + boolean setLeaves(World world, IIndividual tree, String owner, int x, int y, int z); + + IChromosome[] templateAsChromosomes(IAllele[] template); + + IChromosome[] templateAsChromosomes(IAllele[] templateActive, IAllele[] templateInactive); + + boolean setFruitBlock(World world, IAlleleFruit allele, float sappiness, short[] indices, int x, int y, int z); + + /* GAME MODE */ + ArrayList getTreekeepingModes(); + + ITreekeepingMode getTreekeepingMode(World world); + + ITreekeepingMode getTreekeepingMode(String name); + + void registerTreekeepingMode(ITreekeepingMode mode); + + void setTreekeepingMode(World world, String name); + + /* TEMPLATES */ + ArrayList getIndividualTemplates(); + + /* MUTATIONS */ + Collection getMutations(boolean shuffle); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/ITreekeepingMode.java b/forestry_common/core/forestry/api/arboriculture/ITreekeepingMode.java new file mode 100755 index 000000000..99980ccc0 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/ITreekeepingMode.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +import java.util.ArrayList; + +public interface ITreekeepingMode extends ITreeModifier { + + /** + * @return Localized name of this treekeeping mode. + */ + String getName(); + + /** + * @return Localized list of strings outlining the behaviour of this treekeeping mode. + */ + ArrayList getDescription(); + +} diff --git a/forestry_common/core/forestry/api/arboriculture/TreeManager.java b/forestry_common/core/forestry/api/arboriculture/TreeManager.java new file mode 100755 index 000000000..e10c02702 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/TreeManager.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.arboriculture; + +public class TreeManager { + public static int treeSpeciesCount = 0; + + /** + * Get your own reference to this via AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees") and save it somewhere. + */ + @Deprecated + public static ITreeRoot treeInterface; +} diff --git a/forestry_common/core/forestry/api/arboriculture/package-info.java b/forestry_common/core/forestry/api/arboriculture/package-info.java new file mode 100755 index 000000000..b20483dc4 --- /dev/null +++ b/forestry_common/core/forestry/api/arboriculture/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|arboriculture") +package forestry.api.arboriculture; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/circuits/ChipsetManager.java b/forestry_common/core/forestry/api/circuits/ChipsetManager.java new file mode 100755 index 000000000..616a40bdd --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/ChipsetManager.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.circuits; + +public class ChipsetManager { + + public static ISolderManager solderManager; + public static ICircuitRegistry circuitRegistry; + +} diff --git a/forestry_common/core/forestry/api/circuits/ICircuit.java b/forestry_common/core/forestry/api/circuits/ICircuit.java new file mode 100755 index 000000000..84c16539e --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/ICircuit.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.circuits; + +import java.util.List; + +import net.minecraft.tileentity.TileEntity; + +public interface ICircuit { + String getUID(); + + boolean requiresDiscovery(); + + int getLimit(); + + String getName(); + + boolean isCircuitable(TileEntity tile); + + void onInsertion(int slot, TileEntity tile); + + void onLoad(int slot, TileEntity tile); + + void onRemoval(int slot, TileEntity tile); + + void onTick(int slot, TileEntity tile); + + void addTooltip(List list); +} diff --git a/forestry_common/core/forestry/api/circuits/ICircuitBoard.java b/forestry_common/core/forestry/api/circuits/ICircuitBoard.java new file mode 100755 index 000000000..fd2927202 --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/ICircuitBoard.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.circuits; + +import java.util.List; + +import net.minecraft.tileentity.TileEntity; + +import forestry.api.core.INBTTagable; + +public interface ICircuitBoard extends INBTTagable { + + int getPrimaryColor(); + + int getSecondaryColor(); + + void addTooltip(List list); + + void onInsertion(TileEntity tile); + + void onLoad(TileEntity tile); + + void onRemoval(TileEntity tile); + + void onTick(TileEntity tile); + + ICircuit[] getCircuits(); + +} diff --git a/forestry_common/core/forestry/api/circuits/ICircuitLayout.java b/forestry_common/core/forestry/api/circuits/ICircuitLayout.java new file mode 100755 index 000000000..02d9ac818 --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/ICircuitLayout.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.circuits; + +public interface ICircuitLayout { + + String getUID(); + + String getName(); + + String getUsage(); + +} diff --git a/forestry_common/core/forestry/api/circuits/ICircuitLibrary.java b/forestry_common/core/forestry/api/circuits/ICircuitLibrary.java new file mode 100755 index 000000000..73285e708 --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/ICircuitLibrary.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.circuits; + +public interface ICircuitLibrary { + +} diff --git a/forestry_common/core/forestry/api/circuits/ICircuitRegistry.java b/forestry_common/core/forestry/api/circuits/ICircuitRegistry.java new file mode 100755 index 000000000..178acec1f --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/ICircuitRegistry.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.circuits; + +import java.util.HashMap; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface ICircuitRegistry { + + /* CIRCUITS */ + HashMap getRegisteredCircuits(); + + void registerCircuit(ICircuit circuit); + + ICircuit getCircuit(String uid); + + ICircuitLibrary getCircuitLibrary(World world, String playername); + + void registerLegacyMapping(int id, String uid); + + ICircuit getFromLegacyMap(int id); + + /* LAYOUTS */ + HashMap getRegisteredLayouts(); + + void registerLayout(ICircuitLayout layout); + + ICircuitLayout getLayout(String uid); + + ICircuitLayout getDefaultLayout(); + + + ICircuitBoard getCircuitboard(ItemStack itemstack); + + boolean isChipset(ItemStack itemstack); + +} diff --git a/forestry_common/core/forestry/api/circuits/ISolderManager.java b/forestry_common/core/forestry/api/circuits/ISolderManager.java new file mode 100755 index 000000000..5cff49a1c --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/ISolderManager.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.circuits; + +import net.minecraft.item.ItemStack; + +public interface ISolderManager { + + void addRecipe(ICircuitLayout layout, ItemStack resource, ICircuit circuit); + +} diff --git a/forestry_common/core/forestry/api/circuits/package-info.java b/forestry_common/core/forestry/api/circuits/package-info.java new file mode 100755 index 000000000..4525597fe --- /dev/null +++ b/forestry_common/core/forestry/api/circuits/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|circuits") +package forestry.api.circuits; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/core/BlockInterface.java b/forestry_common/core/forestry/api/core/BlockInterface.java new file mode 100755 index 000000000..7e60d9c51 --- /dev/null +++ b/forestry_common/core/forestry/api/core/BlockInterface.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.FMLLog; + +public class BlockInterface { + /** + * Rather limited function to retrieve block ids. + * + * @param ident + * @return ItemStack representing the block. + */ + @Deprecated + public static ItemStack getBlock(String ident) { + ItemStack item = null; + + try { + String pack = ItemInterface.class.getPackage().getName(); + pack = pack.substring(0, pack.lastIndexOf('.')); + String itemClass = pack.substring(0, pack.lastIndexOf('.')) + ".core.config.ForestryBlock"; + Object obj = Class.forName(itemClass).getField(ident).get(null); + if (obj instanceof Block) + item = new ItemStack((Block) obj); + else if (obj instanceof ItemStack) + item = (ItemStack) obj; + } catch (Exception ex) { + FMLLog.warning("Could not retrieve Forestry block identified by: " + ident); + } + + return item; + } + +} diff --git a/forestry_common/core/forestry/api/core/EnumHumidity.java b/forestry_common/core/forestry/api/core/EnumHumidity.java new file mode 100755 index 000000000..6fcea2ff3 --- /dev/null +++ b/forestry_common/core/forestry/api/core/EnumHumidity.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import java.util.ArrayList; + +/** + * Many things Forestry use temperature and humidity of a biome to determine whether they can or how they can work or spawn at a given location. + * + * This enum concerns humidity. + */ +public enum EnumHumidity { + ARID("Arid"), NORMAL("Normal"), DAMP("Damp"); + + /** + * Populated by Forestry with vanilla biomes. Add additional arid biomes here. (ex. desert) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList aridBiomeIds = new ArrayList(); + /** + * Populated by Forestry with vanilla biomes. Add additional damp biomes here. (ex. jungle) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList dampBiomeIds = new ArrayList(); + /** + * Populated by Forestry with vanilla biomes. Add additional normal biomes here. + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList normalBiomeIds = new ArrayList(); + + public final String name; + + private EnumHumidity(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + @Deprecated + public static ArrayList getBiomeIds(EnumHumidity humidity) { + switch (humidity) { + case ARID: + return aridBiomeIds; + case DAMP: + return dampBiomeIds; + case NORMAL: + default: + return normalBiomeIds; + } + } + + /** + * Determines the EnumHumidity given a floating point representation of Minecraft Rainfall + * @param rawHumidity raw rainfall value + * @return EnumHumidity corresponding to rainfall value + */ + public static EnumHumidity getFromValue(float rawHumidity) { + EnumHumidity value = EnumHumidity.ARID; + + if (rawHumidity >= 0.9f) { + value = EnumHumidity.DAMP; + } + else if (rawHumidity >= 0.3f) { + value = EnumHumidity.NORMAL; + } + + return value; + } +} diff --git a/forestry_common/core/forestry/api/core/EnumTemperature.java b/forestry_common/core/forestry/api/core/EnumTemperature.java new file mode 100755 index 000000000..23b8ebfc7 --- /dev/null +++ b/forestry_common/core/forestry/api/core/EnumTemperature.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import java.util.ArrayList; + +import net.minecraft.util.IIcon; +import net.minecraft.world.biome.BiomeGenBase; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.BiomeDictionary; + +/** + * Many things Forestry use temperature and humidity of a biome to determine whether they can or how they can work or spawn at a given location. + * + * This enum concerns temperature. + */ +public enum EnumTemperature { + NONE("None", "habitats/ocean"), ICY("Icy", "habitats/snow"), COLD("Cold", "habitats/taiga"), + NORMAL("Normal", "habitats/plains"), WARM("Warm", "habitats/jungle"), HOT("Hot", "habitats/desert"), HELLISH("Hellish", "habitats/nether"); + + /** + * Populated by Forestry with vanilla biomes. Add additional icy/snow biomes here. (ex. snow plains) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList icyBiomeIds = new ArrayList(); + /** + * Populated by Forestry with vanilla biomes. Add additional cold biomes here. (ex. taiga) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList coldBiomeIds = new ArrayList(); + /** + * Populated by Forestry with vanilla biomes. Add additional normal biomes here. (ex. forest, plains) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList normalBiomeIds = new ArrayList(); + /** + * Populated by Forestry with vanilla biomes. Add additional warm biomes here. (ex. jungle) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList warmBiomeIds = new ArrayList(); + /** + * Populated by Forestry with vanilla biomes. Add additional hot biomes here. (ex. desert) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList hotBiomeIds = new ArrayList(); + /** + * Populated by Forestry with vanilla biomes. Add additional hellish biomes here. (ex. nether) + * @deprecated Biomes will be checked live rather than relying on cached values, so you don't have to register them. + */ + @Deprecated + public static ArrayList hellishBiomeIds = new ArrayList(); + + public final String name; + public final String iconIndex; + + private EnumTemperature(String name, String iconIndex) { + this.name = name; + this.iconIndex = iconIndex; + } + + public String getName() { + return this.name; + } + + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return ForestryAPI.textureManager.getDefault(iconIndex); + } + /** + * @deprecated Switching most internals to use getFromValue to not rely on cached values. + */ + @Deprecated + public static ArrayList getBiomeIds(EnumTemperature temperature) { + + switch (temperature) { + case ICY: + return icyBiomeIds; + case COLD: + return coldBiomeIds; + case WARM: + return warmBiomeIds; + case HOT: + return hotBiomeIds; + case HELLISH: + return hellishBiomeIds; + case NORMAL: + default: + return normalBiomeIds; + } + + } + + /** + * Determines if a given BiomeGenBase is of HELLISH temperature, since it is treated seperatly from actual temperature values. + * Uses the BiomeDictionary. + * @param biomeGen BiomeGenBase of the biome in question + * @return true, if the BiomeGenBase is a Nether-type biome; false otherwise. + */ + public static boolean isBiomeHellish(BiomeGenBase biomeGen) { + return BiomeDictionary.isBiomeOfType(biomeGen, BiomeDictionary.Type.NETHER); + } + + /** + * Determines if a given biomeID is of HELLISH temperature, since it is treated seperatly from actual temperature values. + * Uses the BiomeDictionary. + * @param biomeID ID of the BiomeGenBase in question + * @return true, if the biomeID is a Nether-type biome; false otherwise. + */ + public static boolean isBiomeHellish(int biomeID) { + return BiomeDictionary.isBiomeRegistered(biomeID) && BiomeDictionary.isBiomeOfType(BiomeGenBase.getBiome(biomeID), BiomeDictionary.Type.NETHER); + } + + /** + * Determines the EnumTemperature given a floating point representation of + * Minecraft temperature. Hellish biomes are handled based on their biome + * type - check isBiomeHellish. + * @param rawTemp raw temperature value + * @return EnumTemperature corresponding to value of rawTemp + */ + public static EnumTemperature getFromValue(float rawTemp) { + EnumTemperature value = EnumTemperature.ICY; + + if (rawTemp >= 2.0f) { + value = EnumTemperature.HOT; + } + else if (rawTemp >= 1.2f) { + value = EnumTemperature.WARM; + } + else if (rawTemp >= 0.2f) { + value = EnumTemperature.NORMAL; + } + else if (rawTemp >= 0.05f) { + value = EnumTemperature.COLD; + } + + return value; + } + +} diff --git a/forestry_common/core/forestry/api/core/ForestryAPI.java b/forestry_common/core/forestry/api/core/ForestryAPI.java new file mode 100755 index 000000000..7374016c5 --- /dev/null +++ b/forestry_common/core/forestry/api/core/ForestryAPI.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Forestry's API is divided into several subcategories to make it easier to understand. + * + * If you need to distribute API files, try to only include the parts you are actually + * using to minimize conflicts due to API changes. + * + * .core - Miscallenous base classes and interfaces as well as some basics for tools, armor, game modes and stuff needed by biome mods. + * .fuels - Managers and classes to facilitate adding fuels to various engines and machines. + * .recipes - Managers and helpers to facilitate adding new recipes to various machines. + * .storage - Managers, events and interfaces for defining new backpacks and handling backpack behaviour. + * .mail - Anything related to handling letters and adding new mail carrier systems. + * .genetics - Shared code for all genetic subclasses. + * \ .apiculture - Bees. + * \ .arboriculture - Trees. + * \ .lepidopterology - Butterflies. + * + * Note that if Forestry is not present, all these references will be null. + */ +public class ForestryAPI { + + /** + * The main mod instance for Forestry. + */ + public static Object instance; + + /** + * A {@link ITextureManager} needed for some things in the API. + */ + @SideOnly(Side.CLIENT) + public static ITextureManager textureManager; + + /** + * The currently active {@link IGameMode}. + */ + public static IGameMode activeMode; + + /** + * Provides information on certain Forestry constants (Villager IDs, Chest gen keys, etc) + */ + public static IForestryConstants forestryConstants; + +} diff --git a/forestry_common/core/forestry/api/core/ForestryEvent.java b/forestry_common/core/forestry/api/core/ForestryEvent.java new file mode 100755 index 000000000..db7a401fb --- /dev/null +++ b/forestry_common/core/forestry/api/core/ForestryEvent.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.entity.player.EntityPlayer; + +import cpw.mods.fml.common.eventhandler.Event; + +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IMutation; +import forestry.api.genetics.ISpeciesRoot; + +public abstract class ForestryEvent extends Event { + + private static abstract class BreedingEvent extends ForestryEvent { + public final ISpeciesRoot root; + public final IBreedingTracker tracker; + public final String username; + + private BreedingEvent(ISpeciesRoot root, String username, IBreedingTracker tracker) { + super(); + this.root = root; + this.username = username; + this.tracker = tracker; + } + } + + public static class SpeciesDiscovered extends BreedingEvent { + public final IAlleleSpecies species; + public SpeciesDiscovered(ISpeciesRoot root, String username, IAlleleSpecies species, IBreedingTracker tracker) { + super(root, username, tracker); + this.species = species; + } + } + + public static class MutationDiscovered extends BreedingEvent { + public final IMutation allele; + public MutationDiscovered(ISpeciesRoot root, String username, IMutation allele, IBreedingTracker tracker) { + super(root, username, tracker); + this.allele = allele; + } + } + + public static class SyncedBreedingTracker extends ForestryEvent { + public final IBreedingTracker tracker; + public final EntityPlayer player; + public SyncedBreedingTracker(IBreedingTracker tracker, EntityPlayer player) { + super(); + this.tracker = tracker; + this.player = player; + } + + } +} diff --git a/forestry_common/core/forestry/api/core/IArmorNaturalist.java b/forestry_common/core/forestry/api/core/IArmorNaturalist.java new file mode 100755 index 000000000..ebf73ab36 --- /dev/null +++ b/forestry_common/core/forestry/api/core/IArmorNaturalist.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public interface IArmorNaturalist { + + /** + * Called when the naturalist's armor acts as spectacles for seeing pollinated tree leaves/flowers. + * + * @param player + * Player doing the viewing + * @param armor + * Armor item + * @param doSee + * Whether or not to actually do the side effects of viewing + * @return true if the armor actually allows the player to see pollination. + */ + public boolean canSeePollination(EntityPlayer player, ItemStack armor, boolean doSee); +} diff --git a/forestry_common/core/forestry/api/core/IForestryConstants.java b/forestry_common/core/forestry/api/core/IForestryConstants.java new file mode 100755 index 000000000..054aefc3c --- /dev/null +++ b/forestry_common/core/forestry/api/core/IForestryConstants.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +public interface IForestryConstants { + + /** + * @return The villager ID for the Apiarist Villager. + */ + public int getApicultureVillagerID(); + + /** + * @return The villager ID for the Arborist Villager. + */ + public int getArboricultureVillagerID(); + + /** + * @return The ChestGenHooks key for adding items to the Forestry Villager chest. + */ + public String getVillagerChestGenKey(); +} diff --git a/forestry_common/core/forestry/api/core/IGameMode.java b/forestry_common/core/forestry/api/core/IGameMode.java new file mode 100755 index 000000000..46a6461e4 --- /dev/null +++ b/forestry_common/core/forestry/api/core/IGameMode.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.item.ItemStack; + +public interface IGameMode { + + /** + * @return Human-readable identifier for the game mode. (i.e. 'EASY', 'NORMAL', 'HARD') + */ + String getIdentifier(); + + /** + * @param ident Identifier for the setting. (See the gamemode config.) + * @return Value of the requested setting, false if unknown setting. + */ + boolean getBooleanSetting(String ident); + + /** + * @param ident Identifier for the setting. (See the gamemode config.) + * @return Value of the requested setting, 0 if unknown setting. + */ + int getIntegerSetting(String ident); + + /** + * @param ident Identifier for the setting. (See the gamemode config.) + * @return Value of the requested setting, 0 if unknown setting. + */ + float getFloatSetting(String ident); + + /** + * @param ident Identifier for the setting. (See the gamemode config.) + * @return Value of the requested setting, an itemstack containing an apple if unknown setting. + */ + ItemStack getStackSetting(String ident); + +} diff --git a/forestry_common/core/forestry/api/core/IIconProvider.java b/forestry_common/core/forestry/api/core/IIconProvider.java new file mode 100755 index 000000000..348abd184 --- /dev/null +++ b/forestry_common/core/forestry/api/core/IIconProvider.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Provides icons, needed in some interfaces, most notably for bees and trees. + */ +public interface IIconProvider { + + @SideOnly(Side.CLIENT) + IIcon getIcon(short texUID); + + @SideOnly(Side.CLIENT) + void registerIcons(IIconRegister register); + +} diff --git a/forestry_common/core/forestry/api/core/INBTTagable.java b/forestry_common/core/forestry/api/core/INBTTagable.java new file mode 100755 index 000000000..2b68734cf --- /dev/null +++ b/forestry_common/core/forestry/api/core/INBTTagable.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.nbt.NBTTagCompound; + +public interface INBTTagable { + void readFromNBT(NBTTagCompound nbttagcompound); + + void writeToNBT(NBTTagCompound nbttagcompound); +} diff --git a/forestry_common/core/forestry/api/core/IPlugin.java b/forestry_common/core/forestry/api/core/IPlugin.java new file mode 100755 index 000000000..4412ef3b3 --- /dev/null +++ b/forestry_common/core/forestry/api/core/IPlugin.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +/** + * Optional way to hook into Forestry. + * + * Plugin classes can reside in any package, their class name however has to start with 'Plugin', i.e. 'PluginMyStuff'. + * + * @author SirSengir + */ +public interface IPlugin { + + /** + * @return true if the plugin is to be loaded. + */ + public boolean isAvailable(); + + /** + * Called during Forestry's @PreInit. + */ + public void preInit(); + + /** + * Called at the start of Forestry's @PostInit. + */ + public void doInit(); + + /** + * Called at the end of Forestry's @PostInit. + */ + public void postInit(); + +} diff --git a/forestry_common/core/forestry/api/core/IStructureLogic.java b/forestry_common/core/forestry/api/core/IStructureLogic.java new file mode 100755 index 000000000..cd55c5301 --- /dev/null +++ b/forestry_common/core/forestry/api/core/IStructureLogic.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +public interface IStructureLogic extends INBTTagable { + + /** + * @return String unique to the type of structure controlled by this structure logic. + */ + String getTypeUID(); + + /** + * Called by {@link ITileStructure}'s validateStructure(). + */ + void validateStructure(); + +} diff --git a/forestry_common/core/forestry/api/core/ITextureManager.java b/forestry_common/core/forestry/api/core/ITextureManager.java new file mode 100755 index 000000000..a956d2439 --- /dev/null +++ b/forestry_common/core/forestry/api/core/ITextureManager.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public interface ITextureManager { + + void registerIconProvider(IIconProvider provider); + + IIcon getIcon(short texUID); + + IIcon getDefault(String ident); +} diff --git a/forestry_common/core/forestry/api/core/ITileStructure.java b/forestry_common/core/forestry/api/core/ITileStructure.java new file mode 100755 index 000000000..f4909dde8 --- /dev/null +++ b/forestry_common/core/forestry/api/core/ITileStructure.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.inventory.IInventory; +import net.minecraft.tileentity.TileEntity; + +/** + * The basis for multiblock components. + */ +public interface ITileStructure { + + /** + * @return String unique to the type of structure controlled by this structure logic. Should map to {@link IStructureLogic} + */ + String getTypeUID(); + + /** + * Should map to {@link IStructureLogic} + */ + void validateStructure(); + + /** + * Called when the structure resets. + */ + void onStructureReset(); + + /** + * @return TileEntity that is the master in this structure, null if no structure exists. + */ + ITileStructure getCentralTE(); + + /** + * Called to set the master TileEntity. Implementing TileEntity should keep track of the master's coordinates, not refer to the TE object itself. + * + * @param tile + */ + void setCentralTE(TileEntity tile); + + /** + * @return IInventory representing the TE's inventory. + */ + IInventory getInventory(); + + /** + * Only called on Forestry's own blocks. + */ + void makeMaster(); + + /** + * @return true if this TE is the master in a structure, false otherwise. + */ + boolean isMaster(); + + /** + * @return true if the TE is master or has a master. + */ + boolean isIntegratedIntoStructure(); + +} diff --git a/forestry_common/core/forestry/api/core/IToolScoop.java b/forestry_common/core/forestry/api/core/IToolScoop.java new file mode 100755 index 000000000..516a36025 --- /dev/null +++ b/forestry_common/core/forestry/api/core/IToolScoop.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +/** + * Marks a tool as a scoop. + */ +public interface IToolScoop { + +} diff --git a/forestry_common/core/forestry/api/core/ItemInterface.java b/forestry_common/core/forestry/api/core/ItemInterface.java new file mode 100755 index 000000000..3d6423528 --- /dev/null +++ b/forestry_common/core/forestry/api/core/ItemInterface.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import java.lang.reflect.Method; + +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.FMLLog; + +/** + * This is going away someday, use FML's GameRegistry instead. + * @deprecated + */ +@Deprecated +public class ItemInterface { + + /** + * Get items here! + * + * Blocks currently not supported. + * + * @param ident + * @return ItemStack representing the item, null if not found. + */ + public static ItemStack getItem(String ident) { + ItemStack item = null; + + try { + String pack = ItemInterface.class.getPackage().getName(); + pack = pack.substring(0, pack.lastIndexOf('.')); + String itemClass = pack.substring(0, pack.lastIndexOf('.')) + ".core.config.ForestryItem"; + Object[] enums = Class.forName(itemClass).getEnumConstants(); + for (Object e : enums) { + if (e.toString().equals(ident)) { + Method m = e.getClass().getMethod("getItemStack"); + return (ItemStack) m.invoke(e); + } + } + } catch (Exception ex) { + FMLLog.warning("Could not retrieve Forestry item identified by: " + ident); + } + + return item; + } +} diff --git a/forestry_common/core/forestry/api/core/PluginInfo.java b/forestry_common/core/forestry/api/core/PluginInfo.java new file mode 100755 index 000000000..ac6f3028e --- /dev/null +++ b/forestry_common/core/forestry/api/core/PluginInfo.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Optional annotation to provide additional information on IPlugins. This information will be available via the "/forestry plugin info $pluginID" command ingame. + * + * @author SirSengir + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface PluginInfo { + + /** + * @return Unique identifier for the plugin, no spaces! + */ + String pluginID(); + + /** + * @return Nice and readable plugin name. + */ + String name(); + + /** + * @return Plugin author's name. + */ + String author() default ""; + + /** + * @return URL of plugin homepage. + */ + String url() default ""; + + /** + * @return Version of the plugin, if any. + */ + String version() default ""; + + /** + * @return Short description what the plugin does. + */ + String description() default ""; + + /** + * @return Not used (yet?). + */ + String help() default ""; + +} diff --git a/forestry_common/core/forestry/api/core/Tabs.java b/forestry_common/core/forestry/api/core/Tabs.java new file mode 100755 index 000000000..c8b178d62 --- /dev/null +++ b/forestry_common/core/forestry/api/core/Tabs.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.creativetab.CreativeTabs; + +/** + * References to the specialised tabs added by Forestry to creative inventory. + */ +public class Tabs { + + public static CreativeTabs tabApiculture; + public static CreativeTabs tabArboriculture; + public static CreativeTabs tabLepidopterology; + +} diff --git a/forestry_common/core/forestry/api/core/package-info.java b/forestry_common/core/forestry/api/core/package-info.java new file mode 100755 index 000000000..428939f4f --- /dev/null +++ b/forestry_common/core/forestry/api/core/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="Forestry", provides="ForestryAPI|core") +package forestry.api.core; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/farming/Farmables.java b/forestry_common/core/forestry/api/farming/Farmables.java new file mode 100755 index 000000000..26b7eec2c --- /dev/null +++ b/forestry_common/core/forestry/api/farming/Farmables.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import java.util.Collection; +import java.util.HashMap; + +public class Farmables { + /** + * Can be used to add IFarmables to some of the vanilla farm logics. + * + * Identifiers: farmArboreal farmWheat farmGourd farmInfernal farmPoales farmSucculentes farmVegetables farmShroom + */ + public static HashMap> farmables = new HashMap>(); + + public static IFarmInterface farmInterface; +} diff --git a/forestry_common/core/forestry/api/farming/ICrop.java b/forestry_common/core/forestry/api/farming/ICrop.java new file mode 100755 index 000000000..61f6ffceb --- /dev/null +++ b/forestry_common/core/forestry/api/farming/ICrop.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; + +public interface ICrop { + + /** + * Harvests this crop. Performs the necessary manipulations to set the crop into a "harvested" state. + * + * @return Products harvested. + */ + Collection harvest(); + +} diff --git a/forestry_common/core/forestry/api/farming/IFarmComponent.java b/forestry_common/core/forestry/api/farming/IFarmComponent.java new file mode 100755 index 000000000..4704fab8e --- /dev/null +++ b/forestry_common/core/forestry/api/farming/IFarmComponent.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import forestry.api.core.ITileStructure; + +public interface IFarmComponent extends ITileStructure { + + boolean hasFunction(); + + void registerListener(IFarmListener listener); + + void removeListener(IFarmListener listener); +} diff --git a/forestry_common/core/forestry/api/farming/IFarmHousing.java b/forestry_common/core/forestry/api/farming/IFarmHousing.java new file mode 100755 index 000000000..6f1e00349 --- /dev/null +++ b/forestry_common/core/forestry/api/farming/IFarmHousing.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +public interface IFarmHousing { + + int[] getCoords(); + + int[] getArea(); + + int[] getOffset(); + + World getWorld(); + + /** + * Will run the work cycle on a master TE. Will do nothing on any other farm component. + * + * @return true if any work was done, false otherwise. + */ + boolean doWork(); + + boolean hasLiquid(FluidStack liquid); + + void removeLiquid(FluidStack liquid); + + boolean hasResources(ItemStack[] resources); + + void removeResources(ItemStack[] resources); + + /** + * Callback for {@link IFarmLogic}s to plant a sapling, seed, germling, stem. Will remove the appropriate germling from the farm's inventory. It's up to the + * logic to only call this on a valid location. + * + * @param farmable + * @param world + * @param x + * @param y + * @param z + * @return true if planting was successful, false otherwise. + */ + boolean plantGermling(IFarmable farmable, World world, int x, int y, int z); + + /* INTERACTION WITH HATCHES */ + boolean acceptsAsGermling(ItemStack itemstack); + + boolean acceptsAsResource(ItemStack itemstack); + + boolean acceptsAsFertilizer(ItemStack itemstack); + + /* LOGIC */ + /** + * Set a farm logic for the given direction. UP/DOWN/UNKNOWN are invalid! + * + * @param direction + * @param logic + */ + void setFarmLogic(ForgeDirection direction, IFarmLogic logic); + + /** + * Reset the farm logic for the given direction to default. UP/DOWN/UNKNOWN are invalid! + * + * @param direction + */ + void resetFarmLogic(ForgeDirection direction); +} diff --git a/forestry_common/core/forestry/api/farming/IFarmInterface.java b/forestry_common/core/forestry/api/farming/IFarmInterface.java new file mode 100755 index 000000000..ae851df0e --- /dev/null +++ b/forestry_common/core/forestry/api/farming/IFarmInterface.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import forestry.api.core.IStructureLogic; + +public interface IFarmInterface { + + /** + * Creates {@link IStructureLogic} for use in farm components. + * + * @param structure + * {@link IFarmComponent} to create the logic for. + * @return {@link IStructureLogic} for use in farm components + */ + IStructureLogic createFarmStructureLogic(IFarmComponent structure); +} diff --git a/forestry_common/core/forestry/api/farming/IFarmListener.java b/forestry_common/core/forestry/api/farming/IFarmListener.java new file mode 100755 index 000000000..e9f8e0718 --- /dev/null +++ b/forestry_common/core/forestry/api/farming/IFarmListener.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface IFarmListener { + + /** + * Called before a crop is harvested. + * + * @param crop + * ICrop about to be harvested. + * @return true to cancel further processing of this crop. + */ + boolean beforeCropHarvest(ICrop crop); + + /** + * Called after a crop has been harvested, but before harvested items are stowed in the farms inventory. + * + * @param harvested + * Collection of harvested stacks. May be manipulated. Ensure removal of stacks with 0 or less items! + * @param crop + * Harvested {@link ICrop} + */ + void afterCropHarvest(Collection harvested, ICrop crop); + + /** + * Called after the stack of collected items has been returned by the farm logic, but before it is added to the farm's pending queue. + * + * @param collected + * Collection of collected stacks. May be manipulated. Ensure removal of stacks with 0 or less items! + * @param logic + */ + void hasCollected(Collection collected, IFarmLogic logic); + + /** + * Called after farmland has successfully been cultivated by a farm logic. + * + * @param logic + * @param x + * @param y + * @param z + * @param direction + * @param extent + */ + void hasCultivated(IFarmLogic logic, int x, int y, int z, ForgeDirection direction, int extent); + + /** + * Called after the stack of harvested crops has been returned by the farm logic, but before it is added to the farm's pending queue. + * + * @param harvested + * @param logic + * @param x + * @param y + * @param z + * @param direction + * @param extent + */ + void hasScheduledHarvest(Collection harvested, IFarmLogic logic, int x, int y, int z, ForgeDirection direction, int extent); + + /** + * Can be used to cancel farm task on a per side/{@link IFarmLogic} basis. + * + * @param logic + * @param direction + * @return true to skip any work action on the given logic and direction for this work cycle. + */ + boolean cancelTask(IFarmLogic logic, ForgeDirection direction); +} diff --git a/forestry_common/core/forestry/api/farming/IFarmLogic.java b/forestry_common/core/forestry/api/farming/IFarmLogic.java new file mode 100755 index 000000000..5d4d93b6b --- /dev/null +++ b/forestry_common/core/forestry/api/farming/IFarmLogic.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface IFarmLogic { + + int getFertilizerConsumption(); + + int getWaterConsumption(float hydrationModifier); + + boolean isAcceptedResource(ItemStack itemstack); + + boolean isAcceptedGermling(ItemStack itemstack); + + Collection collect(); + + boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent); + + Collection harvest(int x, int y, int z, ForgeDirection direction, int extent); + + @SideOnly(Side.CLIENT) + IIcon getIcon(); + + ResourceLocation getSpriteSheet(); + + String getName(); +} diff --git a/forestry_common/core/forestry/api/farming/IFarmable.java b/forestry_common/core/forestry/api/farming/IFarmable.java new file mode 100755 index 000000000..4b5cb8e26 --- /dev/null +++ b/forestry_common/core/forestry/api/farming/IFarmable.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.farming; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * IGermling describes a crop or other harvestable object and can be used to inspect item stacks and blocks for matches. + */ +public interface IFarmable { + + /** + * @param world + * @param x + * @param y + * @param z + * @return true if the block at the given location is a "sapling" for this type, i.e. a non-harvestable immature version of the crop. + */ + boolean isSaplingAt(World world, int x, int y, int z); + + /** + * @param world + * @param x + * @param y + * @param z + * @return {@link ICrop} if the block at the given location is a harvestable and mature crop, null otherwise. + */ + ICrop getCropAt(World world, int x, int y, int z); + + /** + * @param itemstack + * @return true if the item is a valid germling (plantable sapling, seed, etc.) for this type. + */ + boolean isGermling(ItemStack itemstack); + + /** + * @param itemstack + * @return true if the item is something that can drop from this type without actually being harvested as a crop. (Apples or sapling from decaying leaves.) + */ + boolean isWindfall(ItemStack itemstack); + + /** + * Plants a sapling by manipulating the world. The {@link IFarmLogic} should have verified the given location as valid. Called by the {@link IFarmHousing} + * which handles resources. + * + * @param germling + * @param world + * @param x + * @param y + * @param z + * @return true on success, false otherwise. + */ + boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z); + +} diff --git a/forestry_common/core/forestry/api/farming/package-info.java b/forestry_common/core/forestry/api/farming/package-info.java new file mode 100755 index 000000000..fc275cf88 --- /dev/null +++ b/forestry_common/core/forestry/api/farming/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|farming") +package forestry.api.farming; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/food/BeverageManager.java b/forestry_common/core/forestry/api/food/BeverageManager.java new file mode 100755 index 000000000..0dca04903 --- /dev/null +++ b/forestry_common/core/forestry/api/food/BeverageManager.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.food; + +public class BeverageManager { + public static IBeverageEffect[] effectList = new IBeverageEffect[128]; + + public static IInfuserManager infuserManager; + public static IIngredientManager ingredientManager; +} diff --git a/forestry_common/core/forestry/api/food/IBeverageEffect.java b/forestry_common/core/forestry/api/food/IBeverageEffect.java new file mode 100755 index 000000000..f93f8ee27 --- /dev/null +++ b/forestry_common/core/forestry/api/food/IBeverageEffect.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.food; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +public interface IBeverageEffect { + int getId(); + + void doEffect(World world, EntityPlayer player); + + String getDescription(); +} diff --git a/forestry_common/core/forestry/api/food/IInfuserManager.java b/forestry_common/core/forestry/api/food/IInfuserManager.java new file mode 100755 index 000000000..18756ef09 --- /dev/null +++ b/forestry_common/core/forestry/api/food/IInfuserManager.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.food; + +import net.minecraft.item.ItemStack; + +public interface IInfuserManager { + + void addMixture(int meta, ItemStack ingredient, IBeverageEffect effect); + + void addMixture(int meta, ItemStack[] ingredients, IBeverageEffect effect); + + ItemStack getSeasoned(ItemStack base, ItemStack[] ingredients); + + boolean hasMixtures(ItemStack[] ingredients); + + ItemStack[] getRequired(ItemStack[] ingredients); + +} diff --git a/forestry_common/core/forestry/api/food/IIngredientManager.java b/forestry_common/core/forestry/api/food/IIngredientManager.java new file mode 100755 index 000000000..20ff837a8 --- /dev/null +++ b/forestry_common/core/forestry/api/food/IIngredientManager.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.food; + +import net.minecraft.item.ItemStack; + +public interface IIngredientManager { + + String getDescription(ItemStack itemstack); + + void addIngredient(ItemStack ingredient, String description); + +} diff --git a/forestry_common/core/forestry/api/food/package-info.java b/forestry_common/core/forestry/api/food/package-info.java new file mode 100755 index 000000000..6a02d6d15 --- /dev/null +++ b/forestry_common/core/forestry/api/food/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|food") +package forestry.api.food; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/fuels/EngineBronzeFuel.java b/forestry_common/core/forestry/api/fuels/EngineBronzeFuel.java new file mode 100755 index 000000000..f7e615bee --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/EngineBronzeFuel.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.fuels; + +import net.minecraftforge.fluids.Fluid; + +public class EngineBronzeFuel { + /** + * Item that is valid fuel for a biogas engine. + */ + public final Fluid liquid; + /** + * Power produced by this fuel per work cycle of the engine. + */ + public final int powerPerCycle; + /** + * How many work cycles a single "stack" of this type lasts. + */ + public final int burnDuration; + /** + * By how much the normal heat dissipation rate of 1 is multiplied when using this fuel type. + */ + public final int dissipationMultiplier; + + public EngineBronzeFuel(Fluid liquid, int powerPerCycle, int burnDuration, int dissipationMultiplier) { + this.liquid = liquid; + this.powerPerCycle = powerPerCycle; + this.burnDuration = burnDuration; + this.dissipationMultiplier = dissipationMultiplier; + } +} diff --git a/forestry_common/core/forestry/api/fuels/EngineCopperFuel.java b/forestry_common/core/forestry/api/fuels/EngineCopperFuel.java new file mode 100755 index 000000000..e5dc9a266 --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/EngineCopperFuel.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.fuels; + +import net.minecraft.item.ItemStack; + +public class EngineCopperFuel { + + /** + * Item that is valid fuel for a peat-fired engine. + */ + public final ItemStack fuel; + /** + * Power produced by this fuel per work cycle. + */ + public final int powerPerCycle; + /** + * Amount of work cycles this item lasts before being consumed. + */ + public final int burnDuration; + + public EngineCopperFuel(ItemStack fuel, int powerPerCycle, int burnDuration) { + this.fuel = fuel; + this.powerPerCycle = powerPerCycle; + this.burnDuration = burnDuration; + } + +} diff --git a/forestry_common/core/forestry/api/fuels/FermenterFuel.java b/forestry_common/core/forestry/api/fuels/FermenterFuel.java new file mode 100755 index 000000000..b3ac01285 --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/FermenterFuel.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.fuels; + +import net.minecraft.item.ItemStack; + +public class FermenterFuel { + /** + * Item that is a valid fuel for the fermenter (i.e. fertilizer). + */ + public final ItemStack item; + /** + * How much is fermeted per work cycle, i.e. how much biomass is produced per cycle. + */ + public final int fermentPerCycle; + /** + * Amount of work cycles a single item of this fuel lasts before expiring. + */ + public final int burnDuration; + + public FermenterFuel(ItemStack item, int fermentPerCycle, int burnDuration) { + this.item = item; + this.fermentPerCycle = fermentPerCycle; + this.burnDuration = burnDuration; + } +} diff --git a/forestry_common/core/forestry/api/fuels/FuelManager.java b/forestry_common/core/forestry/api/fuels/FuelManager.java new file mode 100755 index 000000000..bdb1e747f --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/FuelManager.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.fuels; + +import java.util.HashMap; + + +public class FuelManager { + /** + * Add new fuels for the fermenter here (i.e. fertilizer). Will accept Items, ItemStacks and Strings (Ore Dictionary) + */ + public static HashMap fermenterFuel; + /** + * Add new resources for the moistener here (i.e. wheat) + */ + public static HashMap moistenerResource; + /** + * Add new substrates for the rainmaker here + */ + public static HashMap rainSubstrate; + /** + * Add new fuels for EngineBronze (= biogas engine) here + */ + public static HashMap bronzeEngineFuel; + /** + * Add new fuels for EngineCopper (= peat-fired engine) here + */ + public static HashMap copperEngineFuel; + + // Generator fuel list in GeneratorFuel.class +} diff --git a/forestry_common/core/forestry/api/fuels/GeneratorFuel.java b/forestry_common/core/forestry/api/fuels/GeneratorFuel.java new file mode 100755 index 000000000..97546261a --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/GeneratorFuel.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.fuels; + +import java.util.HashMap; + +import net.minecraftforge.fluids.FluidStack; + +public class GeneratorFuel { + + public static HashMap fuels = new HashMap(); + + /** + * LiquidStack representing the fuel type and amount consumed per triggered cycle. + */ + public final FluidStack fuelConsumed; + /** + * EU emitted per tick while this fuel is being consumed in the generator (i.e. biofuel = 32, biomass = 8). + */ + public final int eu; + /** + * Rate at which the fuel is consumed. 1 - Every tick 2 - Every second tick 3 - Every third tick etc. + */ + public final int rate; + + public GeneratorFuel(FluidStack fuelConsumed, int eu, int rate) { + this.fuelConsumed = fuelConsumed; + this.eu = eu; + this.rate = rate; + } + +} diff --git a/forestry_common/core/forestry/api/fuels/MoistenerFuel.java b/forestry_common/core/forestry/api/fuels/MoistenerFuel.java new file mode 100755 index 000000000..e5f3c4ca4 --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/MoistenerFuel.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.fuels; + +import net.minecraft.item.ItemStack; + +public class MoistenerFuel { + /** + * The item to use + */ + public final ItemStack item; + /** + * The item that leaves the moistener's working slot (i.e. mouldy wheat, decayed wheat, mulch) + */ + public final ItemStack product; + /** + * How much this item contributes to the final product of the moistener (i.e. mycelium) + */ + public final int moistenerValue; + /** + * What stage this product represents. Resources with lower stage value will be consumed first. + */ + public final int stage; + + public MoistenerFuel(ItemStack item, ItemStack product, int stage, int moistenerValue) { + this.item = item; + this.product = product; + this.stage = stage; + this.moistenerValue = moistenerValue; + } +} diff --git a/forestry_common/core/forestry/api/fuels/RainSubstrate.java b/forestry_common/core/forestry/api/fuels/RainSubstrate.java new file mode 100755 index 000000000..f35a6bd66 --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/RainSubstrate.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.fuels; + +import net.minecraft.item.ItemStack; + +public class RainSubstrate { + /** + * Rain substrate capable of activating the rainmaker. + */ + public ItemStack item; + /** + * Duration of the rain shower triggered by this substrate in Minecraft ticks. + */ + public int duration; + /** + * Speed of activation sequence triggered. + */ + public float speed; + + public boolean reverse; + + public RainSubstrate(ItemStack item, int duration, float speed) { + this(item, duration, speed, false); + } + + public RainSubstrate(ItemStack item, float speed) { + this(item, 0, speed, true); + } + + public RainSubstrate(ItemStack item, int duration, float speed, boolean reverse) { + this.item = item; + this.duration = duration; + this.speed = speed; + this.reverse = reverse; + } +} diff --git a/forestry_common/core/forestry/api/fuels/package-info.java b/forestry_common/core/forestry/api/fuels/package-info.java new file mode 100755 index 000000000..73f086aa8 --- /dev/null +++ b/forestry_common/core/forestry/api/fuels/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|fuels") +package forestry.api.fuels; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/genetics/AlleleManager.java b/forestry_common/core/forestry/api/genetics/AlleleManager.java new file mode 100755 index 000000000..15d4ed5d6 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/AlleleManager.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.HashMap; + +import net.minecraft.item.ItemStack; + +/** + * Holds a static reference to the {@link IAlleleRegistry}. + */ +public class AlleleManager { + /** + * Main access point for all things related to genetics. See {@link IAlleleRegistry} for details. + */ + public static IAlleleRegistry alleleRegistry; + /** + * Translates plain leaf blocks into genetic data. Used by bees and butterflies to convert and pollinate foreign leaf blocks. + */ + public static HashMap ersatzSpecimen = new HashMap(); + /** + * Translates plain saplings into genetic data. Used by the treealyzer and the farm to convert foreign saplings. + */ + public static HashMap ersatzSaplings = new HashMap(); + +} diff --git a/forestry_common/core/forestry/api/genetics/EnumTolerance.java b/forestry_common/core/forestry/api/genetics/EnumTolerance.java new file mode 100755 index 000000000..09d3da3df --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/EnumTolerance.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +public enum EnumTolerance { + NONE, + + BOTH_1, BOTH_2, BOTH_3, BOTH_4, BOTH_5, + + UP_1, UP_2, UP_3, UP_4, UP_5, + + DOWN_1, DOWN_2, DOWN_3, DOWN_4, DOWN_5 +} diff --git a/forestry_common/core/forestry/api/genetics/IAllele.java b/forestry_common/core/forestry/api/genetics/IAllele.java new file mode 100755 index 000000000..23902f493 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAllele.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * An {@link IIndividual}'s {@link IGenome} is composed of {@link IChromosome}s consisting each of a primary and secondary {@link IAllele}. + * + * {@link IAllele}s hold all information regarding an {@link IIndividual}'s traits, from species to size, temperature tolerances, etc. + * + * Should be extended for different types of alleles. ISpeciesAllele, IBiomeAllele, etc. + * + * @author SirSengir + */ +public interface IAllele { + + /** + * @return A unique string identifier for this allele. + */ + String getUID(); + + /** + * @return true if the allele is dominant, false otherwise. + */ + boolean isDominant(); + + /** + * @return Localized short, human-readable identifier used in tooltips and beealyzer. + */ + String getName(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleArea.java b/forestry_common/core/forestry/api/genetics/IAlleleArea.java new file mode 100755 index 000000000..fd4b0339c --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleArea.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleArea extends IAllele { + + int[] getValue(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleBoolean.java b/forestry_common/core/forestry/api/genetics/IAlleleBoolean.java new file mode 100755 index 000000000..29a6787e5 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleBoolean.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleBoolean extends IAllele { + + boolean getValue(); + + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleEffect.java b/forestry_common/core/forestry/api/genetics/IAlleleEffect.java new file mode 100755 index 000000000..3c03a7c1c --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleEffect.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Basic effect allele. + */ +public interface IAlleleEffect extends IAllele { + /** + * @return true if this effect can combine with the effect on other allele (i.e. run before or after). combination can only occur if both effects are + * combinable. + */ + boolean isCombinable(); + + /** + * Returns the passed data storage if it is valid for this effect or a new one if the passed storage object was invalid for this effect. + * + * @param storedData + * @return {@link IEffectData} for the next cycle. + */ + IEffectData validateStorage(IEffectData storedData); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleFloat.java b/forestry_common/core/forestry/api/genetics/IAlleleFloat.java new file mode 100755 index 000000000..8124f0a76 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleFloat.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleFloat extends IAllele { + + float getValue(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleFlowers.java b/forestry_common/core/forestry/api/genetics/IAlleleFlowers.java new file mode 100755 index 000000000..45ef918cb --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleFlowers.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + + +public interface IAlleleFlowers extends IAllele { + + /** + * @return FlowerProvider + */ + IFlowerProvider getProvider(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleHandler.java b/forestry_common/core/forestry/api/genetics/IAlleleHandler.java new file mode 100755 index 000000000..19d829e17 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleHandler.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * @author Alex Binnie + * + * Handler for events that occur in IAlleleRegistry, such as registering alleles, branches etc. Useful for handling plugin specific behavior (i.e. + * creating a list of all bee species etc.) + * + */ +public interface IAlleleHandler { + + /** + * Called when an allele is registered with {@link IAlleleRegistry}. + * + * @param allele + * Allele which was registered. + */ + public void onRegisterAllele(IAllele allele); + + /** + * Called when a classification is registered with {@link IAlleleRegistry}. + * + * @param classification + * Classification which was registered. + */ + public void onRegisterClassification(IClassification classification); + + /** + * Called when a fruit family is registered with {@link IAlleleRegistry}. + * + * @param family + * Fruit family which was registered. + */ + public void onRegisterFruitFamily(IFruitFamily family); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleInteger.java b/forestry_common/core/forestry/api/genetics/IAlleleInteger.java new file mode 100755 index 000000000..e45e16b12 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleInteger.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing integer values. + */ +public interface IAlleleInteger extends IAllele { + + int getValue(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAllelePlantType.java b/forestry_common/core/forestry/api/genetics/IAllelePlantType.java new file mode 100755 index 000000000..f292b3588 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAllelePlantType.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.EnumSet; + +import net.minecraftforge.common.EnumPlantType; + +public interface IAllelePlantType extends IAllele { + + public EnumSet getPlantTypes(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleRegistry.java b/forestry_common/core/forestry/api/genetics/IAlleleRegistry.java new file mode 100755 index 000000000..1f0c21177 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleRegistry.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.Collection; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.genetics.IClassification.EnumClassLevel; + +/** + * Manages {@link ISpeciesRoot}, {@link IAllele}s, {@link IFruitFamily}s, {@link IClassification}, the blacklist and allows creation of research notes. + * + * @author SirSengir + */ +public interface IAlleleRegistry { + + /* SPECIES ROOT CLASSES */ + /** + * Register a {@link ISpeciesRoot}. + * @param root {@link ISpeciesRoot} to register. + */ + void registerSpeciesRoot(ISpeciesRoot root); + + /** + * @return Map of all registered {@link ISpeciesRoot}. + */ + Map getSpeciesRoot(); + + /** + * Retrieve the {@link ISpeciesRoot} with the given uid. + * @param uid Unique id for the species class, i.e. "rootBees", "rootTrees", "rootButterflies". + * @return {@link ISpeciesRoot} if it exists, null otherwise. + */ + ISpeciesRoot getSpeciesRoot(String uid); + + /** + * Retrieve a matching {@link ISpeciesRoot} for the given itemstack. + * @param stack An itemstack possibly containing NBT data which can be converted by a species root. + * @return {@link ISpeciesRoot} if found, null otherwise. + */ + ISpeciesRoot getSpeciesRoot(ItemStack stack); + + /** + * Retrieve a matching {@link ISpeciesRoot} for the given {@link IIndividual}-class. + * @param clz Class extending {@link IIndividual}. + * @return {@link ISpeciesRoot} if found, null otherwise. + */ + ISpeciesRoot getSpeciesRoot(Class clz); + + /* INDIVIDUAL */ + /** + * Tests the itemstack for genetic information. + * + * @param stack + * @return true if the itemstack is an individual. + */ + boolean isIndividual(ItemStack stack); + + /** + * Retrieve genetic information from an itemstack. + * + * @param stack + * Stack to retrieve genetic information for. + * @return IIndividual containing genetic information, null if none could be extracted. + */ + IIndividual getIndividual(ItemStack stack); + + /* ALLELES */ + + /** + * @return HashMap of all currently registered alleles. + */ + Map getRegisteredAlleles(); + + /** + * Registers an allele. + * + * @param allele + * IAllele to register. + */ + void registerAllele(IAllele allele); + + /** + * @return HashMap of all registered deprecated alleles and their corresponding replacements + */ + Map getDeprecatedAlleleReplacements(); + + /** + * Registers an old allele UID and the new IAllele to replace instances of it with. + * + * @param deprecatedAlleleUID + * the old allele's UID + * @param replacement + * the IAllele that the deprecated Allele will be replaced with. + */ + void registerDeprecatedAlleleReplacement(String deprecatedAlleleUID, IAllele replacement); + + /** + * Gets an allele + * + * @param uid + * String based unique identifier of the allele to retrieve. + * @return IAllele if found or a replacement is found in the Deprecated Allele map, null otherwise. + */ + IAllele getAllele(String uid); + + /* THIS SHOULD BE PHASED OUT */ + @Deprecated + void reloadMetaMap(World world); + + @Deprecated + IAllele getFromMetaMap(int meta); + + @Deprecated + int getFromUIDMap(String uid); + + /* CLASSIFICATIONS */ + /** + * @return HashMap of all currently registered classifications. + */ + Map getRegisteredClassifications(); + + /** + * Registers a classification. + * + * @param classification + * IClassification to register. + */ + void registerClassification(IClassification classification); + + /** + * Creates and returns a classification. + * + * @param level + * EnumClassLevel of the classification to create. + * @param uid + * String based unique identifier. Implementation will throw an exception if the key is already taken. + * @param scientific + * Binomial for the given classification. + * @return Created {@link IClassification} for easier chaining. + */ + IClassification createAndRegisterClassification(EnumClassLevel level, String uid, String scientific); + + /** + * Gets a classification. + * + * @param uid + * String based unique identifier of the classification to retrieve. + * @return {@link IClassification} if found, null otherwise. + */ + IClassification getClassification(String uid); + + /* FRUIT FAMILIES */ + /** + * Get all registered fruit families. + * + * @return A map of registered fruit families and their UIDs. + */ + Map getRegisteredFruitFamilies(); + + /** + * Registers a new fruit family. + * + * @param family + */ + void registerFruitFamily(IFruitFamily family); + + /** + * Retrieves a fruit family identified by uid. + * + * @param uid + * @return {IFruitFamily} if found, false otherwise. + */ + IFruitFamily getFruitFamily(String uid); + + /* ALLELE HANDLERS */ + /** + * Registers a new IAlleleHandler + * + * @param handler + * IAlleleHandler to register. + */ + void registerAlleleHandler(IAlleleHandler handler); + + /* BLACKLIST */ + /** + * Blacklist an allele identified by its UID from mutation. + * + * @param uid + * UID of the allele to blacklist. + */ + void blacklistAllele(String uid); + + /** + * @return Current blacklisted alleles. + */ + Collection getAlleleBlacklist(); + + /** + * @param uid + * UID of the species to vet. + * @return true if the allele is blacklisted. + */ + boolean isBlacklisted(String uid); + + /* RESEARCH */ + /** + * @param researcher Username of the player who researched this note. + * @param species {@link IAlleleSpecies} to encode on the research note. + * @return An itemstack containing a research note with the given species encoded onto it. + */ + ItemStack getSpeciesNoteStack(String researcher, IAlleleSpecies species); + + /** + * @param researcher Username of the player who researched this note. + * @param mutation {@link IMutation} to encode on the research note. + * @return An itemstack containing a research note with the given mutation encoded onto it. + */ + ItemStack getMutationNoteStack(String researcher, IMutation mutation); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleSpecies.java b/forestry_common/core/forestry/api/genetics/IAlleleSpecies.java new file mode 100755 index 000000000..d14082a45 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleSpecies.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.IIconProvider; + +/** + * Basic species allele. + */ +public interface IAlleleSpecies extends IAllele { + + /** + * @return the {@link ISpeciesRoot} associated with this species. + */ + ISpeciesRoot getRoot(); + + /** + * @return Localized short description of this species. (May be null.) + */ + String getDescription(); + + /** + * Binomial name of the species sans genus ("Apis"). Returning "humboldti" will have the bee species flavour name be "Apis humboldti". Feel free to use fun + * names or return null. + * + * @return flavour text (may be null) + */ + String getBinomial(); + + /** + * Authority for the binomial name, e.g. "Sengir" on species of base Forestry. + * + * @return flavour text (may be null) + */ + String getAuthority(); + + /** + * @return Branch this species is associated with. + */ + IClassification getBranch(); + + /* RESEARCH */ + /** + * Complexity determines the difficulty researching a species. The values of primary and secondary are + * added together (and rounded) to determine the amount of pairs needed for successful research. + * @return Values between 3 - 11 are useful. + */ + int getComplexity(); + + /** + * @param itemstack + * @return A float signifying the chance for the passed itemstack to yield a research success. + */ + float getResearchSuitability(ItemStack itemstack); + + /** + * @param world + * @param researcher + * @param individual + * @param bountyLevel + * @return Array of itemstacks representing the bounty for this research success. + */ + ItemStack[] getResearchBounty(World world, String researcher, IIndividual individual, int bountyLevel); + + /* CLIMATE */ + /** + * @return Preferred temperature + */ + EnumTemperature getTemperature(); + + /** + * @return Preferred humidity + */ + EnumHumidity getHumidity(); + + /* MISC */ + /** + * @return true if the species icon should have a glowing effect. + */ + boolean hasEffect(); + + /** + * @return true if the species should not be displayed in NEI or creative inventory. + */ + boolean isSecret(); + + /** + * @return true to have the species count against the species total. + */ + boolean isCounted(); + + /* APPEARANCE */ + /** + * @param renderPass Render pass to get the colour for. + * @return Colour to use for the render pass. + */ + int getIconColour(int renderPass); + + @SideOnly(Side.CLIENT) + IIconProvider getIconProvider(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IAlleleTolerance.java b/forestry_common/core/forestry/api/genetics/IAlleleTolerance.java new file mode 100755 index 000000000..e00d9fd28 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IAlleleTolerance.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleTolerance extends IAllele { + + EnumTolerance getValue(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IBreedingTracker.java b/forestry_common/core/forestry/api/genetics/IBreedingTracker.java new file mode 100755 index 000000000..b8b5a8d7d --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IBreedingTracker.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.apiculture.IBeekeepingMode; + +/** + * Keeps track of who bred and/or discovered which species in a world. + * + * @author SirSengir + */ +public interface IBreedingTracker { + + /** + * @return Name of the current {@link IBeekeepingMode}. + */ + String getModeName(); + + /** + * Set the current {@link IBeekeepingMode}. + */ + void setModeName(String name); + + /** + * @return Amount of species discovered. + */ + int getSpeciesBred(); + + /** + * Register the birth of an individual. Will mark it as discovered. + * + * @param individual + */ + void registerBirth(IIndividual individual); + + /** + * Register the pickup of an individual. + * + * @param individual + */ + void registerPickup(IIndividual individual); + + /** + * Marks a species as discovered. Should only be called from registerIndividual normally. + * + * @param species + */ + void registerSpecies(IAlleleSpecies species); + + /** + * Register a successful mutation. Will mark it as discovered. + */ + @Deprecated + void registerMutation(IAllele allele0, IAllele allele1); + + /** + * Register a successful mutation. Will mark it as discovered. + * + * @param mutation + */ + void registerMutation(IMutation mutation); + + /** + * Queries the tracker for discovered species. + * + * @param mutation + * Mutation to query for. + * @return true if the mutation has been discovered. + */ + boolean isDiscovered(IMutation mutation); + + /** + * Queries the tracker for discovered species. + * + * @param species + * Species to check. + * @return true if the species has been bred. + */ + boolean isDiscovered(IAlleleSpecies species); + + /** + * Synchronizes the tracker to the client side. Should be called before opening any gui needing that information. + * + * @param player + */ + void synchToPlayer(EntityPlayer player); + + /* LOADING & SAVING */ + void decodeFromNBT(NBTTagCompound nbttagcompound); + + void encodeToNBT(NBTTagCompound nbttagcompound); + +} diff --git a/forestry_common/core/forestry/api/genetics/IChromosome.java b/forestry_common/core/forestry/api/genetics/IChromosome.java new file mode 100755 index 000000000..2e01f4008 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IChromosome.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import forestry.api.core.INBTTagable; + +/** + * Implementations other than Forestry's default one are not supported! + * + * @author SirSengir + */ +public interface IChromosome extends INBTTagable { + + IAllele getPrimaryAllele(); + + IAllele getSecondaryAllele(); + + IAllele getInactiveAllele(); + + IAllele getActiveAllele(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IChromosomeType.java b/forestry_common/core/forestry/api/genetics/IChromosomeType.java new file mode 100755 index 000000000..faaf7a188 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IChromosomeType.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/* + * Interface to be implemented by the enums representing the various chromosomes + */ +public interface IChromosomeType { + + /* + * Get class which all alleles on this chromosome must interface + */ + Class getAlleleClass(); + + String getName(); + + ISpeciesRoot getSpeciesRoot(); + + int ordinal(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IClassification.java b/forestry_common/core/forestry/api/genetics/IClassification.java new file mode 100755 index 000000000..69526bca8 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IClassification.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Biological classifications from domain down to genus. + * + * Used by the *alyzers to display hierarchies. + */ +public interface IClassification { + + public enum EnumClassLevel { + + DOMAIN(0x777fff, true), KINGDOM(0x77c3ff), PHYLUM(0x77ffb6, true), DIVISION(0x77ffb6, true), CLASS(0x7bff77), ORDER(0xbeff77), FAMILY(0xfffd77), + SUBFAMILY(0xfffd77), TRIBE(0xfffd77), GENUS(0xffba77); + + private int colour; + private boolean isDroppable; + + private EnumClassLevel(int colour) { + this(colour, false); + } + + private EnumClassLevel(int colour, boolean isDroppable) { + this.colour = colour; + this.isDroppable = isDroppable; + } + + /** + * @return Colour to use for displaying this classification. + */ + public int getColour() { + return colour; + } + + /** + * @return Indicates whether display of this classification level can be ommitted in case of space constraints. + */ + public boolean isDroppable() { + return isDroppable; + } + } + + /** + * @return Level inside the full hierarchy this particular classification is located at. + */ + EnumClassLevel getLevel(); + + /** + * @return Unique String identifier. + */ + String getUID(); + + /** + * @return Localized branch name for user display. + */ + String getName(); + + /** + * A branch approximates a "genus" in real life. Real life examples: "Micrapis", "Megapis" + * + * @return flavour text (may be null) + */ + String getScientific(); + + /** + * @return Localized description of this branch. (May be null.) + */ + String getDescription(); + + /** + * @return Member groups of this one. + */ + IClassification[] getMemberGroups(); + + /** + * Adds subgroups to this group. + */ + void addMemberGroup(IClassification group); + + /** + * @return Member species of this group. + */ + IAlleleSpecies[] getMemberSpecies(); + + /** + * Used by the allele registry to populate internal collection of branch members on the fly. + * + * @param species + */ + void addMemberSpecies(IAlleleSpecies species); + + /** + * @return Parent classification, null if this is root. + */ + IClassification getParent(); + + /** + * Only used internally by the AlleleRegistry if this classification has been added to another one. + * + * @param parent + */ + void setParent(IClassification parent); +} diff --git a/forestry_common/core/forestry/api/genetics/IEffectData.java b/forestry_common/core/forestry/api/genetics/IEffectData.java new file mode 100755 index 000000000..33137f1fe --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IEffectData.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import forestry.api.core.INBTTagable; + +/** + * Container to hold some temporary data for bee, tree and butterfly effects. + * + * @author SirSengir + */ +public interface IEffectData extends INBTTagable { + void setInteger(int index, int val); + + void setFloat(int index, float val); + + void setBoolean(int index, boolean val); + + int getInteger(int index); + + float getFloat(int index); + + boolean getBoolean(int index); +} diff --git a/forestry_common/core/forestry/api/genetics/IFlowerProvider.java b/forestry_common/core/forestry/api/genetics/IFlowerProvider.java new file mode 100755 index 000000000..58d3e76b8 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IFlowerProvider.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IFlowerProvider { + /** + * @param world + * @param individual + * @param x + * @param y + * @param z + * @return True if the block at the passed coordinates is a valid flower for the species. + */ + boolean isAcceptedFlower(World world, IIndividual individual, int x, int y, int z); + + boolean isAcceptedPollinatable(World world, IPollinatable pollinatable); + + /** + * @param world + * @param individual + * @param x + * @param y + * @param z + * @return True if a flower was planted. + */ + boolean growFlower(World world, IIndividual individual, int x, int y, int z); + + /** + * @return Short, human-readable identifier used in the beealyzer. + */ + String getDescription(); + + /** + * Allows the flower provider to affect the produce at the given location. + * @param world + * @param individual + * @param x + * @param y + * @param z + * @param products + * @return Array of itemstacks being the (modified or unmodified) produce. + */ + ItemStack[] affectProducts(World world, IIndividual individual, int x, int y, int z, ItemStack[] products); + + /** + * @return Array of itemstacks representing valid flowers for the flower provider. The first in the array is for use as an icon Return null or an empty + * array if the flower does not have an itemstack + */ + ItemStack[] getItemStacks(); +} diff --git a/forestry_common/core/forestry/api/genetics/IFruitBearer.java b/forestry_common/core/forestry/api/genetics/IFruitBearer.java new file mode 100755 index 000000000..8d8463a2a --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IFruitBearer.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; + +/** + * Can be implemented by tile entities which can bear fruit. + * + * @author SirSengir + */ +public interface IFruitBearer { + + /** + * @return true if the actual tile can bear fruits. + */ + boolean hasFruit(); + + /** + * @return Family of the potential fruits on this tile. + */ + IFruitFamily getFruitFamily(); + + /** + * Picks the fruits of this tile, resetting it to unripe fruits. + * + * @param tool + * Tool used in picking the fruits. May be null. + * @return Picked fruits. + */ + Collection pickFruit(ItemStack tool); + + /** + * @return float indicating the ripeness of the fruit with >= 1.0f indicating full ripeness. + */ + float getRipeness(); + + /** + * Increases the ripeness of the fruit. + * + * @param add + * Float to add to the ripeness. Will truncate to valid values. + */ + void addRipeness(float add); +} diff --git a/forestry_common/core/forestry/api/genetics/IFruitFamily.java b/forestry_common/core/forestry/api/genetics/IFruitFamily.java new file mode 100755 index 000000000..cf5322ba0 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IFruitFamily.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +public interface IFruitFamily { + + /** + * @return Unique String identifier. + */ + String getUID(); + + /** + * @return Localized family name for user display. + */ + String getName(); + + /** + * A scientific-y name for this fruit family + * + * @return flavour text (may be null) + */ + String getScientific(); + + /** + * @return Localized description of this fruit family. (May be null.) + */ + String getDescription(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IGenome.java b/forestry_common/core/forestry/api/genetics/IGenome.java new file mode 100755 index 000000000..03e2dd226 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IGenome.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import forestry.api.core.INBTTagable; + +/** + * Holds the {@link IChromosome}s which comprise the traits of a given individual. + * + * Only the default implementation is supported. + */ +public interface IGenome extends INBTTagable { + + IAlleleSpecies getPrimary(); + + IAlleleSpecies getSecondary(); + + IChromosome[] getChromosomes(); + + IAllele getActiveAllele(int chromosome); + + IAllele getInactiveAllele(int chromosome); + + boolean isGeneticEqual(IGenome other); + + ISpeciesRoot getSpeciesRoot(); +} diff --git a/forestry_common/core/forestry/api/genetics/IHousing.java b/forestry_common/core/forestry/api/genetics/IHousing.java new file mode 100755 index 000000000..c89aee2f0 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IHousing.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +/** + * Any housing, hatchery or nest which is a fixed location in the world. + */ +public interface IHousing { + + /** + * @return String containing the login of this housing's owner. + */ + String getOwnerName(); + + World getWorld(); + + int getXCoord(); + + int getYCoord(); + + int getZCoord(); + + int getBiomeId(); + + EnumTemperature getTemperature(); + + EnumHumidity getHumidity(); + + void setErrorState(int state); + + int getErrorOrdinal(); + + /** + * Adds products to the housing's inventory. + * + * @param product + * ItemStack with the product to add. + * @param all + * @return Boolean indicating success or failure. + */ + boolean addProduct(ItemStack product, boolean all); + +} diff --git a/forestry_common/core/forestry/api/genetics/IIndividual.java b/forestry_common/core/forestry/api/genetics/IIndividual.java new file mode 100755 index 000000000..a4cdd3a4d --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IIndividual.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.List; + +import forestry.api.core.INBTTagable; + +/** + * An actual individual with genetic information. + * + * Only the default implementation is supported. + */ +public interface IIndividual extends INBTTagable { + + String getIdent(); + + String getDisplayName(); + + void addTooltip(List list); + + /** + * Call to mark the IIndividual as analyzed. + * @return true if the IIndividual has not been analyzed previously. + */ + boolean analyze(); + + boolean isAnalyzed(); + + boolean hasEffect(); + + boolean isSecret(); + + IGenome getGenome(); + + /** + * Check whether the genetic makeup of two IIndividuals is identical. Ignores additional data like generations, irregular mating, etc.. + * @param other + * @return true if the given other IIndividual has the amount of chromosomes and their alleles are identical. + */ + boolean isGeneticEqual(IIndividual other); + + /** + * @return A deep copy of this individual. + */ + IIndividual copy(); + + /** + * @param chromosomeOrdinal Ordinal of the chromosome to check. + * @return true if both primary and secondary allele on the given chromosome match. + */ + boolean isPureBred(int chromosomeOrdinal); + +} diff --git a/forestry_common/core/forestry/api/genetics/IIndividualLiving.java b/forestry_common/core/forestry/api/genetics/IIndividualLiving.java new file mode 100755 index 000000000..6898c74eb --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IIndividualLiving.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.world.World; + +public interface IIndividualLiving extends IIndividual { + + /** + * @return Genetic information of the mate, null if unmated. + */ + IGenome getMate(); + + /** + * @return Current health of the individual. + */ + int getHealth(); + + /** + * @return Maximum health of the individual. + */ + int getMaxHealth(); + + /** + * Age the individual. + * @param world + * @param ageModifier + */ + void age(World world, float ageModifier); + + /** + * Mate with the given individual. + * @param individual the {@link IIndividual} to mate this one with. + */ + void mate(IIndividual individual); + + /** + * @return true if the individual is among the living. + */ + boolean isAlive(); + +} diff --git a/forestry_common/core/forestry/api/genetics/ILegacyHandler.java b/forestry_common/core/forestry/api/genetics/ILegacyHandler.java new file mode 100755 index 000000000..08a015858 --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/ILegacyHandler.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * AlleleManager.alleleRegistry can be cast to this type. + */ +public interface ILegacyHandler { + void registerLegacyMapping(int id, String uid); + + IAllele getFromLegacyMap(int id); +} diff --git a/forestry_common/core/forestry/api/genetics/IMutation.java b/forestry_common/core/forestry/api/genetics/IMutation.java new file mode 100755 index 000000000..21ef0a08a --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IMutation.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.Collection; + +/** + * Individuals can be seeded either as hive drops or as mutation results. + * + * {@link IAlleleRegistry} manages these. + * + * @author SirSengir + */ +public interface IMutation { + + /** + * @return {@link ISpeciesRoot} this mutation is associated with. + */ + ISpeciesRoot getRoot(); + + /** + * @return first of the alleles implementing IAlleleSpecies required for this mutation. + */ + IAllele getAllele0(); + + /** + * @return second of the alleles implementing IAlleleSpecies required for this mutation. + */ + IAllele getAllele1(); + + /** + * @return Array of {@link IAllele} representing the full default genome of the mutated side. + * + * Make sure to return a proper array for the species class. Returning an allele of the wrong type will cause cast errors on runtime. + */ + IAllele[] getTemplate(); + + /** + * @return Unmodified base chance for mutation to fire. + */ + float getBaseChance(); + + /** + * @return Collection of localized, human-readable strings describing special mutation conditions, if any. + */ + Collection getSpecialConditions(); + + /** + * @param allele + * @return true if the passed allele is one of the alleles participating in this mutation. + */ + boolean isPartner(IAllele allele); + + /** + * @param allele + * @return the other allele which was not passed as argument. + */ + IAllele getPartner(IAllele allele); + + /** + * @return true if the mutation should not be displayed in the beealyzer. + */ + boolean isSecret(); + +} diff --git a/forestry_common/core/forestry/api/genetics/IPollinatable.java b/forestry_common/core/forestry/api/genetics/IPollinatable.java new file mode 100755 index 000000000..270421b0a --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/IPollinatable.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.EnumSet; + +import net.minecraftforge.common.EnumPlantType; + +/** + * Can be implemented by tile entities, if they wish to be pollinatable. + * + * @author SirSengir + */ +public interface IPollinatable { + + /** + * @return plant types this pollinatable is classified as. (Can be used by bees to determine whether to interact or not. + */ + EnumSet getPlantType(); + + /** + * @return IIndividual containing the genetic information of this IPollinatable + */ + IIndividual getPollen(); + + /** + * Checks whether this {@link IPollinatable} can mate with the given pollen. + * + * Must be the one to check genetic equivalency. + * + * @param pollen + * IIndividual representing the pollen. + * @return true if mating is possible, false otherwise. + */ + boolean canMateWith(IIndividual pollen); + + /** + * Pollinates this entity. + * + * @param pollen + * IIndividual representing the pollen. + */ + void mateWith(IIndividual pollen); + +} diff --git a/forestry_common/core/forestry/api/genetics/ISpeciesRoot.java b/forestry_common/core/forestry/api/genetics/ISpeciesRoot.java new file mode 100755 index 000000000..2ac219a2d --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/ISpeciesRoot.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.Random; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +/** + * Describes a class of species (i.e. bees, trees, butterflies), provides helper functions and access to common functionality. + */ +public interface ISpeciesRoot { + + /** + * @return A unique identifier for the species class. Should consist of "root" + a common name for the species class in camel-case, i.e. "rootBees", "rootTrees", "rootButterflies". + */ + String getUID(); + + /** + * @return Class of the sub-interface inheriting from {@link IIndividual}. + */ + Class getMemberClass(); + + /** + * @return Integer denoting the number of (counted) species of this type in the world. + */ + int getSpeciesCount(); + + /** + * Used to check whether a given itemstack contains genetic data corresponding to an {@link IIndividual} of this class. + * @param stack itemstack to check. + * @return true if the itemstack contains an {@link IIndividual} of this class, false otherwise. + */ + boolean isMember(ItemStack stack); + + /** + * Used to check whether a given itemstack contains genetic data corresponding to an {@link IIndividual} of this class and matches the given type. + * @param stack itemstack to check. + * @param type Integer denoting the type needed to match. (i.e. butterfly vs. butterfly serum; bee queens, princesses, drones; etc.) + * @return true if the itemstack contains an {@link IIndividual} of this class, false otherwise. + */ + boolean isMember(ItemStack stack, int type); + + /** + * Used to check whether the given {@link IIndividual} is member of this class. + * @param individual {@link IIndividual} to check. + * @return true if the individual is member of this class, false otherwise. + */ + boolean isMember(IIndividual individual); + + IIndividual getMember(ItemStack stack); + + IIndividual getMember(NBTTagCompound compound); + + ItemStack getMemberStack(IIndividual individual, int type); + + /* BREEDING TRACKER */ + IBreedingTracker getBreedingTracker(World world, String player); + + /* GENOME MANIPULATION */ + IIndividual templateAsIndividual(IAllele[] template); + + IIndividual templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive); + + IChromosome[] templateAsChromosomes(IAllele[] template); + + IChromosome[] templateAsChromosomes(IAllele[] templateActive, IAllele[] templateInactive); + + IGenome templateAsGenome(IAllele[] template); + + IGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive); + + /* TEMPLATES */ + /** + * Registers a bee template using the UID of the first allele as identifier. + * + * @param template + */ + void registerTemplate(IAllele[] template); + + /** + * Registers a bee template using the passed identifier. + * + * @param template + */ + void registerTemplate(String identifier, IAllele[] template); + + /** + * Retrieves a registered template using the passed identifier. + * + * @param identifier + * @return Array of {@link IAllele} representing a genome. + */ + IAllele[] getTemplate(String identifier); + + /** + * @return Default individual template for use when stuff breaks. + */ + IAllele[] getDefaultTemplate(); + + /** + * @param rand Random to use. + * @return A random template from the pool of registered species templates. + */ + IAllele[] getRandomTemplate(Random rand); + + Map getGenomeTemplates(); + ArrayList getIndividualTemplates(); + + /* MUTATIONS */ + /** + * Use to register mutations. + * + * @param mutation + */ + void registerMutation(IMutation mutation); + + /** + * @return All registered mutations. + */ + Collection getMutations(boolean shuffle); + + /** + * @param other Allele to match mutations against. + * @return All registered mutations the given allele is part of. + */ + Collection getCombinations(IAllele other); + + /** + * @param result {@link IAllele} to search for. + * @return All registered mutations the given {@link IAllele} is the result of. + */ + Collection getPaths(IAllele result, int chromosomeOrdinal); + + /* RESEARCH */ + /** + * @return List of generic catalysts which should be accepted for research by species of this class. + */ + Map getResearchCatalysts(); + + /** + * Sets an item stack as a valid (generic) research catalyst for this class. + * @param itemstack ItemStack to set as suitable. + * @param suitability Float between 0 and 1 to indicate suitability. + */ + void setResearchSuitability(ItemStack itemstack, float suitability); + + /** + * @return Array of {@link IChromosomeType} which are in this species genome + */ + IChromosomeType[] getKaryotype(); + + /** + * @return {@link IChromosomeType} which is the "key" for this species class, usually the species chromosome. + */ + IChromosomeType getKaryotypeKey(); +} diff --git a/forestry_common/core/forestry/api/genetics/package-info.java b/forestry_common/core/forestry/api/genetics/package-info.java new file mode 100755 index 000000000..a876fa19d --- /dev/null +++ b/forestry_common/core/forestry/api/genetics/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|genetics") +package forestry.api.genetics; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/lepidopterology/EnumButterflyChromosome.java b/forestry_common/core/forestry/api/lepidopterology/EnumButterflyChromosome.java new file mode 100755 index 000000000..92b565d3c --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/EnumButterflyChromosome.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleArea; +import forestry.api.genetics.IAlleleBoolean; +import forestry.api.genetics.IAlleleFloat; +import forestry.api.genetics.IAlleleFlowers; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IAlleleTolerance; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.ISpeciesRoot; + +public enum EnumButterflyChromosome implements IChromosomeType { + /** + * Species of the bee. Alleles here must implement {@link IAlleleButterflySpecies}. + */ + SPECIES(IAlleleButterflySpecies.class), + /** + * Physical size. + */ + SIZE(IAlleleFloat.class), + /** + * Flight speed. + */ + SPEED(IAlleleFloat.class), + /** + * How long the butterfly can last without access to matching pollinatables. + */ + LIFESPAN(IAlleleInteger.class), + /** + * Species with a higher metabolism have a higher appetite and may cause more damage to their environment. + */ + METABOLISM(IAlleleInteger.class), + /** + * Determines likelyhood of caterpillars and length of caterpillar/pupation phase. Also: Number of max caterpillars after mating? + */ + FERTILITY(IAlleleInteger.class), + /** + * Not sure yet. + */ + TEMPERATURE_TOLERANCE(IAlleleTolerance.class), + /** + * Not sure yet. + */ + HUMIDITY_TOLERANCE(IAlleleTolerance.class), + /** + * Only nocturnal butterflys/moths will fly at night. Allows daylight activity for naturally nocturnal species. + */ + NOCTURNAL(IAlleleBoolean.class), + /** + * Only tolerant flyers will fly in the rain. + */ + TOLERANT_FLYER(IAlleleBoolean.class), + /** + * Fire resistance. + */ + FIRE_RESIST(IAlleleBoolean.class), + /** + * Required flowers/leaves. + */ + FLOWER_PROVIDER(IAlleleFlowers.class), + /** + * Extra effect to surroundings. (?) + */ + EFFECT(IAlleleButterflyEffect.class), + /** + * Not used yet + */ + TERRITORY(IAlleleArea.class), + ; + + Class clss; + + EnumButterflyChromosome(Class clss) { + this.clss = clss; + } + + @Override + public Class getAlleleClass() { + return clss; + } + + @Override + public String getName() { + return this.toString().toLowerCase(); + } + + @Override + public ISpeciesRoot getSpeciesRoot() { + return AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies"); + } +} diff --git a/forestry_common/core/forestry/api/lepidopterology/EnumFlutterType.java b/forestry_common/core/forestry/api/lepidopterology/EnumFlutterType.java new file mode 100755 index 000000000..037c75a12 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/EnumFlutterType.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +public enum EnumFlutterType { + BUTTERFLY, + SERUM, + CATERPILLAR, + NONE; + + public static final EnumFlutterType[] VALUES = values(); +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IAlleleButterflyEffect.java b/forestry_common/core/forestry/api/lepidopterology/IAlleleButterflyEffect.java new file mode 100755 index 000000000..a37430005 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IAlleleButterflyEffect.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import forestry.api.genetics.IAlleleEffect; +import forestry.api.genetics.IEffectData; + +public interface IAlleleButterflyEffect extends IAlleleEffect { + + /** + * Used by butterflies to trigger effects in the world. + * @param butterfly {@link IEntityButterfly} + * @param storedData + * @return {@link forestry.api.genetics.IEffectData} for the next cycle. + */ + IEffectData doEffect(IEntityButterfly butterfly, IEffectData storedData); + +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IAlleleButterflySpecies.java b/forestry_common/core/forestry/api/lepidopterology/IAlleleButterflySpecies.java new file mode 100755 index 000000000..2b5e6fb9d --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IAlleleButterflySpecies.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import java.util.EnumSet; +import java.util.Map; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.genetics.IAlleleSpecies; + +public interface IAlleleButterflySpecies extends IAlleleSpecies { + + /** + * @return the IBeeRoot + */ + IButterflyRoot getRoot(); + + /** + * @return Path of the texture to use for entity rendering. + */ + String getEntityTexture(); + + /** + * Allows butterflies to restrict random spawns beyond the restrictions set by getTemperature() and getHumidity(). + * + * @return EnumSet of biome tags this butterfly species can be spawned in. + */ + EnumSet getSpawnBiomes(); + + /** + * @return true if a prospective spawn biome must not match a biome tag outside of getSpawnBiomes. + */ + boolean strictSpawnMatch(); + + /** + * @return Float between 0 and 1 representing the rarity of the species, will affect spawn rate. + */ + float getRarity(); + + /** + * @return Float representing the distance below which this butterfly will take flight if it detects a player which is not sneaking. + */ + float getFlightDistance(); + + /** + * @return true if this species is only active at night. + */ + boolean isNocturnal(); + + Map getButterflyLoot(); + + Map getCaterpillarLoot(); +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IButterfly.java b/forestry_common/core/forestry/api/lepidopterology/IButterfly.java new file mode 100755 index 000000000..161b92c46 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IButterfly.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.genetics.IIndividualLiving; + +public interface IButterfly extends IIndividualLiving { + + IButterflyGenome getGenome(); + + /** + * @return Genetic information of the mate, null if unmated. + */ + IButterflyGenome getMate(); + + /** + * @return Physical size of the butterfly. + */ + float getSize(); + + /** + * @param world + * @param x + * @param y + * @param z + * @return true if the butterfly can naturally spawn at the given location at this time. (Used to auto-spawn butterflies from tree leaves.) + */ + boolean canSpawn(World world, double x, double y, double z); + + /** + * @param world + * @param x + * @param y + * @param z + * @return true if the butterfly can take flight at the given location at this time. (Used to auto-spawn butterflies from dropped items.) + */ + boolean canTakeFlight(World world, double x, double y, double z); + + /** + * @param world + * @param x + * @param y + * @param z + * @return true if the environment (temperature, humidity) is valid for the butterfly at the given location. + */ + boolean isAcceptedEnvironment(World world, double x, double y, double z); + + IButterfly spawnCaterpillar(IButterflyNursery nursery); + + /** + * @param entity + * @param playerKill Whether or not the butterfly was killed by a player. + * @param lootLevel Loot level according to the weapon used to kill the butterfly. + * @return Array of itemstacks to drop on death of the given entity. + */ + ItemStack[] getLootDrop(IEntityButterfly entity, boolean playerKill, int lootLevel); + + /** + * @param nursery + * @param playerKill Whether or not the nursery was broken by a player. + * @param lootLevel Fortune level. + * @return Array of itemstacks to drop on breaking of the nursery. + */ + ItemStack[] getCaterpillarDrop(IButterflyNursery nursery, boolean playerKill, int lootLevel); + + /** + * Create an exact copy of this butterfly. + */ + IButterfly copy(); + +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IButterflyGenome.java b/forestry_common/core/forestry/api/lepidopterology/IButterflyGenome.java new file mode 100755 index 000000000..91875e373 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IButterflyGenome.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IGenome; + +public interface IButterflyGenome extends IGenome { + + IAlleleButterflySpecies getPrimary(); + + IAlleleButterflySpecies getSecondary(); + + float getSize(); + + int getLifespan(); + + int getMetabolism(); + + int getFertility(); + + float getSpeed(); + + EnumTolerance getToleranceTemp(); + + EnumTolerance getToleranceHumid(); + + boolean getNocturnal(); + + boolean getTolerantFlyer(); + + boolean getFireResist(); + + IFlowerProvider getFlowerProvider(); + + IAlleleButterflyEffect getEffect(); + +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IButterflyMutation.java b/forestry_common/core/forestry/api/lepidopterology/IButterflyMutation.java new file mode 100755 index 000000000..cc7fc3d23 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IButterflyMutation.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IGenome; +import forestry.api.genetics.IMutation; + +public interface IButterflyMutation extends IMutation { + float getChance(IButterflyNursery housing, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1); +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IButterflyNursery.java b/forestry_common/core/forestry/api/lepidopterology/IButterflyNursery.java new file mode 100755 index 000000000..4e2add8dc --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IButterflyNursery.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import forestry.api.genetics.IHousing; +import forestry.api.genetics.IIndividual; + +public interface IButterflyNursery extends IHousing { + + IButterfly getCaterpillar(); + + IIndividual getNanny(); + + void setCaterpillar(IButterfly butterfly); + + boolean canNurse(IButterfly butterfly); + +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IButterflyRoot.java b/forestry_common/core/forestry/api/lepidopterology/IButterflyRoot.java new file mode 100755 index 000000000..2fd727a31 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IButterflyRoot.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.ISpeciesRoot; + +public interface IButterflyRoot extends ISpeciesRoot { + + boolean isMember(ItemStack stack); + + IButterfly getMember(ItemStack stack); + + IButterfly getMember(NBTTagCompound compound); + + ItemStack getMemberStack(IIndividual butterfly, int type); + + /* GENOME CONVERSION */ + IButterfly templateAsIndividual(IAllele[] template); + + IButterfly templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive); + + IButterflyGenome templateAsGenome(IAllele[] template); + + IButterflyGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive); + + /* BUTTERFLY SPECIFIC */ + ILepidopteristTracker getBreedingTracker(World world, String player); + + /** + * Spawns the given butterfly in the world. + * @param butterfly + * @return butterfly entity on success, null otherwise. + */ + EntityLiving spawnButterflyInWorld(World world, IButterfly butterfly, double x, double y, double z); + + /** + * @return true if passed item is mated. + */ + boolean isMated(ItemStack stack); + + /* TEMPLATES */ + ArrayList getIndividualTemplates(); + + /* MUTATIONS */ + Collection getMutations(boolean shuffle); + +} diff --git a/forestry_common/core/forestry/api/lepidopterology/IEntityButterfly.java b/forestry_common/core/forestry/api/lepidopterology/IEntityButterfly.java new file mode 100755 index 000000000..0a1932016 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/IEntityButterfly.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.passive.IAnimals; + +import forestry.api.genetics.IIndividual; + +public interface IEntityButterfly extends IAnimals { + + void changeExhaustion(int change); + + int getExhaustion(); + + IButterfly getButterfly(); + + /** + * @return The entity as an EntityCreature to save casting. + */ + EntityCreature getEntity(); + + IIndividual getPollen(); + + void setPollen(IIndividual pollen); +} diff --git a/forestry_common/core/forestry/api/lepidopterology/ILepidopteristTracker.java b/forestry_common/core/forestry/api/lepidopterology/ILepidopteristTracker.java new file mode 100755 index 000000000..94880c9c0 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/ILepidopteristTracker.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import forestry.api.genetics.IBreedingTracker; + +public interface ILepidopteristTracker extends IBreedingTracker { + + void registerCatch(IButterfly butterfly); + +} diff --git a/forestry_common/core/forestry/api/lepidopterology/package-info.java b/forestry_common/core/forestry/api/lepidopterology/package-info.java new file mode 100755 index 000000000..cca141240 --- /dev/null +++ b/forestry_common/core/forestry/api/lepidopterology/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|lepidopterology") +package forestry.api.lepidopterology; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/mail/EnumPostage.java b/forestry_common/core/forestry/api/mail/EnumPostage.java new file mode 100755 index 000000000..ee31000cb --- /dev/null +++ b/forestry_common/core/forestry/api/mail/EnumPostage.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +public enum EnumPostage { + P_0(0), P_1(1), P_2(2), P_5(5), P_10(10), P_20(20), P_50(50), P_100(100), P_200(200); + + private final int value; + + private EnumPostage(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } +} diff --git a/forestry_common/core/forestry/api/mail/ILetter.java b/forestry_common/core/forestry/api/mail/ILetter.java new file mode 100755 index 000000000..8dfcc96f4 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/ILetter.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import java.util.List; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +import forestry.api.core.INBTTagable; + +public interface ILetter extends IInventory, INBTTagable { + + ItemStack[] getPostage(); + + void setProcessed(boolean flag); + + boolean isProcessed(); + + boolean isMailable(); + + void setSender(MailAddress address); + + MailAddress getSender(); + + boolean hasRecipient(); + + void setRecipient(MailAddress address); + + MailAddress[] getRecipients(); + + String getRecipientString(); + + void setText(String text); + + String getText(); + + @SuppressWarnings("rawtypes") + void addTooltip(List list); + + boolean isPostPaid(); + + int requiredPostage(); + + void invalidatePostage(); + + ItemStack[] getAttachments(); + + void addAttachment(ItemStack itemstack); + + void addAttachments(ItemStack[] itemstacks); + + int countAttachments(); + + void addStamps(ItemStack stamps); + +} diff --git a/forestry_common/core/forestry/api/mail/ILetterHandler.java b/forestry_common/core/forestry/api/mail/ILetterHandler.java new file mode 100755 index 000000000..51f7b21d7 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/ILetterHandler.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface ILetterHandler { + IPostalState handleLetter(World world, String recipient, ItemStack letterStack, boolean doLodge); +} diff --git a/forestry_common/core/forestry/api/mail/IPostOffice.java b/forestry_common/core/forestry/api/mail/IPostOffice.java new file mode 100755 index 000000000..68df4bc9d --- /dev/null +++ b/forestry_common/core/forestry/api/mail/IPostOffice.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IPostOffice { + + void collectPostage(ItemStack[] stamps); + + IPostalState lodgeLetter(World world, ItemStack itemstack, boolean doLodge); + + ItemStack getAnyStamp(int max); + + ItemStack getAnyStamp(EnumPostage postage, int max); + + ItemStack getAnyStamp(EnumPostage[] postages, int max); + + void registerTradeStation(ITradeStation trade); + + void deregisterTradeStation(ITradeStation trade); + + Map getActiveTradeStations(World world); +} diff --git a/forestry_common/core/forestry/api/mail/IPostRegistry.java b/forestry_common/core/forestry/api/mail/IPostRegistry.java new file mode 100755 index 000000000..bfb21444b --- /dev/null +++ b/forestry_common/core/forestry/api/mail/IPostRegistry.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IPostRegistry { + + /* POST OFFICE */ + IPostOffice getPostOffice(World world); + + /* LETTERS */ + boolean isLetter(ItemStack itemstack); + + ILetter createLetter(MailAddress sender, MailAddress recipient); + + ILetter getLetter(ItemStack itemstack); + + ItemStack createLetterStack(ILetter letter); + + /* CARRIERS */ + /** + * Registers a new {@link IPostalCarrier}. See {@link IPostalCarrier} for details. + * @param carrier {@link IPostalCarrier} to register. + */ + void registerCarrier(IPostalCarrier carrier); + + IPostalCarrier getCarrier(String uid); + + Map getRegisteredCarriers(); + + /* TRADE STATIONS */ + void deleteTradeStation(World world, String moniker); + + ITradeStation getOrCreateTradeStation(World world, String owner, String moniker); + + ITradeStation getTradeStation(World world, String moniker); + + boolean isAvailableTradeMoniker(World world, String moniker); + + boolean isValidTradeMoniker(World world, String moniker); + + /* PO BOXES */ + boolean isValidPOBox(World world, String username); + +} diff --git a/forestry_common/core/forestry/api/mail/IPostalCarrier.java b/forestry_common/core/forestry/api/mail/IPostalCarrier.java new file mode 100755 index 000000000..b5c0fbecd --- /dev/null +++ b/forestry_common/core/forestry/api/mail/IPostalCarrier.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Postal Carriers are systems which can be hooked into Forestry's mail system to handle mail delivery. + * + * The two available carriers in vanilla Forestry are + * "player" - Delivers mail to individual players. + * "trader" - Handles mail addressed to trade stations. + */ +public interface IPostalCarrier { + + /** + * @return A lower-case identifier without spaces. + */ + String getUID(); + + /** + * @return A human-readable name for this carrier. + */ + String getName(); + + @SideOnly(Side.CLIENT) + IIcon getIcon(); + + /** + * Handle delivery of a letter addressed to this carrier. + * @param world The world the {@link IPostOffice} handles. + * @param office {link @IPostOffice} which received this letter and handed it to the carrier. + * @param recipient An identifier for the recipient as typed by the player into the address field. + * @param letterstack ItemStack representing the letter. See {@link IPostRegistry} for helper functions to validate and extract it. + * @param doDeliver Whether or not the letter is supposed to actually be delivered or if delivery is only to be simulated. + * @return {link IPostalState} holding information on success or failure for delivery. + */ + IPostalState deliverLetter(World world, IPostOffice office, String recipient, ItemStack letterstack, boolean doDeliver); + +} diff --git a/forestry_common/core/forestry/api/mail/IPostalState.java b/forestry_common/core/forestry/api/mail/IPostalState.java new file mode 100755 index 000000000..4ad579db5 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/IPostalState.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +public interface IPostalState { + boolean isOk(); + + String getIdentifier(); + + int ordinal(); +} diff --git a/forestry_common/core/forestry/api/mail/IStamps.java b/forestry_common/core/forestry/api/mail/IStamps.java new file mode 100755 index 000000000..a623b6cc3 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/IStamps.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.item.ItemStack; + +public interface IStamps { + + EnumPostage getPostage(ItemStack itemstack); + +} diff --git a/forestry_common/core/forestry/api/mail/ITradeStation.java b/forestry_common/core/forestry/api/mail/ITradeStation.java new file mode 100755 index 000000000..d6d8a59b2 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/ITradeStation.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.inventory.IInventory; + +public interface ITradeStation extends ILetterHandler, IInventory { + + String getMoniker(); + + boolean isValid(); + + void invalidate(); + + void setVirtual(boolean isVirtual); + + boolean isVirtual(); + + TradeStationInfo getTradeInfo(); + +} diff --git a/forestry_common/core/forestry/api/mail/MailAddress.java b/forestry_common/core/forestry/api/mail/MailAddress.java new file mode 100755 index 000000000..4876a38d4 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/MailAddress.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.core.INBTTagable; + +public class MailAddress implements INBTTagable { + private String type; + private String identifier; + + private MailAddress() { + } + + public MailAddress(String identifier) { + this(identifier, "player"); + } + + public MailAddress(String identifier, String type) { + this.identifier = identifier; + this.type = type; + } + + public String getType() { + return type; + } + + public String getIdentifier() { + return identifier; + } + + public boolean isPlayer() { + return "player".equals(type); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + if(nbttagcompound.hasKey("TP")) + type = nbttagcompound.getString("TP"); + else + type = nbttagcompound.getShort("TYP") == 0 ? "player" : "trader"; + identifier = nbttagcompound.getString("ID"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + nbttagcompound.setString("TP", type); + nbttagcompound.setString("ID", identifier); + } + + public static MailAddress loadFromNBT(NBTTagCompound nbttagcompound) { + MailAddress address = new MailAddress(); + address.readFromNBT(nbttagcompound); + return address; + } +} diff --git a/forestry_common/core/forestry/api/mail/PostManager.java b/forestry_common/core/forestry/api/mail/PostManager.java new file mode 100755 index 000000000..6f6a5ef82 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/PostManager.java @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + + +public class PostManager { + public static IPostRegistry postRegistry; +} diff --git a/forestry_common/core/forestry/api/mail/TradeStationInfo.java b/forestry_common/core/forestry/api/mail/TradeStationInfo.java new file mode 100755 index 000000000..4b7931fbf --- /dev/null +++ b/forestry_common/core/forestry/api/mail/TradeStationInfo.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.item.ItemStack; + +public class TradeStationInfo { + public final String moniker; + public final String owner; + public final ItemStack tradegood; + public final ItemStack[] required; + public final IPostalState state; + + public TradeStationInfo(String moniker, String owner, ItemStack tradegood, ItemStack[] required, IPostalState state) { + this.moniker = moniker; + this.owner = owner; + this.tradegood = tradegood; + this.required = required; + this.state = state; + } +} diff --git a/forestry_common/core/forestry/api/mail/package-info.java b/forestry_common/core/forestry/api/mail/package-info.java new file mode 100755 index 000000000..cd8d3c6e0 --- /dev/null +++ b/forestry_common/core/forestry/api/mail/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|mail") +package forestry.api.mail; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/package-info.java b/forestry_common/core/forestry/api/package-info.java new file mode 100755 index 000000000..30e9bc340 --- /dev/null +++ b/forestry_common/core/forestry/api/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="Forestry", provides="ForestryAPI|core") +package forestry.api; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/recipes/IBottlerManager.java b/forestry_common/core/forestry/api/recipes/IBottlerManager.java new file mode 100755 index 000000000..7faaf22c4 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/IBottlerManager.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.fluids.FluidStack; + +/** + * Provides an interface to the recipe manager of the bottler. + * + * The manager is initialized at the beginning of Forestry's BaseMod.load() cycle. Begin adding recipes in BaseMod.ModsLoaded() and this shouldn't be null even + * if your mod loads before Forestry. + * + * Accessible via {@link RecipeManagers} + * + * Note that this is untested with anything other than biofuel->fuelcan conversion. + * + * @author SirSengir + */ +public interface IBottlerManager extends ICraftingProvider { + /** + * Add a recipe to the bottler. + * The bottler will populate its recipe list dynamically from the LiquidContainerRegistry. Recipes added explicitely will take precedence. + * + * @param cyclesPerUnit + * Amount of work cycles required to run through the conversion once. + * @param input + * LiquidStack representing the input liquid. + * @param can + * ItemStack representing the cans, capsules and/or cells required + * @param bottled + * ItemStack representing the finished product + */ + @Deprecated + public void addRecipe(int cyclesPerUnit, FluidStack input, ItemStack can, ItemStack bottled); +} diff --git a/forestry_common/core/forestry/api/recipes/ICarpenterManager.java b/forestry_common/core/forestry/api/recipes/ICarpenterManager.java new file mode 100755 index 000000000..f5516e2c1 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/ICarpenterManager.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ShapedRecipes; + +import net.minecraftforge.fluids.FluidStack; + +/** + * Provides an interface to the recipe manager of the carpenter. + * + * The manager is initialized at the beginning of Forestry's BaseMod.load() cycle. Begin adding recipes in BaseMod.ModsLoaded() and this shouldn't be null even + * if your mod loads before Forestry. + * + * Accessible via {@link RecipeManagers} + * + * Only shaped recipes can be added currently. + * + * @author SirSengir + */ +public interface ICarpenterManager extends ICraftingProvider { + /** + * Add a shaped recipe to the carpenter. + * + * @param box + * ItemStack of one item representing the required box (carton, crate) for this recipe. May be null. + * @param product + * Crafting result. + * @param materials + * Materials needed in the crafting matrix. This gets passed directly to {@link ShapedRecipes}. Notation is the same. + */ + public void addRecipe(ItemStack box, ItemStack product, Object materials[]); + + /** + * Add a shaped recipe to the carpenter. + * + * @param packagingTime + * Number of work cycles required to craft the recipe once. + * @param box + * ItemStack of one item representing the required box (carton, crate) for this recipe. May be null. + * @param product + * Crafting result. + * @param materials + * Materials needed in the crafting matrix. This gets passed directly to {@link ShapedRecipes}. Notation is the same. + */ + public void addRecipe(int packagingTime, ItemStack box, ItemStack product, Object materials[]); + + /** + * Add a shaped recipe to the carpenter. + * + * @param packagingTime + * Number of work cycles required to craft the recipe once. + * @param liquid + * Liquid required in carpenter's tank. + * @param box + * ItemStack of one item representing the required box (carton, crate) for this recipe. May be null. + * @param product + * Crafting result. + * @param materials + * Materials needed in the crafting matrix. This gets passed directly to {@link ShapedRecipes}. Notation is the same. + */ + public void addRecipe(int packagingTime, FluidStack liquid, ItemStack box, ItemStack product, Object materials[]); + + public void addCrating(String toCrate, ItemStack unpack, ItemStack crated); + + public void addCrating(ItemStack itemStack); +} diff --git a/forestry_common/core/forestry/api/recipes/ICentrifugeManager.java b/forestry_common/core/forestry/api/recipes/ICentrifugeManager.java new file mode 100755 index 000000000..115868c03 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/ICentrifugeManager.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import java.util.HashMap; + +import net.minecraft.item.ItemStack; + +/** + * Provides an interface to the recipe manager of the centrifuge. + * + * The manager is initialized at the beginning of Forestry's BaseMod.load() cycle. Begin adding recipes in BaseMod.ModsLoaded() and this shouldn't be null even + * if your mod loads before Forestry. + * + * Accessible via {@link RecipeManagers} + * + * @author SirSengir + */ +public interface ICentrifugeManager extends ICraftingProvider { + + /** + * Add a recipe to the centrifuge + * + * @param timePerItem + * Time to centrifugate one item of the given type + * @param resource + * ItemStack containing information on item id and damage. Stack size will be ignored. + * @param products + * HashMap specifying the possible products and the chances of them resulting from centrifugation. + */ + public void addRecipe(int timePerItem, ItemStack resource, HashMap products); + + /** + * Add a recipe to the centrifuge + * + * @param timePerItem + * Time to centrifugate one item of the given type + * @param resource + * ItemStack containing information on item id and damage. Stack size will be ignored. + * @param produce + * Array of ItemStacks that can be the result of this recipe. + * @param chances + * Array of integers corresponding and matching to produce providing the chance (0-100) for the ItemStack at the given index to be + * produced. + */ + public void addRecipe(int timePerItem, ItemStack resource, ItemStack[] produce, int[] chances); + + /** + * Add a recipe to the centrifuge + * + * @param timePerItem + * Time to centrifugate one item of the given type + * @param resource + * ItemStack containing information on item id and damage. Stack size will be ignored. + * @param primary + * Primary product produced by centrifugating one item. Yield 100 %. + * @param secondary + * Secondary product that may be produced when centrifugating the given item. May be null. + * @param chance + * Chance (1 - 100) for centrifugation to yield the secondary product. + */ + public void addRecipe(int timePerItem, ItemStack resource, ItemStack primary, ItemStack secondary, int chance); + + /** + * Add a recipe to the centrifuge + * + * @param timePerItem + * Time to centrifugate one item of the given type + * @param resource + * ItemStack containing information on item id and damage. Stack size will be ignored. + * @param primary + * Primary product produced by centrifugating one item. Yield 100 %. + */ + public void addRecipe(int timePerItem, ItemStack resource, ItemStack primary); + +} diff --git a/forestry_common/core/forestry/api/recipes/ICraftingProvider.java b/forestry_common/core/forestry/api/recipes/ICraftingProvider.java new file mode 100755 index 000000000..39f3c3456 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/ICraftingProvider.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import java.util.Map; + +public interface ICraftingProvider { + /** + * Access to the full list of recipes contained in the crafting provider. + * + * @return List of the given format where the first array represents inputs and the second outputs. Objects can be either ItemStack or LiquidStack. + */ + public Map getRecipes(); +} diff --git a/forestry_common/core/forestry/api/recipes/IFabricatorManager.java b/forestry_common/core/forestry/api/recipes/IFabricatorManager.java new file mode 100755 index 000000000..7b0a20f18 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/IFabricatorManager.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.fluids.FluidStack; + +public interface IFabricatorManager extends ICraftingProvider { + + void addRecipe(ItemStack plan, FluidStack molten, ItemStack result, Object[] pattern); + + void addSmelting(ItemStack resource, FluidStack molten, int meltingPoint); + +} diff --git a/forestry_common/core/forestry/api/recipes/IFermenterManager.java b/forestry_common/core/forestry/api/recipes/IFermenterManager.java new file mode 100755 index 000000000..2fcfce4d5 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/IFermenterManager.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.fluids.FluidStack; + +/** + * Provides an interface to the recipe manager of the fermenter. + * + * The manager is initialized at the beginning of Forestry's BaseMod.load() + * cycle. Begin adding recipes in BaseMod.ModsLoaded() and this shouldn't be + * null even if your mod loads before Forestry. + * + * Accessible via {@link RecipeManagers} + * + * @author SirSengir + */ +public interface IFermenterManager extends ICraftingProvider { + + /** + * Add a recipe to the fermenter + * + * @param resource ItemStack representing the resource. + * @param fermentationValue Value of the given resource, i.e. how much needs + * to be fermented for the output to be deposited into the product tank. + * @param modifier Modifies the amount of liquid output per work cycle. + * (water = 1.0f, honey = 1.5f) + * @param output LiquidStack representing output liquid. Amount is + * determined by fermentationValue*modifier. + * @param liquid LiquidStack representing resource liquid and amount. + * @throws NullPointerException if resource, output or liquid is null + */ + public void addRecipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output, FluidStack liquid); + + /** + * Add a recipe to the fermenter. Defaults to water as input liquid. + * + * @param resource ItemStack representing the resource. + * @param modifier Modifies the amount of liquid output per work cycle. + * (water = 1.0f, honey = 1.5f) + * @param fermentationValue Value of the given resource, i.e. how much needs + * to be fermented for the output to be deposited into the product tank. + * @param output LiquidStack representing output liquid. Amount is + * determined by fermentationValue*modifier. + * @throws NullPointerException if resource, output or liquid is null + */ + public void addRecipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output); +} diff --git a/forestry_common/core/forestry/api/recipes/IGenericCrate.java b/forestry_common/core/forestry/api/recipes/IGenericCrate.java new file mode 100755 index 000000000..06121b6cb --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/IGenericCrate.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; + +public interface IGenericCrate { + + void setContained(ItemStack crate, ItemStack contained); + + ItemStack getContained(ItemStack crate); + +} diff --git a/forestry_common/core/forestry/api/recipes/IMoistenerManager.java b/forestry_common/core/forestry/api/recipes/IMoistenerManager.java new file mode 100755 index 000000000..fe92700cd --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/IMoistenerManager.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; + +/** + * Provides an interface to the recipe manager of the moistener. + * + * The manager is initialized at the beginning of Forestry's BaseMod.load() cycle. Begin adding recipes in BaseMod.ModsLoaded() and this shouldn't be null even + * if your mod loads before Forestry. + * + * Accessible via {@link RecipeManagers} + * + * @author SirSengir + */ +public interface IMoistenerManager extends ICraftingProvider { + + /** + * Add a recipe to the moistener + * + * @param resource + * Item required in resource stack. Will be reduced by one per produced item. + * @param product + * Item to produce per resource processed. + * @param timePerItem + * Moistener runs at 1 - 4 time ticks per ingame tick depending on light level. For mycelium this value is currently 5000. + */ + public void addRecipe(ItemStack resource, ItemStack product, int timePerItem); +} diff --git a/forestry_common/core/forestry/api/recipes/ISqueezerManager.java b/forestry_common/core/forestry/api/recipes/ISqueezerManager.java new file mode 100755 index 000000000..108493460 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/ISqueezerManager.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.fluids.FluidStack; + +/** + * Provides an interface to the recipe manager of the suqeezer. + * + * The manager is initialized at the beginning of Forestry's BaseMod.load() cycle. Begin adding recipes in BaseMod.ModsLoaded() and this shouldn't be null even + * if your mod loads before Forestry. + * + * Accessible via {@link RecipeManagers} + * + * @author SirSengir + */ +public interface ISqueezerManager extends ICraftingProvider { + + /** + * Add a recipe to the squeezer. + * + * @param timePerItem + * Number of work cycles required to squeeze one set of resources. + * @param resources + * Array of item stacks representing the required resources for one process. Stack size will be taken into account. + * @param liquid + * {@link FluidStack} representing the output of this recipe. + * @param remnants + * Item stack representing the possible remnants from this recipe. + * @param chance + * Chance remnants will be produced by a single recipe cycle. + */ + public void addRecipe(int timePerItem, ItemStack[] resources, FluidStack liquid, ItemStack remnants, int chance); + + /** + * Add a recipe to the squeezer. + * + * @param timePerItem + * Number of work cycles required to squeeze one set of resources. + * @param resources + * Array of item stacks representing the required resources for one process. Stack size will be taken into account. + * @param liquid + * {@link FluidStack} representing the output of this recipe. + */ + public void addRecipe(int timePerItem, ItemStack[] resources, FluidStack liquid); +} diff --git a/forestry_common/core/forestry/api/recipes/IStillManager.java b/forestry_common/core/forestry/api/recipes/IStillManager.java new file mode 100755 index 000000000..fdeaf01f6 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/IStillManager.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraftforge.fluids.FluidStack; + +/** + * Provides an interface to the recipe manager of the still. + * + * The manager is initialized at the beginning of Forestry's BaseMod.load() cycle. Begin adding recipes in BaseMod.ModsLoaded() and this shouldn't be null even + * if your mod loads before Forestry. + * + * Accessible via {@link RecipeManagers} + * + * Note that this is untested with anything other than biomass->biofuel conversion. + * + * @author SirSengir + */ +public interface IStillManager extends ICraftingProvider { + /** + * Add a recipe to the still + * + * @param cyclesPerUnit + * Amount of work cycles required to run through the conversion once. + * @param input + * ItemStack representing the input liquid. + * @param output + * ItemStack representing the output liquid + */ + public void addRecipe(int cyclesPerUnit, FluidStack input, FluidStack output); +} diff --git a/forestry_common/core/forestry/api/recipes/IVariableFermentable.java b/forestry_common/core/forestry/api/recipes/IVariableFermentable.java new file mode 100755 index 000000000..5b7d1a871 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/IVariableFermentable.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import net.minecraft.item.ItemStack; + +/** + * Fermenter checks any valid fermentation item for an implementation of this interface. + * This does not supersede adding a proper recipe to the fermenter! + */ +public interface IVariableFermentable { + + /** + * @param itemstack + * @return Float representing the modification to be applied to the matching recipe's biomass output. + */ + float getFermentationModifier(ItemStack itemstack); +} diff --git a/forestry_common/core/forestry/api/recipes/RecipeManagers.java b/forestry_common/core/forestry/api/recipes/RecipeManagers.java new file mode 100755 index 000000000..3b3fae344 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/RecipeManagers.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.recipes; + +import java.util.Collection; + +/** + * Contains all available recipe managers for Forestry machines and items. + * + * @author SirSengir + */ +public class RecipeManagers { + + public static Collection craftingProviders; + + /** + * Allows you to add recipes to the bottler. See {@link IBottlerManager} for details. + */ + public static IBottlerManager bottlerManager; + /** + * Allows you to add recipes to the carpenter. See {@link ICarpenterManager} for details. + */ + public static ICarpenterManager carpenterManager; + /** + * Allows you to add recipes to the centrifuge. See {@link ICentrifugeManager} for details. + */ + public static ICentrifugeManager centrifugeManager; + /** + * Allows you to add recipes to the fermenter. See {@link IFermenterManager} for details. + */ + public static IFermenterManager fermenterManager; + /** + * Allows you to add recipes to the moistener. See {@link IMoistenerManager} for details. + */ + public static IMoistenerManager moistenerManager; + /** + * Allows you to add recipes to the squeezer. See {@link ISqueezerManager} for details. + */ + public static ISqueezerManager squeezerManager; + /** + * Allows you to add recipes to the still. See {@link IStillManager} for details. + */ + public static IStillManager stillManager; + + public static IFabricatorManager fabricatorManager; +} diff --git a/forestry_common/core/forestry/api/recipes/package-info.java b/forestry_common/core/forestry/api/recipes/package-info.java new file mode 100755 index 000000000..b1da99013 --- /dev/null +++ b/forestry_common/core/forestry/api/recipes/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|recipes") +package forestry.api.recipes; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/storage/BackpackEvent.java b/forestry_common/core/forestry/api/storage/BackpackEvent.java new file mode 100755 index 000000000..da0032e39 --- /dev/null +++ b/forestry_common/core/forestry/api/storage/BackpackEvent.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.storage; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; + +import cpw.mods.fml.common.eventhandler.Event; + + +public abstract class BackpackEvent extends Event { + + public final EntityPlayer player; + public final IBackpackDefinition backpackDefinition; + public final IInventory backpackInventory; + + public BackpackEvent(EntityPlayer player, IBackpackDefinition backpackDefinition, IInventory backpackInventory) { + this.player = player; + this.backpackDefinition = backpackDefinition; + this.backpackInventory = backpackInventory; + } +} diff --git a/forestry_common/core/forestry/api/storage/BackpackManager.java b/forestry_common/core/forestry/api/storage/BackpackManager.java new file mode 100755 index 000000000..8999416f1 --- /dev/null +++ b/forestry_common/core/forestry/api/storage/BackpackManager.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.storage; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.item.ItemStack; + +public class BackpackManager { + /** + * 0 - Miner's Backpack 1 - Digger's Backpack 2 - Forester's Backpack 3 - Hunter's Backpack 4 - Adventurer's Backpack + * + * Use IMC messages to achieve the same effect! + */ + public static ArrayList[] backpackItems; + + public static IBackpackInterface backpackInterface; + + /** + * Only use this if you know what you are doing. Prefer backpackInterface. + */ + public static HashMap definitions = new HashMap(); +} diff --git a/forestry_common/core/forestry/api/storage/BackpackResupplyEvent.java b/forestry_common/core/forestry/api/storage/BackpackResupplyEvent.java new file mode 100755 index 000000000..8a1ac9e06 --- /dev/null +++ b/forestry_common/core/forestry/api/storage/BackpackResupplyEvent.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.storage; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; + +import cpw.mods.fml.common.eventhandler.Cancelable; + +/** + * Use @SubscribeEvent on a method taking this event as an argument. Will fire whenever a backpack tries to resupply to a player inventory. Processing will stop + * if the event is canceled. + */ +@Cancelable +public class BackpackResupplyEvent extends BackpackEvent { + + public BackpackResupplyEvent(EntityPlayer player, IBackpackDefinition backpackDefinition, IInventory backpackInventory) { + super(player, backpackDefinition, backpackInventory); + } + +} diff --git a/forestry_common/core/forestry/api/storage/BackpackStowEvent.java b/forestry_common/core/forestry/api/storage/BackpackStowEvent.java new file mode 100755 index 000000000..195fce1b5 --- /dev/null +++ b/forestry_common/core/forestry/api/storage/BackpackStowEvent.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.storage; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.eventhandler.Cancelable; + +/** + * Use @SubscribeEvent on a method taking this event as an argument. Will fire whenever a backpack tries to store an item. Processing will stop if the stacksize + * of stackToStow drops to 0 or less or the event is canceled. + */ +@Cancelable +public class BackpackStowEvent extends BackpackEvent { + + public final ItemStack stackToStow; + + public BackpackStowEvent(EntityPlayer player, IBackpackDefinition backpackDefinition, IInventory backpackInventory, ItemStack stackToStow) { + super(player, backpackDefinition, backpackInventory); + this.stackToStow = stackToStow; + } +} diff --git a/forestry_common/core/forestry/api/storage/EnumBackpackType.java b/forestry_common/core/forestry/api/storage/EnumBackpackType.java new file mode 100755 index 000000000..c56121d5e --- /dev/null +++ b/forestry_common/core/forestry/api/storage/EnumBackpackType.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.storage; + +public enum EnumBackpackType { + T1, T2 +} diff --git a/forestry_common/core/forestry/api/storage/IBackpackDefinition.java b/forestry_common/core/forestry/api/storage/IBackpackDefinition.java new file mode 100755 index 000000000..6203b015e --- /dev/null +++ b/forestry_common/core/forestry/api/storage/IBackpackDefinition.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.storage; + +import java.util.Collection; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public interface IBackpackDefinition { + + /** + * @return A unique string identifier + */ + String getKey(); + + /** + * @return Human-readable name of the backpack. + */ + String getName(); + + /** + * @return Primary colour for the backpack icon. + */ + int getPrimaryColour(); + + /** + * @return Secondary colour for backpack icon. + */ + int getSecondaryColour(); + + /** + * Adds an item as valid for this backpack. + * + * @param validItem + */ + void addValidItem(ItemStack validItem); + + /** + * Returns an arraylist of all items valid for this backpack type. + * + * @param player + * @return Collection of itemstack which are valid items for this backpack type. May be empty or null and does not necessarily include all valid items. + */ + Collection getValidItems(EntityPlayer player); + + /** + * Returns true if the itemstack is a valid item for this backpack type. + * + * @param player + * @param itemstack + * @return true if the given itemstack is valid for this backpack, false otherwise. + */ + boolean isValidItem(EntityPlayer player, ItemStack itemstack); + +} diff --git a/forestry_common/core/forestry/api/storage/IBackpackInterface.java b/forestry_common/core/forestry/api/storage/IBackpackInterface.java new file mode 100755 index 000000000..2450cc188 --- /dev/null +++ b/forestry_common/core/forestry/api/storage/IBackpackInterface.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.storage; + +import net.minecraft.item.Item; + +public interface IBackpackInterface { + + /** + * Adds a backpack with the given definition and type, returning the item. + * + * @param definition + * Definition of backpack behaviour. + * @param type + * Type of backpack. (T1 or T2 (= Woven) + * @return Created backpack item. + */ + Item addBackpack(IBackpackDefinition definition, EnumBackpackType type); +} diff --git a/forestry_common/core/forestry/api/storage/package-info.java b/forestry_common/core/forestry/api/storage/package-info.java new file mode 100755 index 000000000..e18563c62 --- /dev/null +++ b/forestry_common/core/forestry/api/storage/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|storage") +package forestry.api.storage; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/api/world/ITreeGenData.java b/forestry_common/core/forestry/api/world/ITreeGenData.java new file mode 100755 index 000000000..2858ad0b0 --- /dev/null +++ b/forestry_common/core/forestry/api/world/ITreeGenData.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.world; + +import net.minecraft.world.World; + +public interface ITreeGenData { + + int getGirth(World world, int x, int y, int z); + + float getHeightModifier(); + + boolean canGrow(World world, int x, int y, int z, int expectedGirth, int expectedHeight); + + void setLeaves(World world, String owner, int x, int y, int z); + + boolean allowsFruitBlocks(); + + boolean trySpawnFruitBlock(World world, int x, int y, int z); +} diff --git a/forestry_common/core/forestry/api/world/IWorldGenInterface.java b/forestry_common/core/forestry/api/world/IWorldGenInterface.java new file mode 100755 index 000000000..91d2abcc2 --- /dev/null +++ b/forestry_common/core/forestry/api/world/IWorldGenInterface.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.world; + +import net.minecraft.world.gen.feature.WorldGenerator; + +public interface IWorldGenInterface { + + /** + * Retrieves generators for trees identified by a given string. + * + * Returned generator classes take an {@link ITreeGenData} in the constructor. + * + * @param ident + * Unique identifier for tree type. Forestry's convention is 'treeSpecies', i.e. 'treeBaobab', 'treeSequoia'. + * @return All generators matching the given ident. + */ + Class[] getTreeGenerators(String ident); +} diff --git a/forestry_common/core/forestry/api/world/WorldGenManager.java b/forestry_common/core/forestry/api/world/WorldGenManager.java new file mode 100755 index 000000000..0a5accd0c --- /dev/null +++ b/forestry_common/core/forestry/api/world/WorldGenManager.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.api.world; + +public class WorldGenManager { + public static IWorldGenInterface worldgenInterface; +} diff --git a/forestry_common/core/forestry/api/world/package-info.java b/forestry_common/core/forestry/api/world/package-info.java new file mode 100755 index 000000000..25762a119 --- /dev/null +++ b/forestry_common/core/forestry/api/world/package-info.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +@API(apiVersion="1.0", owner="ForestryAPI|core", provides="ForestryAPI|world") +package forestry.api.world; +import cpw.mods.fml.common.API; diff --git a/forestry_common/core/forestry/core/CommandForestry.java b/forestry_common/core/forestry/core/CommandForestry.java new file mode 100755 index 000000000..c4f55d29d --- /dev/null +++ b/forestry_common/core/forestry/core/CommandForestry.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import java.util.List; + +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommand; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; + +import forestry.api.core.IPlugin; +import forestry.api.core.PluginInfo; +import forestry.core.config.Version; +import forestry.core.proxy.Proxies; +import forestry.core.utils.CommandMC; +import forestry.plugins.PluginManager; + +public class CommandForestry extends CommandMC { + + @Override + public int compareTo(Object arg0) { + return this.getCommandName().compareTo(((ICommand) arg0).getCommandName()); + } + + @Override + public String getCommandName() { + return "forestry"; + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return "/" + this.getCommandName() + " help"; + } + + @SuppressWarnings("rawtypes") + @Override + public List getCommandAliases() { + return null; + } + + @Override + public void processCommand(ICommandSender sender, String[] arguments) { + + if (arguments.length <= 0) + throw new WrongUsageException("Type '" + this.getCommandUsage(sender) + "' for help."); + + if (arguments[0].matches("version")) { + commandVersion(sender, arguments); + return; + } else if (arguments[0].matches("plugins")) { + commandPlugins(sender, arguments); + return; + } else if (arguments[0].matches("help")) { + sendChatMessage(sender, "Format: '" + this.getCommandName() + " '"); + sendChatMessage(sender, "Available commands:"); + sendChatMessage(sender, "- version : Version information."); + sendChatMessage(sender, "- plugins : list of Forestry plugins."); + sendChatMessage(sender, "- plugins info : information on plugin."); + return; + } + + throw new WrongUsageException(this.getCommandUsage(sender)); + } + + private void commandVersion(ICommandSender sender, String[] arguments) { + String colour = Version.isOutdated() ? "\u00A7c" : "\u00A7a"; + + sendChatMessage(sender, String.format(colour + "Forestry %s for Minecraft %s (Latest: %s).", Version.getVersion(), + Proxies.common.getMinecraftVersion(), Version.getRecommendedVersion())); + if (Version.isOutdated()) + for (String updateLine : Version.getChangelog()) + sendChatMessage(sender, "\u00A79" + updateLine); + } + + private void commandPlugins(ICommandSender sender, String[] arguments) { + + if (arguments.length <= 1) + listPluginsForSender(sender); + else if (arguments[1].matches("info")) + listPluginInfoForSender(sender, arguments); + + } + + private void listPluginsForSender(ICommandSender sender) { + + String pluginList = ""; + + for (IPlugin plugin : PluginManager.plugins) { + if (!pluginList.isEmpty()) + pluginList += ", "; + pluginList += makeListEntry(plugin); + } + + sendChatMessage(sender, pluginList); + } + + private void listPluginInfoForSender(ICommandSender sender, String[] arguments) { + + if (arguments.length < 3) + throw new WrongUsageException("/" + getCommandName() + " plugins info "); + + IPlugin found = null; + for (IPlugin plugin : PluginManager.plugins) { + PluginInfo info = plugin.getClass().getAnnotation(PluginInfo.class); + if (info == null) + continue; + + if ((info.pluginID().equalsIgnoreCase(arguments[2]) || info.name().equalsIgnoreCase(arguments[2]))) { + found = plugin; + break; + } + } + + if (found == null) + throw new CommandException("No information available for plugin " + arguments[2] + "."); + + String entry = "\u00A7c"; + if (found.isAvailable()) + entry = "\u00A7a"; + PluginInfo info = found.getClass().getAnnotation(PluginInfo.class); + if (info != null) { + sendChatMessage(sender, entry + "Plugin: " + info.name()); + if (!info.version().isEmpty()) + sendChatMessage(sender, "\u00A79Version: " + info.version()); + if (!info.author().isEmpty()) + sendChatMessage(sender, "\u00A79Author(s): " + info.author()); + if (!info.url().isEmpty()) + sendChatMessage(sender, "\u00A79URL: " + info.url()); + if (!info.description().isEmpty()) + sendChatMessage(sender, info.description()); + } + + } + + private String makeListEntry(IPlugin plugin) { + String entry = "\u00A7c"; + if (plugin.isAvailable()) + entry = "\u00A7a"; + + PluginInfo info = plugin.getClass().getAnnotation(PluginInfo.class); + if (info != null) { + entry += info.pluginID(); + if (!info.version().isEmpty()) + entry += " (" + info.version() + ")"; + } else + entry += "???"; + + return entry; + } + + @Override + public boolean canCommandSenderUseCommand(ICommandSender sender) { + if (sender instanceof EntityPlayer) + return Proxies.common.isOp((EntityPlayer) sender); + else + return sender.canCommandSenderUseCommand(4, getCommandName()); + } + +} diff --git a/forestry_common/core/forestry/core/CreativeTabForestry.java b/forestry_common/core/forestry/core/CreativeTabForestry.java new file mode 100755 index 000000000..7cf288bdf --- /dev/null +++ b/forestry_common/core/forestry/core/CreativeTabForestry.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import forestry.api.core.ItemInterface; +import forestry.api.core.Tabs; +import forestry.core.utils.StringUtil; + +public class CreativeTabForestry extends CreativeTabs { + + static { + Tabs.tabApiculture = new CreativeTabForestry(1, "apiculture"); + Tabs.tabArboriculture = new CreativeTabForestry(2, "arboriculture"); + Tabs.tabLepidopterology = new CreativeTabForestry(3, "lepidopterology"); + } + public static final CreativeTabs tabForestry = new CreativeTabForestry(0, "forestry"); + + private final int icon; + + public CreativeTabForestry(int icon, String label) { + super(label); + this.icon = icon; + } + + @Override + public ItemStack getIconItemStack() { + switch (icon) { + case 1: + return ItemInterface.getItem("beeDroneGE"); + case 2: + return ItemInterface.getItem("sapling"); + case 3: + return ItemInterface.getItem("butterflyGE"); + case 0: + default: + return ItemInterface.getItem("fertilizerCompound"); + } + } + + @Override + public String getTranslatedTabLabel() { + return StringUtil.localize("itemGroup." + this.getTabLabel()); + } + + @Override + public Item getTabIconItem() { + return null; // not used due to overridden getIconItemStack + } +} diff --git a/forestry_common/core/forestry/core/EnumErrorCode.java b/forestry_common/core/forestry/core/EnumErrorCode.java new file mode 100755 index 000000000..cd41ed758 --- /dev/null +++ b/forestry_common/core/forestry/core/EnumErrorCode.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.render.TextureManager; + +public enum EnumErrorCode { + + UNKNOWN("unknown", 0), + + OK("ok", 1), + + INVALIDBIOME("invalidBiome", 2), + + ISRAINING("isRaining", 3), + + NOTRAINING("notRaining", 4), + + NOFUEL("noFuel", 5), // Biogas & Peat-fired + + NOHEAT("noHeat", 6), // Biogas engine + + NODISPOSAL("noDisposal", 7), + + NORESOURCE("noResource", 8), + + NOTGLOOMY("notGloomy", 9), + + NOTLUCID("notLucid", 10), + + NOTDAY("notDay", 11), + + NOTNIGHT("notNight", 12), + + NOFLOWER("noFlower", 13), + + NOQUEEN("noQueen", 14), + + NODRONE("noDrone", 15), + + NOSKY("noSky", 16), + + NOSPACE("noSpace", 17), + + NORECIPE("noRecipe", 19), + + NOENERGYNET("noEnergyNet", 20), + + NOTHINGANALYZE("noSpecimen", 15), + + FORCEDCOOLDOWN("forcedCooldown", 21), + + NOHONEY("noHoney", 22), + + NOTPOSTPAID("notPostpaid", 23), + + NORECIPIENT("noRecipient", 24), + + NOTALPHANUMERIC("notAlphaNumeric", 25), + + NOTUNIQUE("notUnique", 26), + + NOSTAMPS("noStamps", 23), + + NOCIRCUITBOARD("noCircuitBoard", 28), + + WRONGSTACKSIZE("wrongStacksize", 26), + + NOFERTILIZER("noFertilizer", 5), + + NOFARMLAND("noFarmland", 27), + + CIRCUITMISMATCH("circuitMismatch", 26), + + NOLIQUID("noLiquid", 29); + + private String name; + @SideOnly(Side.CLIENT) + private IIcon icon; + + private EnumErrorCode(String name, int iconIndex) { + this.name = name; + } + + public String getDescription() { + return "errors." + name + ".desc"; + } + + public String getHelp() { + return "errors." + name + ".help"; + } + + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + icon = TextureManager.getInstance().registerTex(register, "errors/" + name); + } + + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return icon; + } + + @SideOnly(Side.CLIENT) + public static void initIcons(IIconRegister register) { + for (EnumErrorCode code : values()) + code.registerIcons(register); + } +} diff --git a/forestry_common/core/forestry/core/EventHandlerCore.java b/forestry_common/core/forestry/core/EventHandlerCore.java new file mode 100755 index 000000000..c5f576990 --- /dev/null +++ b/forestry_common/core/forestry/core/EventHandlerCore.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.eventhandler.Event.Result; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.event.entity.player.EntityItemPickupEvent; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.oredict.OreDictionary; + +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPickupHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.render.TextureManager; +import forestry.core.utils.LiquidHelper; +import forestry.plugins.PluginManager; + +public class EventHandlerCore { + + public EventHandlerCore() { + for(String name : OreDictionary.getOreNames()) + for(ItemStack ore : OreDictionary.getOres(name)) + handleOreRegistration(name, ore); + } + + @SubscribeEvent + public void handleItemPickup(EntityItemPickupEvent event) { + + if (event.isCanceled()) + return; + + for (IPickupHandler handler : PluginManager.pickupHandlers) + if (!handler.onItemPickup(event.entityPlayer, event.item)) { + event.setResult(Result.ALLOW); + return; + } + } + + @SubscribeEvent + public void handleOreRegistration(OreDictionary.OreRegisterEvent event) { + + if (event.isCanceled()) + return; + + handleOreRegistration(event.Name, event.Ore); + } + + private void handleOreRegistration(String name, ItemStack ore) { + for (IOreDictionaryHandler handler : PluginManager.dictionaryHandlers) + handler.onOreRegistration(name, ore); + } + + @SubscribeEvent + public void handleWorldLoad(WorldEvent.Load event) { + for (ISaveEventHandler handler : PluginManager.saveEventHandlers) + handler.onWorldLoad(event.world); + } + + @SubscribeEvent + public void handleWorldSave(WorldEvent.Save event) { + for (ISaveEventHandler handler : PluginManager.saveEventHandlers) + handler.onWorldSave(event.world); + } + + @SubscribeEvent + public void handleWorldUnload(WorldEvent.Unload event) { + for (ISaveEventHandler handler : PluginManager.saveEventHandlers) + handler.onWorldUnload(event.world); + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public void handleTextureRemap(TextureStitchEvent.Pre event) { + if(event.map.getTextureType() == 1) { + EnumErrorCode.initIcons(event.map); + TextureManager.getInstance().initDefaultIcons(event.map); + } else if(event.map.getTextureType() == 0) + LiquidHelper.resetLiquidIcons(event.map); + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public void handleTexturePostmap(TextureStitchEvent.Post event) { + } + +} diff --git a/forestry_common/core/forestry/core/ForestryClient.java b/forestry_common/core/forestry/core/ForestryClient.java new file mode 100755 index 000000000..480f2d50c --- /dev/null +++ b/forestry_common/core/forestry/core/ForestryClient.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import cpw.mods.fml.client.registry.RenderingRegistry; + +import forestry.apiculture.render.BlockCandleRenderer; +import forestry.core.proxy.Proxies; +import forestry.core.render.BlockRenderingHandler; + +public class ForestryClient extends ForestryCore { + + public static int byBlockModelId; + public static int candleRenderId; + public static int blockModelIdEngine; + + @Override + public void init(Object basemod) { + + super.init(basemod); + + byBlockModelId = Proxies.render.getNextAvailableRenderId(); + candleRenderId = Proxies.render.getNextAvailableRenderId(); + blockModelIdEngine = Proxies.render.getNextAvailableRenderId(); + + BlockRenderingHandler renderHandler = new BlockRenderingHandler(); + RenderingRegistry.registerBlockHandler(byBlockModelId, renderHandler); + RenderingRegistry.registerBlockHandler(candleRenderId, new BlockCandleRenderer()); + } + + @Override + public void postInit() { + super.postInit(); + } + +} diff --git a/forestry_common/core/forestry/core/ForestryConstants.java b/forestry_common/core/forestry/core/ForestryConstants.java new file mode 100755 index 000000000..a45f7c057 --- /dev/null +++ b/forestry_common/core/forestry/core/ForestryConstants.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import forestry.api.core.IForestryConstants; +import forestry.core.config.Defaults; + +public class ForestryConstants implements IForestryConstants { + + @Override + public int getApicultureVillagerID() { + return Defaults.ID_VILLAGER_BEEKEEPER; + } + + @Override + public int getArboricultureVillagerID() { + return Defaults.ID_VILLAGER_LUMBERJACK; + } + + @Override + public String getVillagerChestGenKey() { + return Defaults.CHEST_GEN_HOOK_NATURALIST_CHEST; + } + +} diff --git a/forestry_common/core/forestry/core/ForestryCore.java b/forestry_common/core/forestry/core/ForestryCore.java new file mode 100755 index 000000000..1d5cd84d5 --- /dev/null +++ b/forestry_common/core/forestry/core/ForestryCore.java @@ -0,0 +1,251 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import java.io.File; + +import net.minecraft.command.CommandHandler; +import net.minecraft.command.ICommand; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.server.MinecraftServer; + +import cpw.mods.fml.common.event.FMLInterModComms; +import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage; +import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.registry.GameRegistry; + +import net.minecraftforge.common.MinecraftForge; + +import com.google.common.collect.ImmutableList; + +import forestry.api.apiculture.FlowerManager; +import forestry.api.core.ForestryAPI; +import forestry.api.core.IPlugin; +import forestry.api.fuels.EngineBronzeFuel; +import forestry.api.fuels.EngineCopperFuel; +import forestry.api.fuels.FermenterFuel; +import forestry.api.fuels.FuelManager; +import forestry.api.fuels.MoistenerFuel; +import forestry.api.fuels.RainSubstrate; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.config.Version; +import forestry.core.gadgets.TileEngine; +import forestry.core.gadgets.TileMachine; +import forestry.core.gadgets.TileMill; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.plugins.NativePlugin; +import forestry.plugins.PluginCore; +import forestry.plugins.PluginManager; + +public class ForestryCore { + + public void preInit(File modLocation, Object basemod) { + ForestryAPI.instance = basemod; + ForestryAPI.forestryConstants = new ForestryConstants(); + + PluginManager.loadPlugins(modLocation); + + // Register event handler + MinecraftForge.EVENT_BUS.register(new EventHandlerCore()); + + Config.load(); + if (!Config.disableVersionCheck) + Version.versionCheck(); + + for (IPlugin plugin : PluginManager.plugins) { + if (plugin instanceof PluginCore) + plugin.preInit(); + } + + for (IPlugin plugin : PluginManager.plugins) { + if (plugin instanceof PluginCore) + continue; + + if (plugin.isAvailable()) + plugin.preInit(); + else + Proxies.log.fine("Skipped plugin " + plugin.getClass() + " because preconditions were not met."); + } + + } + + public void init(Object basemod) { + + // Register Liquids & Containers + registerLiquidContainers(); + + // Register world generator + GameRegistry.registerWorldGenerator(new WorldGenerator(), 0); + + // Set fuels and resources for the fermenter + FuelManager.fermenterFuel.put(ForestryItem.fertilizerCompound.getItemStack(), new FermenterFuel(ForestryItem.fertilizerCompound.getItemStack(), + GameMode.getGameMode().getIntegerSetting("fermenter.value.fertilizer"), GameMode.getGameMode().getIntegerSetting("fermenter.cycles.fertilizer"))); + FuelManager.fermenterFuel.put(ForestryItem.fertilizerBio.getItemStack(), new FermenterFuel(ForestryItem.fertilizerBio.getItemStack(), GameMode + .getGameMode().getIntegerSetting("fermenter.value.compost"), GameMode.getGameMode().getIntegerSetting("fermenter.cycles.compost"))); + FuelManager.fermenterFuel.put(ForestryItem.mulch.getItemStack(), new FermenterFuel(ForestryItem.mulch.getItemStack(), GameMode.getGameMode() + .getIntegerSetting("fermenter.value.compost"), GameMode.getGameMode().getIntegerSetting("fermenter.cycles.compost"))); + + // Add moistener resources + FuelManager.moistenerResource.put(new ItemStack(Items.wheat), new MoistenerFuel(new ItemStack(Items.wheat), ForestryItem.mouldyWheat.getItemStack(), 0, + 300)); + FuelManager.moistenerResource.put(ForestryItem.mouldyWheat.getItemStack(), new MoistenerFuel(ForestryItem.mouldyWheat.getItemStack(), ForestryItem.decayingWheat.getItemStack(), 1, 600)); + FuelManager.moistenerResource.put(ForestryItem.decayingWheat.getItemStack(), new MoistenerFuel(ForestryItem.decayingWheat.getItemStack(), + ForestryItem.mulch.getItemStack(), 2, 900)); + + // Set fuels for our own engines + FuelManager.copperEngineFuel.put(ForestryItem.peat.getItemStack(), new EngineCopperFuel(ForestryItem.peat.getItemStack(), + Defaults.ENGINE_COPPER_FUEL_VALUE_PEAT, Defaults.ENGINE_COPPER_CYCLE_DURATION_PEAT)); + FuelManager.copperEngineFuel.put(ForestryItem.bituminousPeat.getItemStack(), new EngineCopperFuel(ForestryItem.bituminousPeat.getItemStack(), + Defaults.ENGINE_COPPER_FUEL_VALUE_BITUMINOUS_PEAT, Defaults.ENGINE_COPPER_CYCLE_DURATION_BITUMINOUS_PEAT)); + FuelManager.bronzeEngineFuel.put(LiquidHelper.getFluid(Defaults.LIQUID_BIOMASS), new EngineBronzeFuel(LiquidHelper.getFluid(Defaults.LIQUID_BIOMASS), + Defaults.ENGINE_FUEL_VALUE_BIOMASS, (int) (Defaults.ENGINE_CYCLE_DURATION_BIOMASS * GameMode.getGameMode().getFloatSetting("fuel.biomass.biogas")), 1)); + FuelManager.bronzeEngineFuel.put(LiquidHelper.getFluid(Defaults.LIQUID_WATER), new EngineBronzeFuel(LiquidHelper.getFluid(Defaults.LIQUID_WATER), + Defaults.ENGINE_FUEL_VALUE_WATER, Defaults.ENGINE_CYCLE_DURATION_WATER, 3)); + FuelManager.bronzeEngineFuel.put(LiquidHelper.getFluid(Defaults.LIQUID_MILK), new EngineBronzeFuel(LiquidHelper.getFluid(Defaults.LIQUID_MILK), + Defaults.ENGINE_FUEL_VALUE_MILK, Defaults.ENGINE_CYCLE_DURATION_MILK, 3)); + FuelManager.bronzeEngineFuel.put(LiquidHelper.getFluid(Defaults.LIQUID_SEEDOIL), new EngineBronzeFuel(LiquidHelper.getFluid(Defaults.LIQUID_SEEDOIL), + Defaults.ENGINE_FUEL_VALUE_SEED_OIL, Defaults.ENGINE_CYCLE_DURATION_SEED_OIL, 1)); + FuelManager.bronzeEngineFuel.put(LiquidHelper.getFluid(Defaults.LIQUID_HONEY), new EngineBronzeFuel(LiquidHelper.getFluid(Defaults.LIQUID_HONEY), + Defaults.ENGINE_FUEL_VALUE_HONEY, Defaults.ENGINE_CYCLE_DURATION_HONEY, 1)); + FuelManager.bronzeEngineFuel.put(LiquidHelper.getFluid(Defaults.LIQUID_JUICE), new EngineBronzeFuel(LiquidHelper.getFluid(Defaults.LIQUID_JUICE), + Defaults.ENGINE_FUEL_VALUE_JUICE, Defaults.ENGINE_CYCLE_DURATION_JUICE, 1)); + + // Set rain substrates + FuelManager.rainSubstrate.put(ForestryItem.iodineCharge.getItemStack(), new RainSubstrate(ForestryItem.iodineCharge.getItemStack(), + Defaults.RAINMAKER_RAIN_DURATION_IODINE, 0.01f)); + FuelManager.rainSubstrate.put(ForestryItem.craftingMaterial.getItemStack(1, 4), new RainSubstrate(ForestryItem.craftingMaterial.getItemStack(1, 4), 0.075f)); + + // Set additional apiary flowers + FlowerManager.plainFlowers.add(new ItemStack(Blocks.red_flower)); + FlowerManager.plainFlowers.add(new ItemStack(Blocks.yellow_flower)); + + // Register gui handler + NetworkRegistry.INSTANCE.registerGuiHandler(basemod, new GuiHandler()); + + // Register machines + GameRegistry.registerTileEntity(TileMill.class, "forestry.Grower"); + GameRegistry.registerTileEntity(TileEngine.class, "forestry.Engine"); + GameRegistry.registerTileEntity(TileMachine.class, "forestry.Machine"); + + + } + + public void postInit() { + + for (IPlugin plugin : PluginManager.plugins) { + if (plugin.isAvailable()) + plugin.doInit(); + } + + for (IPlugin plugin : PluginManager.plugins) { + if (plugin.isAvailable()) + plugin.postInit(); + } + + Proxies.common.registerTickHandlers(); + + // Handle IMC messages. + processIMCMessages(FMLInterModComms.fetchRuntimeMessages(ForestryAPI.instance)); + } + + public void serverStarting(MinecraftServer server) { + CommandHandler commandManager = (CommandHandler) server.getCommandManager(); + for (IPlugin plugin : PluginManager.plugins) { + if (plugin.isAvailable() && plugin instanceof NativePlugin) { + ICommand[] commands = ((NativePlugin) plugin).getConsoleCommands(); + if (commands == null) + continue; + for (ICommand command : commands) { + commandManager.registerCommand(command); + } + } + } + } + + public void processIMCMessages(ImmutableList messages) { + for (IMCMessage message : messages) { + for (IPlugin plugin : PluginManager.plugins) { + if (!(plugin instanceof NativePlugin)) + continue; + + if (((NativePlugin) plugin).processIMCMessage(message)) + break; + } + } + } + + public String getPriorities() { + return "after:mod_IC2;after:mod_BuildCraftCore;after:mod_BuildCraftEnergy;after:mod_BuildCraftFactory;after:mod_BuildCraftSilicon;after:mod_BuildCraftTransport;after:mod_RedPowerWorld"; + } + + private void registerLiquidContainers() { + // Add lava and water buckets to the API in case this has not been done yet. + if (LiquidHelper.isEmptyLiquidData()) { + LiquidHelper.injectLiquidContainer(Defaults.LIQUID_LAVA, Defaults.BUCKET_VOLUME, new ItemStack(Items.lava_bucket), new ItemStack(Items.bucket)); + LiquidHelper.injectLiquidContainer(Defaults.LIQUID_WATER, Defaults.BUCKET_VOLUME, new ItemStack(Items.water_bucket), new ItemStack(Items.bucket)); + } + + // Glass + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_GLASS); + + // Set default lava, water and biofuel buckets + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_MILK); + LiquidHelper.injectLiquidContainer(Defaults.LIQUID_MILK, Defaults.BUCKET_VOLUME, new ItemStack(Items.milk_bucket), new ItemStack(Items.bucket)); + + // Lava + LiquidHelper.injectTinContainer(Defaults.LIQUID_LAVA, Defaults.BUCKET_VOLUME, ForestryItem.canLava.getItemStack(), + ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_LAVA, Defaults.BUCKET_VOLUME, ForestryItem.refractoryLava.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + // Water + LiquidHelper.injectLiquidContainer(Defaults.LIQUID_WATER, Defaults.BUCKET_VOLUME, new ItemStack(Items.potionitem, 1, 0), + new ItemStack(Items.glass_bottle)); + LiquidHelper.injectTinContainer(Defaults.LIQUID_WATER, Defaults.BUCKET_VOLUME, ForestryItem.canWater.getItemStack(), + ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_WATER, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleWater.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_WATER, Defaults.BUCKET_VOLUME, ForestryItem.refractoryWater.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_BIOMASS); + LiquidHelper.injectLiquidContainer(Defaults.LIQUID_BIOMASS, Defaults.BUCKET_VOLUME, ForestryItem.bucketBiomass.getItemStack(), new ItemStack(Items.bucket)); + LiquidHelper.injectTinContainer(Defaults.LIQUID_BIOMASS, Defaults.BUCKET_VOLUME, ForestryItem.canBiomass.getItemStack(), ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_BIOMASS, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleBiomass.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_BIOMASS, Defaults.BUCKET_VOLUME, ForestryItem.refractoryBiomass.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_ETHANOL); + LiquidHelper.injectLiquidContainer(Defaults.LIQUID_ETHANOL, Defaults.BUCKET_VOLUME, ForestryItem.bucketBiofuel.getItemStack(), new ItemStack(Items.bucket)); + LiquidHelper.injectTinContainer(Defaults.LIQUID_ETHANOL, Defaults.BUCKET_VOLUME, ForestryItem.canBiofuel.getItemStack(), ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_ETHANOL, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleBiofuel.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_ETHANOL, Defaults.BUCKET_VOLUME, ForestryItem.refractoryBiofuel.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_SEEDOIL); + LiquidHelper.injectTinContainer(Defaults.LIQUID_SEEDOIL, Defaults.BUCKET_VOLUME, ForestryItem.canSeedOil.getItemStack(), ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_SEEDOIL, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleSeedOil.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_SEEDOIL, Defaults.BUCKET_VOLUME, ForestryItem.refractorySeedOil.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_HONEY); + LiquidHelper.injectTinContainer(Defaults.LIQUID_HONEY, Defaults.BUCKET_VOLUME, ForestryItem.canHoney.getItemStack(), ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_HONEY, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleHoney.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_HONEY, Defaults.BUCKET_VOLUME, ForestryItem.refractoryHoney.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_JUICE); + LiquidHelper.injectTinContainer(Defaults.LIQUID_JUICE, Defaults.BUCKET_VOLUME, ForestryItem.canJuice.getItemStack(), ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_JUICE, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleJuice.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_JUICE, Defaults.BUCKET_VOLUME, ForestryItem.refractoryJuice.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_ICE); + LiquidHelper.injectTinContainer(Defaults.LIQUID_ICE, Defaults.BUCKET_VOLUME, ForestryItem.canIce.getItemStack(), ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_ICE, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleIce.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_ICE, Defaults.BUCKET_VOLUME, ForestryItem.refractoryIce.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + + } +} diff --git a/forestry_common/core/forestry/core/GameMode.java b/forestry_common/core/forestry/core/GameMode.java new file mode 100755 index 000000000..a544fa502 --- /dev/null +++ b/forestry_common/core/forestry/core/GameMode.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import java.util.HashMap; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import forestry.api.core.ForestryAPI; +import forestry.api.core.IGameMode; +import forestry.core.config.Config; +import forestry.core.config.Configuration; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.config.Property; +import forestry.core.proxy.Proxies; + +public class GameMode implements IGameMode { + + public static IGameMode getGameMode() { + + if (ForestryAPI.activeMode == null) + ForestryAPI.activeMode = new GameMode(Config.gameMode); + + return ForestryAPI.activeMode; + } + + private String identifier = "EASY"; + private final String category; + + private final HashMap booleanSettings = new HashMap(); + private final HashMap integerSettings = new HashMap(); + private final HashMap floatSettings = new HashMap(); + private final HashMap stackSettings = new HashMap(); + + private static final float ENERGY_DEMAND_MODIFIER = 1.0f; + private static final float FUEL_MODIFIER = 1.0f; + + private static final int FARM_FERTILIZER_VALUE = 2000; + + private final ItemStack recipeFertilizerOutputApatite = ForestryItem.fertilizerCompound.getItemStack(8); + private final ItemStack recipeFertilizerOutputAsh = ForestryItem.fertilizerCompound.getItemStack(16); + private final ItemStack recipeCompostOutputWheat = ForestryItem.fertilizerBio.getItemStack(4); + private final ItemStack recipeCompostOutputAsh = ForestryItem.fertilizerBio.getItemStack(1); + + private final ItemStack recipeHumusOutputFertilizer = new ItemStack(ForestryBlock.soil, 8, 0); + private final ItemStack recipeHumusOutputCompost = new ItemStack(ForestryBlock.soil, 8, 0); + + private final ItemStack recipeBogEarthOutputBucket = new ItemStack(ForestryBlock.soil, 6, 1); + private final ItemStack recipeBogEarthOutputCans = new ItemStack(ForestryBlock.soil, 8, 1); + + private final ItemStack recipeCanOutput = ForestryItem.canEmpty.getItemStack(12); + private final ItemStack recipeCapsuleOutput = ForestryItem.waxCapsule.getItemStack(4); + private final ItemStack recipeRefractoryOutput = ForestryItem.refractoryEmpty.getItemStack(4); + + private static final int FERMENTATION_DURATION_FERTILIZER = 200; + private static final int FERMENTATION_DURATION_COMPOST = 250; + + private static final int FERMENTED_CYCLE_FERTILIZER = 56; + private static final int FERMENTED_CYCLE_COMPOST = 48; + + private static final int FERMENTED_SAPLING = 250; + private static final int FERMENTED_CACTI = 50; + private static final int FERMENTED_WHEAT = 50; + private static final int FERMENTED_CANE = 50; + private static final int FERMENTED_MUSHROOM = 50; + + private static final int SQUEEZED_LIQUID_SEED = 10; + private static final int SQUEEZED_LIQUID_APPLE = 200; + private static final int SQUEEZED_MULCH_APPLE = 20; + + public GameMode(String identifier) { + + this.identifier = identifier; + this.category = "gamemodes/" + identifier; + + Configuration config = Config.config; + + initSetting("energy.demand.modifier", ENERGY_DEMAND_MODIFIER, -1, "modifies the energy required to activate machines, as well as the max amount of energy stored and accepted."); + initSetting("farms.fertilizer.value", FARM_FERTILIZER_VALUE, -1, "modifies the time a piece of fertilizer lasts in a farm."); + + initSetting("fuel.ethanol.generator", FUEL_MODIFIER, -1, "modifies the energy provided by ethanol in a Bio Generator."); + initSetting("fuel.ethanol.combustion", FUEL_MODIFIER, -1, "modifies the energy provided by ethanol in Buildcraft Combustion Engines."); + initSetting("fuel.biomass.generator", FUEL_MODIFIER, -1, "modifies the energy provided by Biomass in a Bio Generator."); + initSetting("fuel.biomass.biogas", FUEL_MODIFIER, -1, "modifies the energy provided by Biomass in Biogas Engines."); + + initSetting("recipe.output.fertilizer.apatite", recipeFertilizerOutputApatite, "amount of fertilizer yielded by the recipe using apatite."); + initSetting("recipe.output.fertilizer.ash", recipeFertilizerOutputAsh, "amount of fertilizer yielded by the recipe using ash."); + initSetting("recipe.output.compost.wheat", recipeCompostOutputWheat, "amount of compost yielded by the recipe using wheat."); + initSetting("recipe.output.compost.ash", recipeCompostOutputAsh, "amount of compost yielded by the recipe using ash."); + initSetting("recipe.output.humus.fertilizer", recipeHumusOutputFertilizer, "amount of humus yielded by the recipe using fertilizer."); + initSetting("recipe.output.humus.compost", recipeHumusOutputCompost, "amount of humus yielded by the recipe using compost."); + initSetting("recipe.output.bogearth.bucket", recipeBogEarthOutputBucket, "amount of bog earth yielded by the recipe using buckets."); + initSetting("recipe.output.bogearth.can", recipeBogEarthOutputCans, "amount of bog earth yielded by the recipes using cans, cells or capsules."); + + initSetting("recipe.output.can", recipeCanOutput, "amount yielded by the recipe for tin cans."); + initSetting("recipe.output.capsule", recipeCapsuleOutput, "amount yielded by the recipe for wax capsules."); + initSetting("recipe.output.refractory", recipeRefractoryOutput, "amount yielded by the recipe for refractory capsules."); + + initSetting("fermenter.cycles.fertilizer", FERMENTATION_DURATION_FERTILIZER, -1, "modifies the amount of cycles fertilizer can keep a fermenter going."); + initSetting("fermenter.cycles.compost", FERMENTATION_DURATION_COMPOST, -1, "modifies the amount of cycles compost can keep a fermenter going."); + + initSetting("fermenter.value.fertilizer", FERMENTED_CYCLE_FERTILIZER, -1, "modifies the amount of biomass per cycle a fermenter will produce using fertilizer."); + initSetting("fermenter.value.compost", FERMENTED_CYCLE_COMPOST, -1, "modifies the amount of biomass per cycle a fermenter will produce using compost."); + + initSetting("fermenter.yield.sapling", FERMENTED_SAPLING, FERMENTED_SAPLING * 8, "modifies the base amount of biomass a sapling will yield in a fermenter, affected by sappiness trait."); + initSetting("fermenter.yield.cactus", FERMENTED_CACTI, FERMENTED_CACTI * 8, "modifies the amount of biomass a piece of cactus will yield in a fermenter."); + initSetting("fermenter.yield.wheat", FERMENTED_WHEAT, FERMENTED_WHEAT * 8, "modifies the amount of biomass a piece of wheat will yield in a fermenter."); + initSetting("fermenter.yield.cane", FERMENTED_CANE, FERMENTED_CANE * 8, "modifies the amount of biomass a piece of sugar cane will yield in a fermenter."); + initSetting("fermenter.yield.mushroom", FERMENTED_MUSHROOM, FERMENTED_MUSHROOM * 8, "modifies the amount of biomass a mushroom will yield in a fermenter."); + + initSetting("squeezer.liquid.seed", SQUEEZED_LIQUID_SEED, SQUEEZED_LIQUID_SEED * 8, "modifies the amount of seed oil squeezed from a single seed. other sources are based off this."); + initSetting("squeezer.liquid.apple", SQUEEZED_LIQUID_APPLE, SQUEEZED_LIQUID_APPLE * 8, "modifies the amount of juice squeezed from a single apple. other sources are based off this."); + initSetting("squeezer.mulch.apple", SQUEEZED_MULCH_APPLE, SQUEEZED_MULCH_APPLE * 8, "modifies the chance of mulch per squeezed apple."); + initSetting("energy.engine.clockwork", true, "set to false to disable the clockwork engine."); + + config.save(); + + } + + private void initSetting(String ident, ItemStack def, String comment) { + Property property = Config.config.get(ident, category, def.stackSize); + property.Comment = comment; + ItemStack changed = def.copy(); + changed.stackSize = Integer.parseInt(property.Value); + stackSettings.put(ident, changed); + } + + private void initSetting(String ident, int def, int max, String comment) { + Property property = Config.config.get(ident, category, def); + if(max < 0) { + property.Comment = comment; + integerSettings.put(ident, Integer.parseInt(property.Value)); + } else { + property.Comment = comment + " (max: " + max + ")"; + integerSettings.put(ident, Math.min(Integer.parseInt(property.Value), max)); + } + Config.config.set(ident, category, integerSettings.get(ident)); + + } + + private void initSetting(String ident, float def, float max, String comment) { + Property property = Config.config.get(ident, category, def); + if(max < 0) { + property.Comment = comment; + floatSettings.put(ident, Float.parseFloat(property.Value)); + } else { + property.Comment = comment + " (max: " + max + ")"; + floatSettings.put(ident, Math.min(Float.parseFloat(property.Value), max)); + } + Config.config.set(ident, category, floatSettings.get(ident)); + } + + private void initSetting(String ident, boolean def, String comment) { + Property property = Config.config.get(ident, category, def); + property.Comment = comment; + booleanSettings.put(ident, Boolean.parseBoolean(property.Value)); + Config.config.set(ident, category, booleanSettings.get(ident)); + } + + @Override + public int getIntegerSetting(String ident) { + if(integerSettings.containsKey(ident)) + return integerSettings.get(ident); + Proxies.log.warning("No such setting: " + ident); + return -1; + } + + @Override + public float getFloatSetting(String ident) { + if(floatSettings.containsKey(ident)) + return floatSettings.get(ident); + Proxies.log.warning("No such setting: " + ident); + return 1; + } + + @Override + public boolean getBooleanSetting(String ident) { + if(booleanSettings.containsKey(ident)) + return booleanSettings.get(ident); + Proxies.log.warning("No such setting: " + ident); + return false; + } + + @Override + public ItemStack getStackSetting(String ident) { + if(stackSettings.containsKey(ident)) + return stackSettings.get(ident); + Proxies.log.warning("No such setting: " + ident); + return new ItemStack(Items.apple, 1); + } + + @Override + public String getIdentifier() { + return identifier; + } + +} diff --git a/forestry_common/core/forestry/core/GuiHandler.java b/forestry_common/core/forestry/core/GuiHandler.java new file mode 100755 index 000000000..fe3540abb --- /dev/null +++ b/forestry_common/core/forestry/core/GuiHandler.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.core.circuits.ContainerSolderingIron; +import forestry.core.circuits.GuiSolderingIron; +import forestry.core.circuits.ItemSolderingIron.SolderingInventory; +import forestry.core.gadgets.TileAnalyzer; +import forestry.core.gadgets.TileEscritoire; +import forestry.core.gui.ContainerAnalyzer; +import forestry.core.gui.ContainerEscritoire; +import forestry.core.gui.GuiAnalyzer; +import forestry.core.gui.GuiEscritoire; +import forestry.core.network.GuiId; +import forestry.plugins.PluginManager; + +public class GuiHandler extends GuiHandlerBase { + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + + if (cleanId < GuiId.values().length) + switch (GuiId.values()[cleanId]) { + + case AnalyzerGUI: + return new GuiAnalyzer(player.inventory, (TileAnalyzer) getTileForestry(world, x, y, z)); + + case NaturalistBenchGUI: + return new GuiEscritoire(player, (TileEscritoire) getTileForestry(world, x, y, z)); + + case SolderingIronGUI: + return new GuiSolderingIron(player.inventory, new SolderingInventory()); + + default: + for (IGuiHandler handler : PluginManager.guiHandlers) { + Object element = handler.getClientGuiElement(id, player, world, x, y, z); + if (element != null) + return element; + } + + return null; + } + + return null; + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + + if (cleanId < GuiId.values().length) + switch (GuiId.values()[cleanId]) { + + case AnalyzerGUI: + return new ContainerAnalyzer(player.inventory, (TileAnalyzer) getTileForestry(world, x, y, z)); + + case NaturalistBenchGUI: + return new ContainerEscritoire(player, (TileEscritoire) getTileForestry(world, x, y, z)); + + case SolderingIronGUI: + return new ContainerSolderingIron(player.inventory, new SolderingInventory()); + + default: + for (IGuiHandler handler : PluginManager.guiHandlers) { + Object element = handler.getServerGuiElement(id, player, world, x, y, z); + if (element != null) + return element; + } + + return null; + + } + + return null; + } +} diff --git a/forestry_common/core/forestry/core/GuiHandlerBase.java b/forestry_common/core/forestry/core/GuiHandlerBase.java new file mode 100755 index 000000000..3cd76a3cd --- /dev/null +++ b/forestry_common/core/forestry/core/GuiHandlerBase.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.gadgets.TileForestry; +import forestry.core.gadgets.TileNaturalistChest; +import forestry.core.gui.ContainerNaturalistInventory; +import forestry.core.gui.GuiNaturalistInventory; +import forestry.core.proxy.Proxies; + +public abstract class GuiHandlerBase implements IGuiHandler { + + public TileForestry getTileForestry(World world, int x, int y, int z) { + try { + return (TileForestry) world.getTileEntity(x, y, z); + } catch (Exception ex) { + Proxies.log.warning("Failed to cast a tile entity to a TileForestry at " + x + "/" + y + "/" + z); + } + + return null; + } + + public GuiNaturalistInventory getNaturalistChestGui(String rootUID, EntityPlayer player, World world, int x, int y, int z, int page) { + TileNaturalistChest tile = (TileNaturalistChest) getTileForestry(world, x, y, z); + ISpeciesRoot speciesRoot = AlleleManager.alleleRegistry.getSpeciesRoot(rootUID); + return new GuiNaturalistInventory(speciesRoot, player, new ContainerNaturalistInventory(speciesRoot, player.inventory, tile, page, 25), tile, page, 5); + } + + public ContainerNaturalistInventory getNaturalistChestContainer(String rootUID, EntityPlayer player, World world, int x, int y, int z, int page) { + ISpeciesRoot speciesRoot = AlleleManager.alleleRegistry.getSpeciesRoot(rootUID); + speciesRoot.getBreedingTracker(world, player.getGameProfile().getId()).synchToPlayer(player); + return new ContainerNaturalistInventory(speciesRoot, + player.inventory, (TileNaturalistChest) getTileForestry(world, x, y, z), page, 25); + } + + public ItemStack getEquippedItem(EntityPlayer player) { + return player.getCurrentEquippedItem(); + } + + public static int encodeGuiData(int guiId, int data) { + return data << 8 | guiId; + } + + public static int decodeGuiID(int guiId) { + return guiId & 0xFF; + } + + public static int decodeGuiData(int guiId) { + return guiId >> 8; + } +} diff --git a/forestry_common/core/forestry/core/PickupHandlerCore.java b/forestry_common/core/forestry/core/PickupHandlerCore.java new file mode 100755 index 000000000..afa29f302 --- /dev/null +++ b/forestry_common/core/forestry/core/PickupHandlerCore.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.interfaces.IPickupHandler; + +public class PickupHandlerCore implements IPickupHandler { + + @Override + public boolean onItemPickup(EntityPlayer entityPlayer, EntityItem entityitem) { + ItemStack itemstack = entityitem.getEntityItem(); + if (itemstack == null || itemstack.stackSize <= 0) + return false; + + ISpeciesRoot root = AlleleManager.alleleRegistry.getSpeciesRoot(itemstack); + if(root != null) + root.getBreedingTracker(entityitem.worldObj, entityPlayer.getGameProfile().getId()).registerPickup(root.getMember(itemstack)); + + return true; + } + +} diff --git a/forestry_common/core/forestry/core/SaveEventHandlerCore.java b/forestry_common/core/forestry/core/SaveEventHandlerCore.java new file mode 100755 index 000000000..efcedde16 --- /dev/null +++ b/forestry_common/core/forestry/core/SaveEventHandlerCore.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.world.World; + +import forestry.core.interfaces.ISaveEventHandler; + +public class SaveEventHandlerCore implements ISaveEventHandler { + + @Override + public void onWorldLoad(World world) { + } + + @Override + public void onWorldSave(World world) { + } + + @Override + public void onWorldUnload(World world) { + } + +} diff --git a/forestry_common/core/forestry/core/TemperatureState.java b/forestry_common/core/forestry/core/TemperatureState.java new file mode 100755 index 000000000..29f5531ae --- /dev/null +++ b/forestry_common/core/forestry/core/TemperatureState.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +public enum TemperatureState { + + UNKNOWN, + + COOL, + + WARMED_UP, + + OPERATING_TEMPERATURE, + + RUNNING_HOT, + + OVERHEATING, + + MELTING + +} diff --git a/forestry_common/core/forestry/core/TickHandlerCoreClient.java b/forestry_common/core/forestry/core/TickHandlerCoreClient.java new file mode 100755 index 000000000..7df49e2b4 --- /dev/null +++ b/forestry_common/core/forestry/core/TickHandlerCoreClient.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import java.util.concurrent.ConcurrentLinkedQueue; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ChatComponentText; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent.Phase; +import cpw.mods.fml.common.gameevent.TickEvent.PlayerTickEvent; + +import forestry.core.config.Config; +import forestry.core.config.Version; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Utils; + +public class TickHandlerCoreClient { + public TickHandlerCoreClient() { + FMLCommonHandler.instance().bus().register(this); + } + + private static ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue(); + + public void queueChatMessage(String message) { + messages.add(message); + } + private boolean naggedVersion, naggedVerify; + private boolean hasNaturalistView; + + @SubscribeEvent + public void onPlayerTick(PlayerTickEvent event) { + if (event.phase != Phase.END) return; + + EntityPlayer player = Proxies.common.getClientInstance().thePlayer; + boolean hasNaturalistEye = Utils.hasNaturalistEye(player); + if (hasNaturalistEye != hasNaturalistView) { + hasNaturalistView = !hasNaturalistView; + Proxies.common.getClientInstance().renderGlobal.markBlockRangeForRenderUpdate( + (int) player.posX - 32, (int) player.posY - 32, (int) player.posZ - 32, + (int) player.posX + 32, (int) player.posY + 32, (int) player.posZ + 32); + } + + if (messages.size() > 0) { + String message; + while ((message = messages.poll()) != null) { + player.addChatMessage(new ChatComponentText(message)); + } + } + + /* + if (!Config.disableNags) + if (Proxies.common.isModLoaded("GregTech_Addon")) + queueChatMessage("\u00A76Forestry may have been modified by GregTech. It may behave unexpectedly and some config options may not work. Do not report issues with this install! You can disable this nag in the config."); + */ + + if (!naggedVersion && !Config.disableVersionCheck && Version.needsUpdateNoticeAndMarkAsSeen()) { + queueChatMessage(String.format("\u00A7cNew version of Forestry available: %s for Minecraft %s", Version.getRecommendedVersion(), + Proxies.common.getMinecraftVersion())); + queueChatMessage("\u00A7cThis message only displays once. Type '/forestry version' to see the changelog."); + naggedVersion = true; + } + + if (!naggedVerify && Config.invalidFingerprint) { + queueChatMessage("\u00A76Forestry's jar file was tampered with. Some machines have shut down and beekeeping has grown dangerous. Get a new jar from the official download page to fix that!"); + naggedVerify = true; + } + } +} diff --git a/forestry_common/core/forestry/core/TickHandlerCoreServer.java b/forestry_common/core/forestry/core/TickHandlerCoreServer.java new file mode 100755 index 000000000..aa1913b8c --- /dev/null +++ b/forestry_common/core/forestry/core/TickHandlerCoreServer.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import net.minecraft.entity.player.EntityPlayer; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent.Phase; +import cpw.mods.fml.common.gameevent.TickEvent.WorldTickEvent; + +import forestry.core.interfaces.IResupplyHandler; +import forestry.plugins.PluginManager; + +public class TickHandlerCoreServer { + public TickHandlerCoreServer() { + FMLCommonHandler.instance().bus().register(this); + } + + @SubscribeEvent + public void onWorldTick(WorldTickEvent event) { + if (event.phase != Phase.END) return; + + for (Object obj : event.world.playerEntities) { + EntityPlayer player = (EntityPlayer) obj; + for (IResupplyHandler handler : PluginManager.resupplyHandlers) + handler.resupply(player); + } + + } +} diff --git a/forestry_common/core/forestry/core/WorldGenerator.java b/forestry_common/core/forestry/core/WorldGenerator.java new file mode 100755 index 000000000..730d7edd9 --- /dev/null +++ b/forestry_common/core/forestry/core/WorldGenerator.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core; + +import java.util.Random; + +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; + +import cpw.mods.fml.common.IWorldGenerator; + +import forestry.api.core.IPlugin; +import forestry.core.config.Config; +import forestry.core.config.ForestryBlock; +import forestry.core.proxy.Proxies; +import forestry.core.worldgen.WorldGenMinableMeta; +import forestry.plugins.NativePlugin; +import forestry.plugins.PluginManager; + +public class WorldGenerator implements IWorldGenerator { + + private WorldGenMinableMeta apatiteGenerator; + private WorldGenMinableMeta copperGenerator; + private WorldGenMinableMeta tinGenerator; + + @Override + public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { + + if (apatiteGenerator == null) { + apatiteGenerator = new WorldGenMinableMeta(ForestryBlock.resources, 0, 36); + copperGenerator = new WorldGenMinableMeta(ForestryBlock.resources, 1, 6); + tinGenerator = new WorldGenMinableMeta(ForestryBlock.resources, 2, 6); + } + + // shift to world coordinates + chunkX = chunkX << 4; + chunkZ = chunkZ << 4; + + // / APATITE + if (Config.generateApatiteOre) + if (random.nextFloat() < 0.8f) { + int randPosX = chunkX + random.nextInt(16); + int randPosY = random.nextInt(world.getActualHeight() - 72) + 56; // Does not generate below y = 64 + int randPosZ = chunkZ + random.nextInt(16); + if (apatiteGenerator.generate(world, random, randPosX, randPosY, randPosZ)) + Proxies.log.finest("Generated apatite vein around %s/%s/%s", randPosX, randPosY, randPosZ); + } + + // / COPPER + if (Config.generateCopperOre) + for (int i = 0; i < 20; i++) { + int randPosX = chunkX + random.nextInt(16); + int randPosY = random.nextInt(76) + 32; + int randPosZ = chunkZ + random.nextInt(16); + copperGenerator.generate(world, random, randPosX, randPosY, randPosZ); + } + + // / TIN + if (Config.generateTinOre) + for (int i = 0; i < 18; i++) { + int randPosX = chunkX + random.nextInt(16); + int randPosY = random.nextInt(76) + 16; + int randPosZ = chunkZ + random.nextInt(16); + tinGenerator.generate(world, random, randPosX, randPosY, randPosZ); + } + + // / PLUGIN WORLD GENERATION + for (IPlugin plugin : PluginManager.plugins) + if (plugin.isAvailable() && plugin instanceof NativePlugin) + ((NativePlugin) plugin).generateSurface(world, random, chunkX, chunkZ); + } + +} diff --git a/forestry_common/core/forestry/core/circuits/Circuit.java b/forestry_common/core/forestry/core/circuits/Circuit.java new file mode 100755 index 000000000..078257ea2 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/Circuit.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import java.util.List; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuit; +import forestry.core.utils.StringUtil; + +public abstract class Circuit implements ICircuit { + + String uid; + int limit = 1; + boolean requiresDiscovery; + String name; + String[] descriptions; + + public Circuit(String uid, boolean requiresDiscovery, String name, String[] descriptions) { + this.uid = uid; + this.requiresDiscovery = requiresDiscovery; + this.name = name; + this.descriptions = descriptions; + + ChipsetManager.circuitRegistry.registerCircuit(this); + } + + protected void setLimit(int limit) { + this.limit = limit; + } + + @Override + public String getUID() { + return "forestry." + this.uid; + } + + @Override + public int getLimit() { + return this.limit; + } + + @Override + public boolean requiresDiscovery() { + return this.requiresDiscovery; + } + + @Override + public String getName() { + return "circuit." + this.name; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addTooltip(List list) { + for (String description : descriptions) + list.add(" - " + StringUtil.localize(description)); + } + + public static ICircuit energyElectricChoke1; + public static ICircuit energyFireDampener1; + public static ICircuit energyElectricEfficiency1; + public static ICircuit energyElectricBoost1; + public static ICircuit energyElectricBoost2; + + public static ICircuit farmArborealManaged; + public static ICircuit farmShroomManaged; + public static ICircuit farmCerealManaged; + public static ICircuit farmVegetableManaged; + public static ICircuit farmPeatManaged; + public static ICircuit farmSucculentManaged; + public static ICircuit farmPoaleManaged; + public static ICircuit farmFungal; + public static ICircuit farmInfernalManaged; + public static ICircuit farmGourdManaged; + + public static ICircuit farmShroomManual; + public static ICircuit farmCerealManual; + public static ICircuit farmVegetableManual; + public static ICircuit farmPeatManual; + public static ICircuit farmSucculentManual; + public static ICircuit farmPoalesManual; + public static ICircuit farmGourdManual; + public static ICircuit farmCocoaManual; + + public static ICircuit farmOrchardManual; + public static ICircuit farmRubberManual; +} diff --git a/forestry_common/core/forestry/core/circuits/CircuitBoard.java b/forestry_common/core/forestry/core/circuits/CircuitBoard.java new file mode 100755 index 000000000..4a0dfb49d --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/CircuitBoard.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuit; +import forestry.api.circuits.ICircuitBoard; +import forestry.api.circuits.ICircuitLayout; + +public class CircuitBoard implements ICircuitBoard { + + EnumCircuitBoardType type; + ICircuitLayout layout; + ICircuit[] circuits; + + public CircuitBoard(EnumCircuitBoardType type, ICircuitLayout layout, ICircuit[] circuits) { + this.type = type; + this.layout = layout; + this.circuits = circuits; + } + + public CircuitBoard(NBTTagCompound nbttagcompound) { + readFromNBT(nbttagcompound); + } + + @Override + public int getPrimaryColor() { + return type.primaryColor; + } + + @Override + public int getSecondaryColor() { + return type.secondaryColor; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addTooltip(List list) { + if (layout != null) + list.add("\u00A76" + layout.getUsage() + ":"); + + for (ICircuit circuit : circuits) + if (circuit != null) + circuit.addTooltip(list); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + type = EnumCircuitBoardType.values()[nbttagcompound.getShort("T")]; + + // Layout + if (nbttagcompound.hasKey("LY")) + layout = ChipsetManager.circuitRegistry.getLayout(nbttagcompound.getString("LY")); + if (layout == null) + ChipsetManager.circuitRegistry.getDefaultLayout(); + + // FIXME: Legacy I + ArrayList readcircuits = new ArrayList(); + if (nbttagcompound.hasKey("CS")) { + + NBTTagList nbttaglist = nbttagcompound.getTagList("CS", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + readcircuits.add(ChipsetManager.circuitRegistry.getFromLegacyMap(nbttagcompound1.getInteger("I"))); + } + + circuits = readcircuits.toArray(new ICircuit[0]); + return; + + } + + // FIXME: Legacy II + if (nbttagcompound.hasKey("CL")) { + NBTTagList nbttaglist = nbttagcompound.getTagList("CL", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + readcircuits.add(ChipsetManager.circuitRegistry.getCircuit(nbttagcompound1.getString("I"))); + } + + circuits = readcircuits.toArray(new ICircuit[0]); + return; + } + + // New + if (circuits != null) + return; + + circuits = new ICircuit[4]; + for (int i = 0; i < 4; i++) { + if (!nbttagcompound.hasKey("CA.I" + i)) + continue; + circuits[i] = ChipsetManager.circuitRegistry.getCircuit(nbttagcompound.getString("CA.I" + i)); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + nbttagcompound.setShort("T", (short) type.ordinal()); + + // Layout + if (layout != null) + nbttagcompound.setString("LY", layout.getUID()); + + // Circuits + for (int i = 0; i < circuits.length; i++) { + ICircuit circuit = circuits[i]; + if (circuit == null) + continue; + + nbttagcompound.setString("CA.I" + i, circuit.getUID()); + } + + } + + @Override + public void onInsertion(TileEntity tile) { + for (int i = 0; i < circuits.length; i++) { + if (circuits[i] == null) + continue; + circuits[i].onInsertion(i, tile); + } + } + + @Override + public void onLoad(TileEntity tile) { + for (int i = 0; i < circuits.length; i++) { + if (circuits[i] == null) + continue; + circuits[i].onLoad(i, tile); + } + } + + @Override + public void onRemoval(TileEntity tile) { + for (int i = 0; i < circuits.length; i++) { + if (circuits[i] == null) + continue; + circuits[i].onRemoval(i, tile); + } + } + + @Override + public void onTick(TileEntity tile) { + for (int i = 0; i < circuits.length; i++) { + if (circuits[i] == null) + continue; + circuits[i].onTick(i, tile); + } + } + + @Override + public ICircuit[] getCircuits() { + return circuits; + } +} diff --git a/forestry_common/core/forestry/core/circuits/CircuitBoardManager.java b/forestry_common/core/forestry/core/circuits/CircuitBoardManager.java new file mode 100755 index 000000000..0445d5e11 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/CircuitBoardManager.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +public class CircuitBoardManager { +} diff --git a/forestry_common/core/forestry/core/circuits/CircuitId.java b/forestry_common/core/forestry/core/circuits/CircuitId.java new file mode 100755 index 000000000..348e52bb0 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/CircuitId.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +public class CircuitId { + public static final int ELECTRIC_CHOKE_I = 1; + public static final int FIRE_DAMPENER_I = 2; + public static final int ELECTRIC_EFFICIENCY_I = 3; + public static final int ELECTRIC_BOOST_I = 4; + public static final int ELECTRIC_BOOST_II = 5; +} diff --git a/forestry_common/core/forestry/core/circuits/CircuitLayout.java b/forestry_common/core/forestry/core/circuits/CircuitLayout.java new file mode 100755 index 000000000..0146ea1ef --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/CircuitLayout.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import forestry.api.circuits.ICircuitLayout; +import forestry.core.utils.StringUtil; + +public class CircuitLayout implements ICircuitLayout { + + String uid; + + public CircuitLayout(String uid) { + this.uid = uid; + } + + @Override + public String getUID() { + return "forestry." + this.uid; + } + + @Override + public String getName() { + return StringUtil.localize("layout." + this.uid); + } + + @Override + public String getUsage() { + return StringUtil.localize("usage." + this.uid); + } +} diff --git a/forestry_common/core/forestry/core/circuits/CircuitLibrary.java b/forestry_common/core/forestry/core/circuits/CircuitLibrary.java new file mode 100755 index 000000000..b2844f861 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/CircuitLibrary.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.WorldSavedData; + +import forestry.api.circuits.ICircuitLibrary; + +public class CircuitLibrary extends WorldSavedData implements ICircuitLibrary { + + public CircuitLibrary(String par1Str) { + super(par1Str); + } + + @Override + public void readFromNBT(NBTTagCompound var1) { + } + + @Override + public void writeToNBT(NBTTagCompound var1) { + } + +} diff --git a/forestry_common/core/forestry/core/circuits/CircuitRegistry.java b/forestry_common/core/forestry/core/circuits/CircuitRegistry.java new file mode 100755 index 000000000..ec6301181 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/CircuitRegistry.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import java.util.HashMap; +import java.util.LinkedHashMap; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.circuits.ICircuit; +import forestry.api.circuits.ICircuitBoard; +import forestry.api.circuits.ICircuitLayout; +import forestry.api.circuits.ICircuitLibrary; +import forestry.api.circuits.ICircuitRegistry; +import forestry.core.config.ForestryItem; + +public class CircuitRegistry implements ICircuitRegistry { + + private LinkedHashMap layoutMap = new LinkedHashMap(); + private LinkedHashMap circuitMap = new LinkedHashMap(); + private HashMap legacyMap = new HashMap(); + + @Override + public ICircuitLibrary getCircuitLibrary(World world, String playername) { + CircuitLibrary library = (CircuitLibrary) world.loadItemData(CircuitLibrary.class, "CircuitLibrary_" + playername); + + if (library == null) { + library = new CircuitLibrary(playername); + world.setItemData("CircuitLibrary_" + playername, library); + } + + return library; + } + + /* CIRCUIT LAYOUTS */ + @Override + public ICircuitLayout getDefaultLayout() { + if (layoutMap.containsKey("forestry.engine.tin")) + return layoutMap.get("forestry.engine.tin"); + else + return layoutMap.values().iterator().next(); + } + + @Override + public LinkedHashMap getRegisteredLayouts() { + return layoutMap; + } + + @Override + public void registerLayout(ICircuitLayout layout) { + layoutMap.put(layout.getUID(), layout); + } + + @Override + public ICircuitLayout getLayout(String uid) { + if (layoutMap.containsKey(uid)) + return layoutMap.get(uid); + else + return null; + } + + /* CIRCUITS */ + @Override + public HashMap getRegisteredCircuits() { + return circuitMap; + } + + @Override + public void registerCircuit(ICircuit circuit) { + circuitMap.put(circuit.getUID(), circuit); + } + + @Override + public ICircuit getCircuit(String uid) { + return circuitMap.get(uid); + } + + @Override + public void registerLegacyMapping(int id, String uid) { + this.legacyMap.put(id, uid); + } + + @Override + public ICircuit getFromLegacyMap(int id) { + if (!legacyMap.containsKey(id)) + return null; + + return getCircuit(legacyMap.get(id)); + } + + public void initialize() { + registerLayout(new CircuitLayout("engine.tin")); + } + + + + @Override + public boolean isChipset(ItemStack itemstack) { + return ForestryItem.circuitboards.isItemEqual(itemstack); + } + + @Override + public ICircuitBoard getCircuitboard(ItemStack itemstack) { + NBTTagCompound nbttagcompound = itemstack.getTagCompound(); + if (nbttagcompound == null) + return null; + + return new CircuitBoard(nbttagcompound); + } +} diff --git a/forestry_common/core/forestry/core/circuits/ContainerSolderingIron.java b/forestry_common/core/forestry/core/circuits/ContainerSolderingIron.java new file mode 100755 index 000000000..52bd3c688 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/ContainerSolderingIron.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.circuits.ICircuitLayout; +import forestry.core.circuits.ItemSolderingIron.SolderingInventory; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.IGuiSelectable; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; + +public class ContainerSolderingIron extends ContainerItemInventory implements IGuiSelectable { + + SolderingInventory inventory; + + public ContainerSolderingIron(InventoryPlayer inventoryplayer, SolderingInventory inventory) { + super(inventory, inventoryplayer.player); + this.inventory = inventory; + + // Input + this.addSlot(new SlotCustom(inventory, 0, 152, 12, new Object[] { ItemCircuitBoard.class })); + + // Output + this.addSlot(new SlotCustom(inventory, 1, 152, 92, new Object[] { ItemCircuitBoard.class })); + + // Ingredients + this.addSlot(new Slot(inventory, 2, 12, 32)); + this.addSlot(new Slot(inventory, 3, 12, 52)); + this.addSlot(new Slot(inventory, 4, 12, 72)); + this.addSlot(new Slot(inventory, 5, 12, 92)); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSecuredSlot(inventoryplayer, l1 + i1 * 9 + 9, 8 + l1 * 18, 123 + i1 * 18); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSecuredSlot(inventoryplayer, j1, 8 + j1 * 18, 181); + + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + return false; + } + + /* + * @Override public void onCraftGuiClosed(EntityPlayer entityplayer) { + * + * if (!Proxies.common.isSimulating(entityplayer.worldObj)) return; + * + * // Drop everything still in there. for (int i = 0; i < inventory.getSizeInventory(); i++) { ItemStack stack = inventory.getStackInSlot(i); if (stack == + * null) { continue; } + * + * Proxies.common.dropItemPlayer(entityplayer, stack); inventory.setInventorySlotContents(i, null); } + * + * } + */ + + public ICircuitLayout getLayout() { + return inventory.getLayout(); + } + + public void advanceSelection(int index, World world) { + PacketPayload payload = new PacketPayload(2, 0, 0); + payload.intPayload[0] = index; + payload.intPayload[1] = 0; + sendSelectionChange(payload); + } + + public void regressSelection(int index, World world) { + PacketPayload payload = new PacketPayload(2, 0, 0); + payload.intPayload[0] = index; + payload.intPayload[1] = 1; + sendSelectionChange(payload); + } + + private void sendSelectionChange(PacketPayload payload) { + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + } + + @Override + public void setSelection(PacketUpdate packet) { + inventory.setLayout(packet.payload.stringPayload[0]); + } + + @Override + public void handleSelectionChange(EntityPlayer player, PacketUpdate packet) { + + if (packet.payload.intPayload[1] == 0) { + if (packet.payload.intPayload[0] == 0) + inventory.advanceLayout(); + + } else if (packet.payload.intPayload[0] == 0) + inventory.regressLayout(); + + sendSelection(player); + } + + public void sendSelection(EntityPlayer player) { + PacketPayload payload = new PacketPayload(0, 0, 1); + payload.stringPayload[0] = inventory.getLayout().getUID(); + Proxies.net.sendToPlayer(new PacketUpdate(PacketIds.GUI_SELECTION, payload), player); + } + +} diff --git a/forestry_common/core/forestry/core/circuits/EnumCircuitBoardType.java b/forestry_common/core/forestry/core/circuits/EnumCircuitBoardType.java new file mode 100755 index 000000000..3f4768236 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/EnumCircuitBoardType.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +public enum EnumCircuitBoardType { + BASIC((short) 1, 0x191919, 0x6dcff6), ENHANCED((short) 2, 0x191919, 0xcb7c32), REFINED((short) 3, 0x191919, 0xc9c9c9), INTRICATE((short) 4, 0x191919, + 0xe2cb6b); + + final short sockets; + final int primaryColor; + final int secondaryColor; + + private EnumCircuitBoardType(short sockets, int primaryColor, int secondaryColor) { + this.sockets = sockets; + this.primaryColor = primaryColor; + this.secondaryColor = secondaryColor; + } +} diff --git a/forestry_common/core/forestry/core/circuits/GuiSolderingIron.java b/forestry_common/core/forestry/core/circuits/GuiSolderingIron.java new file mode 100755 index 000000000..c574cd67f --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/GuiSolderingIron.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.IInventory; + +import forestry.api.circuits.ICircuitLayout; +import forestry.core.circuits.ItemSolderingIron.CircuitRecipe; +import forestry.core.circuits.ItemSolderingIron.SolderingInventory; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.GuiForestry; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StringUtil; + +public class GuiSolderingIron extends GuiForestry { + + private final IInventory inventory; + + public GuiSolderingIron(InventoryPlayer inventoryplayer, SolderingInventory inventory) { + super(Defaults.TEXTURE_PATH_GUI + "/solder.png", new ContainerSolderingIron(inventoryplayer, inventory), inventory); + + this.inventory = inventory; + + xSize = 176; + ySize = 205; + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + ICircuitLayout layout = ((ContainerSolderingIron) inventorySlots).getLayout(); + String title = layout.getName(); + fontRendererObj.drawString(title, guiLeft + 8 + getCenteredOffset(title, 138), guiTop + 16, fontColor.get("gui.screen")); + + for (int l = 2; l < inventory.getSizeInventory(); l++) { + String description; + CircuitRecipe recipe = ItemSolderingIron.SolderManager.getMatchingRecipe(layout, inventory.getStackInSlot(l)); + if (recipe == null) + description = "(" + StringUtil.localize("gui.noeffect") + ")"; + else + description = StringUtil.localize(recipe.circuit.getName()) + " (" + recipe.circuit.getLimit() + ")"; + + int row = (l - 2) * 20; + fontRendererObj.drawString(description, guiLeft + 32, guiTop + 36 + row, fontColor.get("gui.screen")); + } + } + + @SuppressWarnings("unchecked") + @Override + public void initGui() { + super.initGui(); + + buttonList.add(new GuiButton(1, guiLeft + 12, guiTop + 10, 12, 18, "<")); + buttonList.add(new GuiButton(2, guiLeft + 130, guiTop + 10, 12, 18, ">")); + + } + + @Override + protected void actionPerformed(GuiButton guibutton) { + super.actionPerformed(guibutton); + + if (guibutton.id == 1) + ((ContainerSolderingIron) inventorySlots).regressSelection(0, Proxies.common.getRenderWorld()); + else if (guibutton.id == 2) + ((ContainerSolderingIron) inventorySlots).advanceSelection(0, Proxies.common.getRenderWorld()); + } + +} diff --git a/forestry_common/core/forestry/core/circuits/ISolderingIron.java b/forestry_common/core/forestry/core/circuits/ISolderingIron.java new file mode 100755 index 000000000..9288ab59e --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/ISolderingIron.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +public interface ISolderingIron { + +} diff --git a/forestry_common/core/forestry/core/circuits/ItemCircuitBoard.java b/forestry_common/core/forestry/core/circuits/ItemCircuitBoard.java new file mode 100755 index 000000000..5bff9e87f --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/ItemCircuitBoard.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import java.util.List; +import java.util.Locale; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuit; +import forestry.api.circuits.ICircuitBoard; +import forestry.api.circuits.ICircuitLayout; +import forestry.core.config.ForestryItem; +import forestry.core.items.ItemForestry; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemCircuitBoard extends ItemForestry { + + public ItemCircuitBoard() { + super(); + setHasSubtypes(true); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + itemList.add(createCircuitboard(EnumCircuitBoardType.BASIC, null, new ICircuit[] {})); + itemList.add(createCircuitboard(EnumCircuitBoardType.ENHANCED, null, new ICircuit[] {})); + itemList.add(createCircuitboard(EnumCircuitBoardType.REFINED, null, new ICircuit[] {})); + itemList.add(createCircuitboard(EnumCircuitBoardType.INTRICATE, null, new ICircuit[] {})); + } + + /** + * @return true if the item's stackTagCompound needs to be synchronized over SMP. + */ + @Override + public boolean getShareTag() { + return true; + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + icons = new IIcon[2]; + icons[0] = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".0"); + icons[1] = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".1"); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int i, int j) { + if (j > 0) + return icons[0]; + else + return icons[1]; + } + + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int j) { + EnumCircuitBoardType type = EnumCircuitBoardType.values()[itemstack.getItemDamage()]; + if (j == 0) + return type.primaryColor; + else + return type.secondaryColor; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + EnumCircuitBoardType type = EnumCircuitBoardType.values()[itemstack.getItemDamage()]; + return StringUtil.localize("item.circuitboard." + type.toString().toLowerCase(Locale.ENGLISH)); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + ICircuitBoard circuitboard = ChipsetManager.circuitRegistry.getCircuitboard(itemstack); + if (circuitboard != null) + circuitboard.addTooltip(list); + } + + public static ItemStack createCircuitboard(EnumCircuitBoardType type, ICircuitLayout layout, ICircuit[] circuits) { + ItemStack chipset = ForestryItem.circuitboards.getItemStack(1, type.ordinal()); + saveChipset(chipset, new CircuitBoard(type, layout, circuits)); + return chipset; + } + + public static void saveChipset(ItemStack itemstack, ICircuitBoard circuitboard) { + if (circuitboard == null) { + itemstack.setTagCompound(null); + return; + } + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + circuitboard.writeToNBT(nbttagcompound); + itemstack.setTagCompound(nbttagcompound); + } + +} diff --git a/forestry_common/core/forestry/core/circuits/ItemSolderingIron.java b/forestry_common/core/forestry/core/circuits/ItemSolderingIron.java new file mode 100755 index 000000000..2157ef322 --- /dev/null +++ b/forestry_common/core/forestry/core/circuits/ItemSolderingIron.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.circuits; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map.Entry; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuit; +import forestry.api.circuits.ICircuitLayout; +import forestry.api.circuits.ISolderManager; +import forestry.api.core.ForestryAPI; +import forestry.core.EnumErrorCode; +import forestry.core.interfaces.IErrorSource; +import forestry.core.items.ItemForestry; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ItemInventory; + +public class ItemSolderingIron extends ItemForestry implements ISolderingIron { + + public static class CircuitRecipe { + ICircuitLayout layout; + ItemStack resource; + ICircuit circuit; + + public CircuitRecipe(ICircuitLayout layout, ItemStack resource, ICircuit circuit) { + this.resource = resource; + this.layout = layout; + this.circuit = circuit; + } + + public boolean matches(ICircuitLayout layout, ItemStack itemstack) { + if (!this.layout.getUID().equals(layout.getUID())) + return false; + + return itemstack.isItemEqual(resource); + } + } + + public static class SolderManager implements ISolderManager { + public static ArrayList recipes = new ArrayList(); + + @Override + public void addRecipe(ICircuitLayout layout, ItemStack resource, ICircuit circuit) { + if (layout == null) + throw new IllegalArgumentException("layout may not be null"); + if (resource == null) + throw new IllegalArgumentException("resource may not be null"); + if (circuit == null) + throw new IllegalArgumentException("circuit may not be null"); + recipes.add(new CircuitRecipe(layout, resource, circuit)); + } + + public static CircuitRecipe getMatchingRecipe(ICircuitLayout layout, ItemStack resource) { + if (layout == null || resource == null) + return null; + + for (CircuitRecipe recipe : recipes) + if (recipe.matches(layout, resource)) + return recipe; + + return null; + } + } + + // / INVENTORY MANAGMENT + public static class SolderingInventory extends ItemInventory implements IErrorSource { + + ICircuitLayout layout; + EnumErrorCode errorState; + + short blankSlot = 0; + short finishedSlot = 1; + short ingredientSlot1 = 2; + + public SolderingInventory() { + super(ItemSolderingIron.class, 6); + layout = ChipsetManager.circuitRegistry.getDefaultLayout(); + } + + public SolderingInventory(ItemStack itemstack) { + super(ItemSolderingIron.class, 6, itemstack); + layout = ChipsetManager.circuitRegistry.getDefaultLayout(); + } + + public ICircuitLayout getLayout() { + return this.layout; + } + + public void setLayout(String uid) { + this.layout = ChipsetManager.circuitRegistry.getLayout(uid); + } + + public void advanceLayout() { + Iterator> it = ChipsetManager.circuitRegistry.getRegisteredLayouts().entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + if (entry.getKey().equals(layout.getUID())) { + + if (it.hasNext()) + layout = it.next().getValue(); + else + layout = ChipsetManager.circuitRegistry.getRegisteredLayouts().entrySet().iterator().next().getValue(); + + break; + } + } + } + + public void regressLayout() { + Iterator> it = ChipsetManager.circuitRegistry.getRegisteredLayouts().entrySet().iterator(); + + ICircuitLayout previous = null; + while (it.hasNext()) { + Entry entry = it.next(); + if (entry.getKey().equals(layout.getUID())) { + + if (previous != null) + layout = previous; + else + while (it.hasNext()) + layout = it.next().getValue(); + + break; + } + + previous = entry.getValue(); + } + } + + private Collection getCircuits(EnumCircuitBoardType type, boolean doConsume) { + + ArrayList circuits = new ArrayList(); + + for (short i = 0; i < type.sockets; i++) { + ItemStack ingredient = inventoryStacks[ingredientSlot1 + i]; + if (ingredient == null) + continue; + + CircuitRecipe recipe = SolderManager.getMatchingRecipe(layout, ingredient); + if (recipe == null) + continue; + + // / Make sure we don't exceed this circuits limit per chipset + if (getCount(recipe.circuit, circuits) >= recipe.circuit.getLimit()) + continue; + + if (doConsume) + decrStackSize(ingredientSlot1 + i, recipe.resource.stackSize); + circuits.add(recipe.circuit); + } + + return circuits; + } + + public void trySolder() { + + // Requires blank slot + if (inventoryStacks[blankSlot] == null) + return; + if (inventoryStacks[blankSlot].stackSize > 1) + return; + if (inventoryStacks[finishedSlot] != null) + return; + + ItemStack blank = inventoryStacks[blankSlot]; + // Need a chipset item + if (!ChipsetManager.circuitRegistry.isChipset(blank)) + return; + + // Illegal type + if (blank.getItemDamage() < 0 || blank.getItemDamage() >= EnumCircuitBoardType.values().length) + return; + + EnumCircuitBoardType type = EnumCircuitBoardType.values()[blank.getItemDamage()]; + Collection circuits = getCircuits(type, false); + + if (circuits.size() <= 0) + return; + else if (circuits.size() != type.sockets) { + errorState = EnumErrorCode.CIRCUITMISMATCH; + return; + } + + circuits = getCircuits(type, true); + inventoryStacks[finishedSlot] = ItemCircuitBoard.createCircuitboard(type, layout, circuits.toArray(new ICircuit[0])); + inventoryStacks[blankSlot] = null; + } + + public int getCount(ICircuit circuit, ArrayList circuits) { + int count = 0; + for (ICircuit other : circuits) + if (other.getUID().equals(circuit.getUID())) + count++; + return count; + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + } + + @Override + public void markDirty() { + errorState = EnumErrorCode.OK; + trySolder(); + } + + @Override + public boolean throwsErrors() { + return true; + } + + @Override + public EnumErrorCode getErrorState() { + if (inventoryStacks[blankSlot] == null) + return EnumErrorCode.NOCIRCUITBOARD; + if (inventoryStacks[blankSlot].stackSize > 1) + return EnumErrorCode.WRONGSTACKSIZE; + if (errorState != EnumErrorCode.OK) + return errorState; + + return EnumErrorCode.OK; + } + } + + public ItemSolderingIron() { + super(); + setMaxStackSize(1); + setMaxDamage(5); + } + + @Override + public boolean isFull3D() { + return true; + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) + entityplayer.openGui(ForestryAPI.instance, GuiId.SolderingIronGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + + return itemstack; + } +} diff --git a/forestry_common/core/forestry/core/config/Config.java b/forestry_common/core/forestry/core/config/Config.java new file mode 100755 index 000000000..605c2b3ec --- /dev/null +++ b/forestry_common/core/forestry/core/config/Config.java @@ -0,0 +1,373 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Properties; + +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.core.proxy.Proxies; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.Localization; + +public class Config { + + public static final String CATEGORY_COMMON = "common"; + + public static Configuration config; + + public static String gameMode; + + public static HashSet disabledStructures = new HashSet(); + + public static boolean isDebug = false; + + // Native Plugins + public static boolean disableApiculture = false; + public static boolean disableArboriculture = false; + public static boolean disableCultivation = false; + public static boolean disableEnergy = false; + public static boolean disableFactory = false; + public static boolean disableFarming = false; + public static boolean disableFood = false; + public static boolean disableMail = false; + public static boolean disableStorage = false; + + public static boolean disablePermissions = false; + public static boolean disableNags = false; + public static boolean disableVersionCheck = false; + + public static boolean invalidFingerprint = false; + + // Graphics + public static boolean enableParticleFX = true; + + // Bees + public static boolean clearInvalidChromosomes = false; + + // Dungeon loot + public static boolean dungeonLootRare = false; + + // World generation + public static boolean generateApatiteOre = true; + public static boolean generateCopperOre = true; + public static boolean generateTinOre = true; + public static boolean generateBeehives = true; + public static boolean generateBogEarth = false; + + // Performance + public static boolean enableBackpackResupply = true; + public static int planterThrottle; + public static int harvesterThrottle; + + // Customization + public static boolean tooltipLiquidAmount = true; + public static boolean planterSideSensitive = true; + /** + * True if the harvester should decide output to pipes according to side. + */ + public static boolean harvesterSideSensitive = true; + + /* GO AWAY GRED */ + private static boolean craftingBronzeEnabled = true; + + public static boolean getCraftingBronzeEnabled() { + return craftingBronzeEnabled; + } + + public static boolean craftingStampsEnabled = true; + public static ArrayList collectorStamps = new ArrayList(); + + public static boolean applePickup = true; + public static boolean squareFarms = false; + + // Mail + public static boolean mailAlertEnabled = true; + + public static String fakeUserLogin = "[Forestry]"; + public static boolean fakeUserAutoop = true; + + // Hints + public static boolean disableHints = false; + public static HashMap hints = new HashMap(); + public static boolean disableEnergyStat = false; + + @SuppressWarnings({ "all" }) + public static void load() { + + setDebugMode(); + + config = new Configuration(); + config.addPurge("buildcraft.blockid.engine"); + config.addPurge("buildcraft.blockid.pipe"); + config.addPurge("crafting.farms.enabled"); + config.addPurge("crafting.farms.uncrafting.enabled"); + config.addPurge("performance.planter"); + config.addPurge("performance.harvester"); + config.addPurge("buildcraft.ignore"); + config.addPurge("power.framework"); + + Property property = config.get("difficulty.gamemode", CATEGORY_COMMON, "EASY"); + property.Comment = "set to your preferred game mode. available modes are OP, EASY, NORMAL, HARD. mismatch with the server may cause visual glitches with recipes. setting an unavailable mode will create a new mode definition file."; + gameMode = property.Value; + + property = config.get("difficulty.recreate.definitions", CATEGORY_COMMON, true); + property.Comment = "set to true to force recreation of the game mode definitions in config/forestry/gamemodes"; + boolean recreate = Boolean.parseBoolean(property.Value); + + if (recreate) + Proxies.log.info("Recreating all gamemode definitions from the defaults. This may be caused by an upgrade"); + + // Make sure the default mode files are there. + File easyMode = config.getCategoryFile("gamemodes/EASY"); + if (recreate) + CopyFileToFS(easyMode, "/config/forestry/gamemodes/EASY.conf"); + + File opMode = config.getCategoryFile("gamemodes/OP"); + if (!opMode.exists() || recreate) + CopyFileToFS(opMode, "/config/forestry/gamemodes/OP.conf"); + + File normalMode = config.getCategoryFile("gamemodes/NORMAL"); + if (!normalMode.exists() || recreate) + CopyFileToFS(normalMode, "/config/forestry/gamemodes/NORMAL.conf"); + + File hardMode = config.getCategoryFile("gamemodes/HARD"); + if (!hardMode.exists() || recreate) + CopyFileToFS(hardMode, "/config/forestry/gamemodes/HARD.conf"); + + config.set("difficulty.recreate.definitions", CATEGORY_COMMON, false); + + Property particleFX = config.get("performance.particleFX.enabled", CATEGORY_COMMON, true); + particleFX.Comment = "set to false to disable particle fx on slower machines"; + enableParticleFX = Boolean.parseBoolean(particleFX.Value); + + Property genApatiteOre = config.get("world.generate.apatite", CATEGORY_COMMON, true); + genApatiteOre.Comment = "set to false to force forestry to skip generating own apatite ore blocks in the world"; + generateApatiteOre = Boolean.parseBoolean(genApatiteOre.Value); + + Property genBeehives = config.get("world.generate.beehives", CATEGORY_COMMON, true); + genBeehives.Comment = "set to false to force forestry to skip generating beehives in the world"; + generateBeehives = Boolean.parseBoolean(genBeehives.Value); + + Property genCopperOre = config.get("world.generate.copper", CATEGORY_COMMON, true); + genCopperOre.Comment = "set to false to force forestry to skip generating own copper ore blocks in the world"; + generateCopperOre = Boolean.parseBoolean(genCopperOre.Value); + + Property genTinOre = config.get("world.generate.tin", CATEGORY_COMMON, true); + genTinOre.Comment = "set to false to force forestry to skip generating own tin ore blocks in the world"; + generateTinOre = Boolean.parseBoolean(genTinOre.Value); + + Property planterSideSense = config.get("planters.sidesensitive", CATEGORY_COMMON, true); + planterSideSense.Comment = "set to false if farms should output all harvested products regardless of side a pipe is attached to"; + planterSideSensitive = Boolean.parseBoolean(planterSideSense.Value); + Property harvesterSideSense = config.get("harvesters.sidesensitive", CATEGORY_COMMON, true); + harvesterSideSense.Comment = "set to false if harvesters should output all harvested products regardless of side a pipe is attached to"; + harvesterSideSensitive = Boolean.parseBoolean(harvesterSideSense.Value); + + Property bronzeRecipe = config.get("crafting.bronze.enabled", CATEGORY_COMMON, true); + bronzeRecipe.Comment = "set to false to disable crafting recipe for bronze"; + craftingBronzeEnabled = Boolean.parseBoolean(bronzeRecipe.Value); + + property = config.get("crafting.stamps.enabled", CATEGORY_COMMON, true); + property.Comment = "set to false to disable crafting recipes for all types of stamps."; + craftingStampsEnabled = Boolean.parseBoolean(property.Value); + + String defaultCollectors = "20n;50n;100n;200n"; + property = config.get("crafting.stamps.collector", CATEGORY_COMMON, defaultCollectors); + property.Comment = "if crafting of stamps is generally allowed, these stamps are still excluded from crafting."; + try { + collectorStamps.addAll(Arrays.asList(parseStamps(property.Value))); + } catch(Exception ex) { + config.set("crafting.stamps.collector", CATEGORY_COMMON, defaultCollectors); + collectorStamps.addAll(Arrays.asList(parseStamps(defaultCollectors))); + } + + Property indicatorEnable = config.get("tweaks.mailalert.enabled", CATEGORY_COMMON, true); + indicatorEnable.Comment = "set to false to disable the mail alert box"; + mailAlertEnabled = Boolean.parseBoolean(indicatorEnable.Value); + + Property appleHarvest = config.get("tweaks.apple.pickup.enabled", CATEGORY_COMMON, true); + appleHarvest.Comment = "set to false to disable apple pickup by appropriate harvesters"; + applePickup = Boolean.parseBoolean(appleHarvest.Value); + + Property clearGenome = config.get("genetics.clear.invalid.chromosomes", CATEGORY_COMMON, clearInvalidChromosomes); + clearGenome.Comment = "NEW: set to true to clear chromosomes which contain invalid alleles. might rescue your save if it is crashing after removal of a bee addon."; + clearInvalidChromosomes = Boolean.parseBoolean(clearGenome.Value); + + Property dungeonLootRarity = config.get("difficulty.dungeonloot.rare", CATEGORY_COMMON, false); + dungeonLootRarity.Comment = "set to true to make dungeon loot generated by forestry rarer"; + dungeonLootRare = Boolean.parseBoolean(dungeonLootRarity.Value); + + Property resupplyEnable = config.get("performance.backpacks.resupply", CATEGORY_COMMON, true); + resupplyEnable.Comment = "leaving this enabled will cycle the list of active players PER INGAME TICK to check for resupply via backpack. you want to set this to false on busy servers."; + Config.enableBackpackResupply = Boolean.parseBoolean(resupplyEnable.Value); + + property = config.get("tweaks.hints.disabled", CATEGORY_COMMON, false); + property.Comment = "set to true to disable hints on machine and engine guis."; + Config.disableHints = Boolean.parseBoolean(property.Value); + property = config.get("tweaks.energystat.disabled", CATEGORY_COMMON, true); + property.Comment = "set to true to disable energy statistics on energy consumers."; + Config.disableEnergyStat = !isDebug && Boolean.parseBoolean(property.Value); + property = config.get("tweaks.tooltip.liquidamount.disabled", CATEGORY_COMMON, false); + property.Comment = "set to true to disable displaying liquid amounts in tank tooltips."; + Config.tooltipLiquidAmount = isDebug || !Boolean.parseBoolean(property.Value); + + property = config.get("tweaks.permissions.disabled", CATEGORY_COMMON, false); + property.Comment = "set to true to disable access restrictions on forestry machines."; + Config.disablePermissions = Boolean.parseBoolean(property.Value); + + property = config.get("tweaks.nags.disabled", CATEGORY_COMMON, false); + property.Comment = "set to true to disable some nagging and warnings (e.g. GregTech)."; + Config.disableNags = Boolean.parseBoolean(property.Value); + + property = config.get("tweaks.upgradenotice.disabled", CATEGORY_COMMON, false); + property.Comment = "set to true to disable update and version check notice."; + Config.disableVersionCheck = isDebug || Boolean.parseBoolean(property.Value); + + property = config.get("tweaks.farms.squared", CATEGORY_COMMON, false); + property.Comment = "set to true to have farms use a square layout instead of a diamond one."; + Config.squareFarms = Boolean.parseBoolean(property.Value); + + property = config.get("structures.schemata.disabled", CATEGORY_COMMON, ""); + property.Comment = "add schemata keys to disable them. current keys: alveary3x3;farm3x3;farm3x4;farm3x5;farm4x4;farm5x5"; + disabledStructures.addAll(Arrays.asList(parseStructureKeys(property.Value))); + for (String str : disabledStructures) + Proxies.log.finer("Disabled structure '%s'.", str); + + property = config.get("permissions.login", CATEGORY_COMMON, "[Forestry]"); + property.Comment = "set the default login used by Forestry."; + Config.fakeUserLogin = property.Value; + + property = config.get("permissions.autoop", CATEGORY_COMMON, true); + property.Comment = "set to false to prevent Forestry's user from autooping."; + Config.fakeUserAutoop = Boolean.parseBoolean(property.Value); + + registerClimates(); + ForestryTrigger.initialize(); + + config.save(); + + loadHints(); + } + + private static void setDebugMode() { + File debug = new File(Proxies.common.getForestryRoot(), "config/" + Defaults.MOD.toLowerCase(Locale.ENGLISH) + "/DEBUG.ON"); + isDebug = debug.exists(); + } + + private static void CopyFileToFS(File destination, String resourcePath) { + InputStream stream = Config.class.getResourceAsStream(resourcePath); + OutputStream outstream; + int readBytes; + byte[] buffer = new byte[4096]; + try { + + if (destination.getParentFile() != null) + destination.getParentFile().mkdirs(); + + if (!destination.exists() && !destination.createNewFile()) + return; + + outstream = new FileOutputStream(destination); + while ((readBytes = stream.read(buffer)) > 0) + outstream.write(buffer, 0, readBytes); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + private static void loadHints() { + + Properties prop = new Properties(); + + try { + InputStream hintStream = Localization.class.getResourceAsStream("/config/forestry/hints.properties"); + prop.load(hintStream); + } catch (Exception ex) { + ex.printStackTrace(); + } + + for (String key : prop.stringPropertyNames()) + hints.put(key, parseHints(prop.getProperty(key))); + } + + private static String[] parseHints(String list) { + if (list.isEmpty()) + return new String[0]; + else + return list.split("[;]+"); + } + + private static String[] parseStructureKeys(String list) { + if (list.isEmpty()) + return new String[0]; + else + return list.split("[;]+"); + + } + + private static String[] parseStamps(String list) { + if (list.isEmpty()) + return new String[0]; + else + return list.split("[;]+"); + } + + private static void registerClimates() { + + for (BiomeGenBase biome : BiomeGenBase.getBiomeGenArray()) { + if (biome == null) + continue; + + if (BiomeDictionary.isBiomeOfType(biome, BiomeDictionary.Type.NETHER)) + EnumTemperature.hellishBiomeIds.add(biome.biomeID); + else if (biome.temperature >= 2.0f) + EnumTemperature.hotBiomeIds.add(biome.biomeID); + else if (biome.temperature >= 1.2f) + EnumTemperature.warmBiomeIds.add(biome.biomeID); + else if (biome.temperature >= 0.2f) + EnumTemperature.normalBiomeIds.add(biome.biomeID); + else if (biome.temperature >= 0.15f) + EnumTemperature.coldBiomeIds.add(biome.biomeID); + else + EnumTemperature.icyBiomeIds.add(biome.biomeID); + } + + // / HUMIDITY + for (BiomeGenBase biome : BiomeGenBase.getBiomeGenArray()) { + if (biome == null) + continue; + + if (biome.rainfall >= 0.9f) + EnumHumidity.dampBiomeIds.add(biome.biomeID); + else if (biome.rainfall >= 0.3f) + EnumHumidity.normalBiomeIds.add(biome.biomeID); + else + EnumHumidity.aridBiomeIds.add(biome.biomeID); + } + + } + + public static boolean getOrCreateBooleanProperty(String key, String kind, boolean defaults) { + return Boolean.parseBoolean(config.get(key, kind, defaults).Value); + } + +} diff --git a/forestry_common/core/forestry/core/config/Configuration.java b/forestry_common/core/forestry/core/config/Configuration.java new file mode 100755 index 000000000..440392b3f --- /dev/null +++ b/forestry_common/core/forestry/core/config/Configuration.java @@ -0,0 +1,286 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +import net.minecraftforge.common.config.Configuration.UnicodeInputStreamReader; + +import forestry.core.proxy.Proxies; + +public class Configuration { + + private String newLine; + private ArrayList purge = new ArrayList(); + private TreeMap> categorized = new TreeMap>(); + + public Configuration() { + newLine = System.getProperty("line.separator"); + } + + public void addPurge(String key) { + purge.add(key); + } + + public Property get(String key, String category, boolean defaultVal) { + + Property existing = getExisting(key, category); + if (existing != null) + return existing; + + // Create new property since none exists yet. + Property property = new Property(key, new Boolean(defaultVal).toString()); + categorized.get(category).add(property); + return property; + } + + public Property get(String key, String category, int defaultVal) { + + Property existing = getExisting(key, category); + if (existing != null) + return existing; + + // Create new property since none exists yet. + Property property = new Property(key, new Integer(defaultVal).toString()); + categorized.get(category).add(property); + return property; + } + + public Property get(String key, String category, float defaultVal) { + + Property existing = getExisting(key, category); + if (existing != null) + return existing; + + // Create new property since none exists yet. + Property property = new Property(key, new Float(defaultVal).toString()); + categorized.get(category).add(property); + return property; + } + + public Property get(String key, String category, String defaultVal) { + + Property existing = getExisting(key, category); + if (existing != null) + return existing; + + // Create new property since none exists yet. + Property property = new Property(key, defaultVal); + categorized.get(category).add(property); + return property; + } + + public void set(String key, String category, boolean val) { + Property existing = getExisting(key, category); + if (existing != null) { + existing.Value = new Boolean(val).toString(); + return; + } + + // Create new property since none exists yet. + Property property = new Property(key, new Boolean(val).toString()); + categorized.get(category).add(property); + + } + + public void set(String key, String category, String val) { + Property existing = getExisting(key, category); + if (existing != null) { + existing.Value = val; + return; + } + + // Create new property since none exists yet. + Property property = new Property(key, val); + categorized.get(category).add(property); + + } + + public void set(String key, String category, int val) { + Property existing = getExisting(key, category); + if (existing != null) { + existing.Value = new Integer(val).toString(); + return; + } + + // Create new property since none exists yet. + Property property = new Property(key, new Integer(val).toString()); + categorized.get(category).add(property); + + } + + public void set(String key, String category, float val) { + Property existing = getExisting(key, category); + if (existing != null) { + existing.Value = new Float(val).toString(); + return; + } + + // Create new property since none exists yet. + Property property = new Property(key, new Float(val).toString()); + categorized.get(category).add(property); + + } + + public Property getExisting(String key, String category) { + if (!categorized.containsKey(category)) + loadCategory(category); + + for (Property property : categorized.get(category)) + if (property.Key.equals(key)) + return property; + + return null; + } + + public File getCategoryFile(String category) { + return new File(Proxies.common.getForestryRoot(), "config/" + Defaults.MOD.toLowerCase(Locale.ENGLISH) + "/" + category + ".conf"); + } + + public void loadCategory(String category) { + + File file = getCategoryFile(category); + + categorized.remove(category); + categorized.put(category, new ArrayList()); + + try { + + if (file.getParentFile() != null) + file.getParentFile().mkdirs(); + + if (!file.exists()) + return; + + if (!file.canRead()) + return; + + UnicodeInputStreamReader filein = new UnicodeInputStreamReader(new FileInputStream(file), "UTF-8"); + BufferedReader reader = new BufferedReader(filein); + + String lastComment = null; + String line; + + while (true) { + line = reader.readLine(); + + if (line == null) + break; + + if (line.startsWith("#")) { + if (line.length() > 3) + lastComment = line.substring(2, line.length() - 1); + continue; + } + + if (!line.contains("=")) + continue; + + String[] tokens = line.split("="); + Property property; + if (tokens.length > 1) + property = new Property(tokens[0], tokens[1].trim()); + else + property = new Property(tokens[0], ""); + + if (lastComment != null) { + property.Comment = lastComment; + lastComment = null; + } + categorized.get(category).add(property); + } + + reader.close(); + + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public void save() { + Iterator>> it = categorized.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + saveFile(getCategoryFile(entry.getKey()), entry.getValue()); + } + } + + private void saveFile(File file, ArrayList properties) { + + try { + + if (file.getParentFile() != null) + file.getParentFile().mkdirs(); + + if (!file.exists() && !file.createNewFile()) + return; + + if (!file.canWrite()) + return; + + FileOutputStream fileout = new FileOutputStream(file); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fileout, "UTF-8")); + + writer.write("# " + Defaults.MOD + newLine + "# " + Version.getVersion() + newLine); + + writer.write("#" + newLine + "# Config files:" + newLine); + writer.write("# base.conf\t\t-\t Contains Forge configuration for block and item ids" + newLine); + writer.write("# common.conf\t\t-\t Contains all options common to Forestry" + newLine); + writer.write("# apiculture.conf\t-\t Contains all options for bee breeding" + newLine); + writer.write("# backpacks.conf\t-\t Contains custom configurations for backpacks" + newLine); + writer.write("# pipes.conf\t\t-\t Configures item id for the apiarist's pipe" + newLine); + writer.write("# gamemodes/\t\t-\t Configures available gamemodes"); + TreeMap> subsectioned = getSubsectioned(properties); + + Iterator>> it = subsectioned.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + writer.write(newLine + newLine + "#####################" + newLine + "# " + entry.getKey().toUpperCase() + newLine + "#####################" + + newLine); + + for (Property property : entry.getValue()) { + if(purge.contains(property.Key)) + continue; + if (property.Comment != null) + writer.write("# " + property.Comment + newLine); + writer.write(property.Key + "=" + property.Value + newLine); + } + } + + writer.close(); + + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + private TreeMap> getSubsectioned(ArrayList properties) { + TreeMap> subsectioned = new TreeMap>(); + + for (Property property : properties) { + String subsection = property.Key.split("\\.")[0]; + if (!subsectioned.containsKey(subsection)) + subsectioned.put(subsection, new ArrayList()); + subsectioned.get(subsection).add(property); + } + + return subsectioned; + } + +} diff --git a/forestry_common/core/forestry/core/config/Defaults.java b/forestry_common/core/forestry/core/config/Defaults.java new file mode 100755 index 000000000..920053f00 --- /dev/null +++ b/forestry_common/core/forestry/core/config/Defaults.java @@ -0,0 +1,259 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +import java.util.Locale; + +import net.minecraftforge.oredict.OreDictionary; + +public class Defaults { + // System + public static final String MOD = "Forestry"; + public static final String ID = MOD.toLowerCase(Locale.ENGLISH); + public static final String URL = "http://forestry.sengir.net/"; + + public static final int WILDCARD = OreDictionary.WILDCARD_VALUE; + + public static final int WORLD_HEIGHT = 256; + + public static final int FLAG_BLOCK_UPDATE = 1; + public static final int FLAG_BLOCK_SYNCH = 2; + + public static final int NET_MAX_UPDATE_DISTANCE = 50; + + public static final String DEFAULT_POWER_FRAMEWORK = "forestry.energy.BioPowerFramework"; + public static final int BUCKET_VOLUME = 1000; + + public static final int[] FACINGS = { 0, 1, 2, 3, 4, 5 }; + public static final int FACING_UP = 1; + public static final int FACING_DOWN = 0; + public static final int FACING_NORTH = 2; + public static final int FACING_SOUTH = 3; + public static final int FACING_WEST = 4; + public static final int FACING_EAST = 5; + public static final int[] FACING_SIDES = { FACING_NORTH, FACING_SOUTH, FACING_WEST, FACING_EAST }; + public static final int[] FACING_NORTHSOUTH = { FACING_NORTH, FACING_SOUTH }; + public static final int[] FACING_WESTEAST = { FACING_WEST, FACING_EAST }; + public static final int[] FACINGS_NONE = new int[0]; + + public static final String LIQUID_WATER = "water"; + public static final String LIQUID_LAVA = "lava"; + public static final String LIQUID_MILK = "milk"; + public static final String LIQUID_BIOMASS = "biomass"; + public static final String LIQUID_ETHANOL = "bioethanol"; + public static final String LIQUID_SEEDOIL = "seedoil"; + public static final String LIQUID_HONEY = "honey"; + public static final String LIQUID_JUICE = "juice"; + public static final String LIQUID_ICE = "ice"; + public static final String LIQUID_MEAD = "short.mead"; + public static final String LIQUID_GLASS = "glass"; + public static final String LIQUID_OIL = "oil"; + public static final String LIQUID_FUEL = "fuel"; + + // Textures + public static final String TEXTURE_PATH_GUI = "textures/gui"; + public static final String TEXTURE_PATH_BLOCKS = "textures/blocks"; + public static final String TEXTURE_PATH_ITEMS = "textures/items"; + public static final String TEXTURE_PATH_ENTITIES = "textures/entity"; + + public static final String TEXTURE_BLOCKS = TEXTURE_PATH_BLOCKS + "/blocks.png"; + public static final String TEXTURE_ARBORICULTURE = TEXTURE_PATH_BLOCKS + "/arboriculture.png"; + public static final String TEXTURE_PODS = TEXTURE_PATH_BLOCKS + "/pods.png"; + public static final String TEXTURE_FARM = TEXTURE_PATH_BLOCKS + "/farm.png"; + + public static final String TEXTURE_APIARIST_ARMOR_PRIMARY = TEXTURE_PATH_ITEMS + "/apiarist_armor_1.png"; + public static final String TEXTURE_APIARIST_ARMOR_SECONDARY = TEXTURE_PATH_ITEMS + "/apiarist_armor_2.png"; + public static final String TEXTURE_NATURALIST_ARMOR_PRIMARY = TEXTURE_PATH_ITEMS + "/naturalist_armor_1.png"; + public static final String TEXTURE_SKIN_BEEKPEEPER = TEXTURE_PATH_ENTITIES + "/beekeeper.png"; + public static final String TEXTURE_SKIN_LUMBERJACK = TEXTURE_PATH_ENTITIES + "/lumberjack.png"; + + public static final String TEXTURE_ICONS_MINECRAFT = "/gui/items.png"; + public static final String TEXTURE_BLOCKS_MINECRAFT = "/terrain.png"; + + // Villagers + public static final int ID_VILLAGER_BEEKEEPER = 80; + public static final int ID_VILLAGER_LUMBERJACK = 81; + + // Village Chest Gen hook + public static final String CHEST_GEN_HOOK_NATURALIST_CHEST = "naturalistChest"; + + // Definition IDs + public static final int DEFINITION_ANALYZER_META = 0; + public static final int DEFINITION_ESCRITOIRE_META = 1; + + public static final int DEFINITION_APIARY_META = 0; + public static final int DEFINITION_APIARISTCHEST_META = 1; + public static final int DEFINITION_BEEHOUSE_META = 2; + + public static final int DEFINITION_ENGINETIN_META = 0; + public static final int DEFINITION_ENGINECOPPER_META = 1; + public static final int DEFINITION_ENGINEBRONZE_META = 2; + public static final int DEFINITION_GENERATOR_META = 3; + public static final int DEFINITION_ENGINECLOCKWORK_META = 4; + + public static final int DEFINITION_MAILBOX_META = 0; + public static final int DEFINITION_TRADESTATION_META = 1; + public static final int DEFINITION_PHILATELIST_META = 2; + + public static final int DEFINITION_BOTTLER_META = 0; + public static final int DEFINITION_CARPENTER_META = 1; + public static final int DEFINITION_CENTRIFUGE_META = 2; + public static final int DEFINITION_FERMENTER_META = 3; + public static final int DEFINITION_MOISTENER_META = 4; + public static final int DEFINITION_SQUEEZER_META = 5; + public static final int DEFINITION_STILL_META = 6; + public static final int DEFINITION_RAINMAKER_META = 7; + + public static final int DEFINITION_FABRICATOR_META = 0; + public static final int DEFINITION_RAINTANK_META = 1; + public static final int DEFINITION_WORKTABLE_META = 2; + + public static final int DEFINITION_LEPICHEST_META = 0; + + public static final int DEFINITION_ARBCHEST_META = 0; + + // Package Ids + public static final int ID_PACKAGE_MACHINE_FERMENTER = 0; + public static final int ID_PACKAGE_MACHINE_STILL = 1; + public static final int ID_PACKAGE_MACHINE_BOTTLER = 2; + public static final int ID_PACKAGE_MACHINE_RAINTANK = 3; + public static final int ID_PACKAGE_MACHINE_CARPENTER = 5; + public static final int ID_PACKAGE_MACHINE_MOISTENER = 6; + public static final int ID_PACKAGE_MACHINE_APIARY = 7; + public static final int ID_PACKAGE_MACHINE_CENTRIFUGE = 8; + public static final int ID_PACKAGE_MACHINE_SQUEEZER = 9; + public static final int ID_PACKAGE_MACHINE_ALVEARY = 10; + public static final int ID_PACKAGE_MACHINE_FABRICATOR = 11; + + public static final int ID_PACKAGE_MILL_RAINMAKER = 1; + public static final int ID_PACKAGE_MILL_APIARIST_CHEST = 3; + public static final int ID_PACKAGE_MILL_ANALYZER = 4; + public static final int ID_PACKAGE_MILL_MAILBOX = 5; + public static final int ID_PACKAGE_MILL_TRADER = 6; + public static final int ID_PACKAGE_MILL_PHILATELIST = 7; + + // Item Ids + + public static final int SLOTS_BACKPACK_DEFAULT = 15; + public static final int SLOTS_BACKPACK_T2 = 45; + public static final int SLOTS_BACKPACK_APIARIST = 125; + + // Bee ids + public static final int ID_BEE_SPECIES_REDDENED = 31; + public static final int ID_BEE_SPECIES_DARKENED = 32; + public static final int ID_BEE_SPECIES_OMEGA = 33; + + // Food stuff + public static final int FOOD_AMBROSIA_HEAL = 8; + public static final int FOOD_JUICE_HEAL = 2; + public static final float FOOD_JUICE_SATURATION = 0.2f; + public static final int FOOD_HONEY_HEAL = 2; + public static final float FOOD_HONEY_SATURATION = 0.2f; + + // IndustrialCraft 2 + public static final int ID_IC2_FUELCAN_DAMAGE = 6480; + + // BuildCraft + public static final int BUILDCRAFT_BLOCKID_ENGINE = 161; + public static final int BUILDCRAFT_BLOCKID_PIPE = 166; + + public static final int APIARY_MIN_LEVEL_LIGHT = 11; + public static final int APIARY_BREEDING_TIME = 100; + + // Energy + public static final int ENGINE_TANK_CAPACITY = 10 * BUCKET_VOLUME; + public static final int ENGINE_CYCLE_DURATION_WATER = 1000; + public static final int ENGINE_CYCLE_DURATION_JUICE = 2500; + public static final int ENGINE_CYCLE_DURATION_HONEY = 2500; + public static final int ENGINE_CYCLE_DURATION_MILK = 10000; + public static final int ENGINE_CYCLE_DURATION_SEED_OIL = 2500; + public static final int ENGINE_CYCLE_DURATION_BIOMASS = 2500; + public static final int ENGINE_CYCLE_DURATION_ETHANOL = 15000; + public static final int ENGINE_FUEL_VALUE_WATER = 1; + public static final int ENGINE_FUEL_VALUE_JUICE = 1; + public static final int ENGINE_FUEL_VALUE_HONEY = 2; + public static final int ENGINE_FUEL_VALUE_MILK = 1; + public static final int ENGINE_FUEL_VALUE_SEED_OIL = 3; + public static final int ENGINE_FUEL_VALUE_BIOMASS = 5; + public static final int ENGINE_HEAT_VALUE_LAVA = 20; + + public static final float ENGINE_PISTON_SPEED_MAX = 0.08f; + + public static final int ENGINE_BRONZE_HEAT_MAX = 10000; + public static final int ENGINE_BRONZE_HEAT_LOSS_COOL = 2; + public static final int ENGINE_BRONZE_HEAT_LOSS_OPERATING = 1; + public static final int ENGINE_BRONZE_HEAT_LOSS_OVERHEATING = 5; + public static final int ENGINE_BRONZE_HEAT_GENERATION_ENERGY = 1; + + public static final int ENGINE_COPPER_CYCLE_DURATION_PEAT = 5000; + public static final int ENGINE_COPPER_FUEL_VALUE_PEAT = 1; + public static final int ENGINE_COPPER_CYCLE_DURATION_BITUMINOUS_PEAT = 6000; + public static final int ENGINE_COPPER_FUEL_VALUE_BITUMINOUS_PEAT = 2; + public static final int ENGINE_COPPER_HEAT_MAX = 10000; + public static final int ENGINE_COPPER_ASH_FOR_ITEM = 7500; + + public static final int ENGINE_TIN_HEAT_MAX = 3000; + public static final int ENGINE_TIN_EU_FOR_CYCLE = 6; + public static final int ENGINE_TIN_ENERGY_PER_CYCLE = 2; + public static final int ENGINE_TIN_MAX_EU_STORED = 2 * ENGINE_TIN_EU_FOR_CYCLE; + public static final int ENGINE_TIN_MAX_EU_BATTERY = 100; + + // Factory + public static final int PROCESSOR_TANK_CAPACITY = 10 * BUCKET_VOLUME; + + public static final int MACHINE_LATENCY = 1000; + public static final int MACHINE_MIN_ENERGY_RECEIVED = 5; + public static final int MACHINE_MAX_ENERGY_RECEIVED = 40; + public static final int MACHINE_MIN_ACTIVATION_ENERGY = 15; + public static final int MACHINE_MAX_ENERGY = 500; + + public static final int RAINMAKER_RAIN_DURATION_IODINE = 10000; + + public static final int STILL_DESTILLATION_DURATION = 100; + public static final int STILL_DESTILLATION_INPUT = 10; + public static final int STILL_DESTILLATION_OUTPUT = 3; + + public static final int BOTTLER_FILLING_TIME = 20; + public static final int BOTTLER_FUELCAN_VOLUME = 2000; + + // Storage + public static final int RAINTANK_TANK_CAPACITY = 30 * BUCKET_VOLUME; + public static final int RAINTANK_AMOUNT_PER_UPDATE = 10; + public static final int RAINTANK_FILLING_TIME = 12; + public static final int CARPENTER_CRATING_CYCLES = 5; + public static final int CARPENTER_UNCRATING_CYCLES = 5; + public static final int CARPENTER_CRATING_LIQUID_QUANTITY = 100; + + // SMP gui ids + public static final int ID_GUI_ARBORETUM = 90; + public static final int ID_GUI_BOTTLER = 91; + public static final int ID_GUI_ENGINE_BRONZE = 92; + public static final int ID_GUI_FARM = 93; + public static final int ID_GUI_FERMENTER = 94; + public static final int ID_GUI_FORESTER = 95; + public static final int ID_GUI_PLANTATION = 96; + public static final int ID_GUI_PUMPKIN_FARM = 97; + public static final int ID_GUI_PEAT_BOG = 98; + public static final int ID_GUI_STILL = 99; + public static final int ID_GUI_ENGINE_COPPER = 89; + public static final int ID_GUI_RAINTANK = 88; + public static final int ID_GUI_GENERATOR = 87; + public static final int ID_GUI_CARPENTER = 86; + public static final int ID_GUI_MOISTENER = 85; + public static final int ID_GUI_MUSHROOM_FARM = 84; + public static final int ID_GUI_APIARY = 83; + public static final int ID_GUI_CENTRIFUGE = 82; + public static final int ID_GUI_APIARIST_INVENTORY = 81; + public static final int ID_GUI_BACKPACK = 80; + public static final int ID_GUI_SQUEEZER = 79; + public static final int ID_GUI_NETHER_FARM = 78; + public static final int ID_GUI_BEEALYZER = 100; + public static final int ID_GUI_BACKPACK_T2 = 101; + public static final int ID_GUI_BIOME_FINDER = 102; + // ID 100 used by bucket filler. +} diff --git a/forestry_common/core/forestry/core/config/ForestryBlock.java b/forestry_common/core/forestry/core/config/ForestryBlock.java new file mode 100755 index 000000000..06fdeca9f --- /dev/null +++ b/forestry_common/core/forestry/core/config/ForestryBlock.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +import net.minecraft.block.Block; + +import forestry.core.gadgets.BlockBase; + +/** + * Allows direct access to Forestry's blocks. Will be populated during BaseMod.load(). + * + * All of this stuff is metadata sensitive which is not reflected here! + * + * Make sure to only reference it in modsLoaded() or later. + * + * @author SirSengir + * + */ +public class ForestryBlock { + + /** + * 0 - Humus 1 - Bog Earth + */ + public static Block soil; + /** + * 0 - Apatite Ore 1 - Copper Ore 2 - Tin Ore + */ + public static Block resources; + /** + * 0 - Legacy 1 - Forest Hive 2 - Meadows Hive + */ + public static Block beehives; + + public static Block mushroom; + public static Block candle; + public static Block stump; + public static Block glass; + + public static Block planks1; + public static Block planks2; + public static Block slabs1; + public static Block slabs2; + public static Block slabs3; + public static Block slabs4; + public static Block log1; + public static Block log2; + public static Block log3; + public static Block log4; + public static Block log5; + public static Block log6; + public static Block log7; + public static Block log8; + + public static Block fences1; + public static Block fences2; + public static Block stairs; + + public static Block saplingGE; + public static Block leaves; + public static Block pods; + + public static BlockBase arboriculture; + + public static Block alveary; + public static Block farm; + + public static BlockBase core; + public static BlockBase apiculture; + public static BlockBase mail; + + public static BlockBase engine; + public static BlockBase factoryTESR; + public static BlockBase factoryPlain; + + public static BlockBase lepidopterology; +} diff --git a/forestry_common/core/forestry/core/config/ForestryItem.java b/forestry_common/core/forestry/core/config/ForestryItem.java new file mode 100755 index 000000000..376c02ff5 --- /dev/null +++ b/forestry_common/core/forestry/core/config/ForestryItem.java @@ -0,0 +1,275 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import forestry.core.proxy.Proxies; + +/** + * Allows direct access to Forestry's items. Will be populated during + * preInit and Init. + * + * Most items with the exception of bees do not care for damage values. + * + * Make sure to only reference it in postInit or later. + * + * @author SirSengir + * + */ +public enum ForestryItem { + + fertilizerBio, + fertilizerCompound, + apatite, + // Ingots + ingotCopper, + ingotTin, + ingotBronze, + // Tools + wrench, + pipette, + bucketBiomass, + vialEmpty, + vialCatalyst, + bucketBiofuel, + // Crafting + impregnatedCasing, + sturdyCasing, + hardenedCasing, + craftingMaterial, + // Rainmaker + iodineCharge, + // Gears + gearBronze, + gearCopper, + gearTin, + // Chipsets + circuitboards, + solderingIron, + tubes, + // Mail + stamps, + letters, + catalogue, + // mailIndicator, + + // Carpenter + stickImpregnated, + woodPulp, + carton, + crate, + // Tools + bronzePickaxe, + brokenBronzePickaxe, + kitPickaxe, + bronzeShovel, + brokenBronzeShovel, + kitShovel, + // Do not touch - contagious! + tent, + biomeFinder, + // Moistener + mouldyWheat, + decayingWheat, + mulch, + // Peat + peat, + bituminousPeat, + ash, + // Bees + beeQueenGE, + beeDroneGE, + beePrincessGE, + beeLarvaeGE, + beealyzer, + imprinter, + honeyDrop, + scoop, + beeswax, + pollen, + propolis, + honeydew, + royalJelly, + honeyedSlice, + ambrosia, + honeyPot, + phosphor, + refractoryWax, + waxCast, + frameUntreated, + frameImpregnated, + frameProven, + // Trees + sapling, + pollenFertile, + treealyzer, + grafter, + grafterProven, + // Butterflies + butterflyGE, + flutterlyzer, + serumGE, + caterpillarGE, + researchNote, + // Beverages + beverage, + infuser, + // Naturalist's Armor + naturalistHat, + // Apiarist's Armor + apiaristHat, + apiaristChest, + apiaristLegs, + apiaristBoots, + // Combs + beeComb, + // Fruits + fruits, + // Backpacks + apiaristBackpack, + lepidopteristBackpack, + minerBackpack, + diggerBackpack, + foresterBackpack, + hunterBackpack, + builderBackpack, + adventurerBackpack, + // T2 + minerBackpackT2, + diggerBackpackT2, + foresterBackpackT2, + hunterBackpackT2, + builderBackpackT2, + adventurerBackpackT2, + // Capsules + waxCapsule, + waxCapsuleWater, + waxCapsuleBiomass, + waxCapsuleBiofuel, + waxCapsuleOil, + waxCapsuleFuel, + waxCapsuleSeedOil, + waxCapsuleHoney, + waxCapsuleJuice, + waxCapsuleIce, + // Refractory Capsules + refractoryEmpty, + refractoryWater, + refractoryBiomass, + refractoryBiofuel, + refractoryOil, + refractoryFuel, + refractoryLava, + refractorySeedOil, + refractoryHoney, + refractoryJuice, + refractoryIce, + // Cans + canWater, + canEmpty, + canBiomass, + canBiofuel, + canOil, + canFuel, + canLava, + canSeedOil, + canHoney, + canJuice, + canIce, + // Crating + cratedWood, + cratedCobblestone, + cratedDirt, + cratedStone, + cratedBrick, + cratedCacti, + cratedSand, + cratedObsidian, + cratedNetherrack, + cratedSoulsand, + cratedSandstone, + cratedBogearth, + cratedHumus, + cratedNetherbrick, + cratedPeat, + cratedApatite, + cratedFertilizer, + cratedTin, + cratedCopper, + cratedBronze, + cratedWheat, + cratedMycelium, + cratedMulch, + cratedSilver, + cratedBrass, + cratedNikolite, + cratedCookies, + cratedHoneycombs, + cratedBeeswax, + cratedPollen, + cratedPropolis, + cratedHoneydew, + cratedRoyalJelly, + cratedCocoaComb, + cratedRedstone, + cratedLapis, + cratedReeds, + cratedClay, + cratedGlowstone, + cratedApples, + cratedNetherwart, + cratedResin, + cratedRubber, + cratedScrap, + cratedUUM, + cratedSimmeringCombs, + cratedStringyCombs, + cratedFrozenCombs, + cratedDrippingCombs, + cratedRefractoryWax, + cratedPhosphor, + cratedAsh, + cratedCharcoal, + cratedGravel, + cratedCoal, + cratedSeeds, + cratedSaplings; + private Item item; + + public void registerItem(Item item, String name) { + this.item = item; + item.setUnlocalizedName(name); + Proxies.common.registerItem(item); + } + + public boolean isItemEqual(ItemStack stack) { + return stack != null && this.item == stack.getItem(); + } + + public boolean isItemEqual(Item i) { + return i != null && this.item == i; + } + + public Item item() { + return item; + } + + public ItemStack getItemStack() { + return getItemStack(1, 0); + } + + public ItemStack getItemStack(int qty) { + return getItemStack(qty, 0); + } + + public ItemStack getItemStack(int qty, int meta) { + return new ItemStack(item, qty, meta); + } +} diff --git a/forestry_common/core/forestry/core/config/Property.java b/forestry_common/core/forestry/core/config/Property.java new file mode 100755 index 000000000..7fb68851f --- /dev/null +++ b/forestry_common/core/forestry/core/config/Property.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +public class Property { + public String Key; + public String Value; + public String Comment; + + public Property(String key, String value) { + Key = key; + Value = value; + } +} diff --git a/forestry_common/core/forestry/core/config/SessionVars.java b/forestry_common/core/forestry/core/config/SessionVars.java new file mode 100755 index 000000000..4242db8a0 --- /dev/null +++ b/forestry_common/core/forestry/core/config/SessionVars.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +import java.util.HashMap; + +public class SessionVars { + + private static HashMap stringVars = new HashMap(); + + private static Class openedLedger; + + public static void setOpenedLedger(Class ledgerClass) { + openedLedger = ledgerClass; + } + + public static Class getOpenedLedger() { + return openedLedger; + } + + public static void setStringVar(String ident, String val) { + stringVars.put(ident, val); + } + + public static String getStringVar(String ident) { + if(stringVars.containsKey(ident)) + return stringVars.get(ident); + + return null; + } + + public static void clearStringVar(String ident) { + stringVars.remove(ident); + } +} diff --git a/forestry_common/core/forestry/core/config/Version.java b/forestry_common/core/forestry/core/config/Version.java new file mode 100755 index 000000000..514ff179e --- /dev/null +++ b/forestry_common/core/forestry/core/config/Version.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.config; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.versioning.DefaultArtifactVersion; + +import forestry.Forestry; +import forestry.core.proxy.Proxies; + +/** + * With permission from pahimar. + * + * @author Pahimar + * + */ +public class Version { + + public enum EnumUpdateState { + + CURRENT, OUTDATED, CONNECTION_ERROR + } + public static final String VERSION = "@VERSION@"; + public static final String BUILD_NUMBER = "@BUILD_NUMBER@"; + public static final String[] FAILED_CHANGELOG = new String[] { String.format("Unable to retrieve changelog for %s", Defaults.MOD) }; + public static final String FINGERPRINT = "@FINGERPRINT@"; + public static final String FORGEPRINT = "de4cf8a3f3bc15635810044c39240bf96804ea7d"; + private static final String REMOTE_VERSION_FILE = "http://bit.ly/forestryver"; + private static final String REMOTE_CHANGELOG_ROOT = "https://dl.dropbox.com/u/44760587/forestry/changelog/"; + private static final String REMOTE_FINGERPRINT_ROOT = new String(new byte[] { 104, 116, 116, 112, 115, 58, 47, 47, 100, 108, 46, 100, 114, 111, 112, 98, + 111, 120, 46, 99, 111, 109, 47, 117, 47, 52, 52, 55, 54, 48, 53, 56, 55, 47, 102, 111, 114, 101, 115, 116, 114, 121, 47, 102, 105, 110, 103, 101, + 114, 112, 114, 105, 110, 116, 115, 47 }); + public static EnumUpdateState currentVersion = EnumUpdateState.CURRENT; + public static final String FORGE_VERSION = "@FORGE_VERSION@"; + public static String remoteFingerprint; + public static String remoteForgeprint; + private static String recommendedVersion; + private static String[] cachedChangelog = FAILED_CHANGELOG; + + public static String getVersion() { + return VERSION + " (" + BUILD_NUMBER + ")"; + } + + public static boolean isOutdated() { + return currentVersion == EnumUpdateState.OUTDATED; + } + + public static boolean needsUpdateNoticeAndMarkAsSeen() { + if (!isOutdated()) + return false; + + Property property = Config.config.get("vars.version.seen", Config.CATEGORY_COMMON, VERSION); + property.Comment = "indicates the last version the user has been informed about and will suppress further notices on it."; + String seenVersion = property.Value; + + if (recommendedVersion == null || recommendedVersion.equals(seenVersion)) + return false; + + property.Value = recommendedVersion; + Config.config.save(); + return true; + } + + public static String getRecommendedVersion() { + return recommendedVersion; + } + + public static void updateRemoteFingerprints() { + remoteFingerprint = retrieveRemoteString(REMOTE_FINGERPRINT_ROOT + new String(new byte[] { 102, 111, 114, 101, 115, 116, 114, 121, 46, 107, 101, 121 }) + + "1", FINGERPRINT); + remoteFingerprint = retrieveRemoteString(REMOTE_FINGERPRINT_ROOT + new String(new byte[] { 102, 111, 114, 103, 101, 46, 107, 101, 121 }) + "1", + FORGEPRINT); + } + + public static String retrieveRemoteString(String location, String defaultValue) { + try { + + HttpURLConnection conn = null; + while (location != null && !location.isEmpty()) { + URL url = new URL(location); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("User-Agent", + "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)"); + conn.connect(); + location = conn.getHeaderField("Location"); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = null; + if ((line = reader.readLine()) != null) + return line; + + } catch (Exception e) { + e.printStackTrace(); + Proxies.log.warning("Unable to read from remote fingerprint authority."); + } + + return defaultValue; + } + + private static class VersionChecker extends Thread { + + @Override + public void run() { + try { + String location = REMOTE_VERSION_FILE; + HttpURLConnection conn = null; + while (location != null && !location.isEmpty()) { + URL url = new URL(location); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("User-Agent", + "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)"); + conn.connect(); + location = conn.getHeaderField("Location"); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = null; + String mcVersion = Proxies.common.getMinecraftVersion(); + while ((line = reader.readLine()) != null) { + if (line.startsWith(mcVersion) && line.contains(Defaults.MOD)) { + String[] tokens = line.split(":"); + recommendedVersion = tokens[2]; + } + } + + if (recommendedVersion == null) + return; + + int result = FMLCommonHandler.instance().findContainerFor(Forestry.instance).getProcessedVersion().compareTo(new DefaultArtifactVersion(recommendedVersion)); + if (result >= 0) { + Proxies.log.finer("Using the latest version [" + VERSION + " (build:" + BUILD_NUMBER + ")] for Minecraft " + mcVersion); + currentVersion = EnumUpdateState.CURRENT; + return; + } + + cachedChangelog = grabChangelog(recommendedVersion); + + Proxies.log.warning("Using outdated version [" + VERSION + " (build:" + BUILD_NUMBER + ")] for Minecraft " + mcVersion + ". Consider updating."); + currentVersion = EnumUpdateState.OUTDATED; + + } catch (Exception e) { +// e.printStackTrace(); + Proxies.log.warning("Unable to read from remote version authority."); + currentVersion = EnumUpdateState.CONNECTION_ERROR; + } + } + } + + public static void versionCheck() { + new VersionChecker().start(); + } + + public static String[] getChangelog() { + return cachedChangelog; + } + + public static String[] grabChangelog(String version) { + + try { + + String location = REMOTE_CHANGELOG_ROOT + version; + HttpURLConnection conn = null; + while (location != null && !location.isEmpty()) { + URL url = new URL(location); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("User-Agent", + "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)"); + conn.connect(); + location = conn.getHeaderField("Location"); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = null; + ArrayList changelog = new ArrayList(); + while ((line = reader.readLine()) != null) { + if (line.startsWith("#")) + continue; + if (line.isEmpty()) + continue; + + changelog.add(line); + } + + return changelog.toArray(new String[0]); + + } catch (Exception ex) { +// ex.printStackTrace(); + Proxies.log.warning("Unable to read changelog from remote site."); + } + + return new String[] { String.format("Unable to retrieve changelog for %s %s", Defaults.MOD, version) }; + } +} diff --git a/forestry_common/core/forestry/core/gadgets/BlockBase.java b/forestry_common/core/forestry/core/gadgets/BlockBase.java new file mode 100755 index 000000000..72417a033 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/BlockBase.java @@ -0,0 +1,253 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.IFluidHandler; + +import forestry.core.interfaces.IOwnable; +import forestry.core.items.ItemNBTTile; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; + +public class BlockBase extends BlockForestry { + + private final List definitions = new ArrayList(); + private final boolean hasTESR; + + public BlockBase(Material material) { + this(material, false); + } + + public BlockBase(Material material, boolean hasTESR) { + super(material); + + this.hasTESR = hasTESR; + } + + public MachineDefinition addDefinition(MachineDefinition definition) { + definition.setBlock(this); + + while (definitions.size() <= definition.meta) definitions.add(null); + + definitions.set(definition.meta, definition); + + return definition; + } + + @Override + public boolean isOpaqueCube() { + return !hasTESR; + } + + @Override + public boolean renderAsNormalBlock() { + return !hasTESR; + } + + @Override + public int getRenderType() { + if (hasTESR) + return Proxies.common.getByBlockModelId(); + else + return 0; + } + + private MachineDefinition getDefinition(IBlockAccess world, int x, int y, int z) { + return getDefinition(world.getBlockMetadata(x, y, z)); + } + + private MachineDefinition getDefinition(int metadata) { + if (metadata >= definitions.size() || definitions.get(metadata) == null) + return definitions.get(0); + + return definitions.get(metadata); + } + + /* CREATIVE INVENTORY */ + @SuppressWarnings("rawtypes") + @SideOnly(Side.CLIENT) + @Override + public void getSubBlocks(Item item, CreativeTabs tab, List list) { + for (MachineDefinition definition : definitions) { + if (definition == null) + continue; + definition.getSubBlocks(item, tab, list); + } + } + + /* TILE ENTITY CREATION */ + @Override + public TileEntity createTileEntity(World world, int metadata) { + if (metadata >= definitions.size() || definitions.get(metadata) == null) + metadata = 0; + + return definitions.get(metadata).createMachine(); + } + + @Override + public TileEntity createNewTileEntity(World world, int meta) { + return createTileEntity(world, meta); // TODO: refactor to just use Block, not BlockContainer + } + + /* BLOCK DROPS */ + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + if (getDefinition(metadata).handlesDrops()) + return getDefinition(metadata).getDrops(world, x, y, z, metadata, fortune); + else + return super.getDrops(world, x, y, z, metadata, fortune); + } + + /* INTERACTION */ + @Override + public boolean isSideSolid(IBlockAccess world, int x, int y, int z, ForgeDirection side) { + return getDefinition(world, x, y, z).isSolidOnSide(world, x, y, z, side.ordinal()); + } + + @Override + public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entityliving, ItemStack stack) { + super.onBlockPlacedBy(world, x, y, z, entityliving, stack); + + TileForestry tile = (TileForestry) world.getTileEntity(x, y, z); + + if (stack.getItem() instanceof ItemNBTTile && stack.hasTagCompound()) { + tile.readFromNBT(stack.getTagCompound()); + tile.xCoord = x; + tile.yCoord = y; + tile.zCoord = z; + } + + tile.rotateAfterPlacement(world, x, y, z, entityliving, stack); + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float par7, float par8, float par9) { + if (getDefinition(world, x, y, z).onBlockActivated(world, x, y, z, player, side, par7, par8, par9)) + return true; + + if (player.isSneaking()) + return false; + + TileBase tile = (TileBase) world.getTileEntity(x, y, z); + if (!tile.isUseableByPlayer(player)) + return false; + + ItemStack current = player.getCurrentEquippedItem(); + if (current != null && current.getItem() != Items.bucket && tile instanceof IFluidHandler) { + if (Proxies.common.isSimulating(world)) { + if (LiquidHelper.handleRightClick((IFluidHandler) tile, ForgeDirection.getOrientation(side), player, true, tile.canDrainWithBucket())) { + return true; + } + } else { + if (FluidContainerRegistry.isContainer(current)) { + return true; + } + } + } + + if (!Proxies.common.isSimulating(world)) + return true; + + if (tile.allowsInteraction(player)) + tile.openGui(player, tile); + else + player.addChatMessage(new ChatComponentTranslation("\u00A7c%s %s", new ChatComponentText(tile.getOwnerName()), new ChatComponentTranslation("chat.accesslocked"))); + return true; + } + + @Override + public boolean rotateBlock(World world, int x, int y, int z, ForgeDirection axis) { + return getDefinition(world, x, y, z).rotateBlock(world, x, y, z, axis); + } + + @Override + public void onBlockAdded(World world, int x, int y, int z) { + super.onBlockAdded(world, x, y, z); + getDefinition(world, x, y, z).onBlockAdded(world, x, y, z); + } + + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + + IOwnable tile = (IOwnable) world.getTileEntity(x, y, z); + if (tile.isOwnable() && !tile.allowsRemoval(player)) + return false; + + if (getDefinition(world, x, y, z).removedByPlayer(world, player, x, y, z)) + return world.setBlockToAir(x, y, z); + else + return false; + } + + @Override + public boolean canConnectRedstone(IBlockAccess world, int x, int y, int z, int side) { + int metadata = world.getBlockMetadata(x, y, z); + if (metadata >= definitions.size() || definitions.get(metadata) == null) + metadata = 0; + return definitions.get(metadata).canConnectRedstone(world, x, y, z, side); + } + + @Override + public int damageDropped(int metadata) { + return metadata; + } + + /* TEXTURES */ + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + for (MachineDefinition def : definitions) { + def.registerIcons(register); + } + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int metadata) { + if (metadata >= definitions.size() || definitions.get(metadata) == null) + metadata = 0; + return definitions.get(metadata).getBlockTextureFromSideAndMetadata(side, metadata); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + int metadata = world.getBlockMetadata(x, y, z); + if (metadata >= definitions.size() || definitions.get(metadata) == null) + metadata = 0; + return definitions.get(metadata).getIcon(world, x, y, z, side, metadata); + } + + @Override + public boolean getUseNeighborBrightness() { + return hasTESR; + } +} diff --git a/forestry_common/core/forestry/core/gadgets/BlockForestry.java b/forestry_common/core/forestry/core/gadgets/BlockForestry.java new file mode 100755 index 000000000..0f816218a --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/BlockForestry.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import forestry.core.CreativeTabForestry; +import forestry.core.interfaces.IOwnable; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Utils; + +public abstract class BlockForestry extends BlockContainer { + + protected static boolean keepInventory = false; + protected Random furnaceRand; + + public BlockForestry(Material material) { + super(material); + setHardness(1.5f); + furnaceRand = new Random(); + setCreativeTab(CreativeTabForestry.tabForestry); + } + + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + IOwnable tile = (IOwnable) world.getTileEntity(x, y, z); + if (!tile.isOwnable() || tile.allowsRemoval(player)) + return super.removedByPlayer(world, player, x, y, z); + else + return false; + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + + if (!Proxies.common.isSimulating(world)) + return; + + TileEntity tile = world.getTileEntity(x, y, z); + if (tile instanceof TileForestry) { + TileForestry tileForestry = (TileForestry) tile; + Utils.dropInventory(tileForestry, world, x, y, z); + tileForestry.onRemoval(); + } + super.breakBlock(world, x, y, z, block, meta); + } + + @Override + public void onBlockPlacedBy(World world, int i, int j, int k, EntityLivingBase entityliving, ItemStack itemstack) { + + if (!Proxies.common.isSimulating(world)) + return; + + TileForestry tile = (TileForestry) world.getTileEntity(i, j, k); + if (entityliving instanceof EntityPlayer) + tile.owner = ((EntityPlayer) entityliving).getGameProfile().getId(); + } +} diff --git a/forestry_common/core/forestry/core/gadgets/BlockResource.java b/forestry_common/core/forestry/core/gadgets/BlockResource.java new file mode 100755 index 000000000..9d8eae49b --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/BlockResource.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.CreativeTabForestry; +import forestry.core.config.ForestryItem; +import forestry.core.render.TextureManager; + +public class BlockResource extends Block { + public BlockResource() { + super(Material.rock); + setHardness(3F); + setResistance(5F); + setCreativeTab(CreativeTabForestry.tabForestry); + } + + @Override + public void dropBlockAsItemWithChance(World world, int x, int y, int z, int metadata, float par6, int par7) { + super.dropBlockAsItemWithChance(world, x, y, z, metadata, par6, par7); + + if (metadata == 0) + this.dropXpOnBlockBreak(world, x, y, z, MathHelper.getRandomIntegerInRange(world.rand, 1, 4)); + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + ArrayList drops = new ArrayList(); + + if (metadata == 0) { + int fortmod = world.rand.nextInt(fortune + 2) - 1; + if (fortmod < 0) + fortmod = 0; + + int amount = (2 + world.rand.nextInt(5)) * (fortmod + 1); + if (amount > 0) + drops.add(ForestryItem.apatite.getItemStack(amount)); + } else + drops.add(new ItemStack(this, 1, metadata)); + + return drops; + } + + @Override + public int getDamageValue(World world, int x, int y, int z) { + return world.getBlockMetadata(x, y, z); + } + + // / CREATIVE INVENTORY + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + itemList.add(new ItemStack(this, 1, 0)); + itemList.add(new ItemStack(this, 1, 1)); + itemList.add(new ItemStack(this, 1, 2)); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon iconApatite; + @SideOnly(Side.CLIENT) + private IIcon iconCopper; + @SideOnly(Side.CLIENT) + private IIcon iconTin; + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister register) { + iconApatite = TextureManager.getInstance().registerTex(register, "ores/apatite"); + iconCopper = TextureManager.getInstance().registerTex(register, "ores/copper"); + iconTin = TextureManager.getInstance().registerTex(register, "ores/tin"); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(int i, int j) { + if (j == 0) + return iconApatite; + else if (j == 1) + return iconCopper; + else + return iconTin; + } + +} diff --git a/forestry_common/core/forestry/core/gadgets/BlockSoil.java b/forestry_common/core/forestry/core/gadgets/BlockSoil.java new file mode 100755 index 000000000..af8ca7fbd --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/BlockSoil.java @@ -0,0 +1,260 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.EnumPlantType; +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.core.CreativeTabForestry; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; + +/** + * Humus, bog earth, peat + * + * @author + * + */ +public class BlockSoil extends Block { + + private final int degradeDelimiter = 3; + + public BlockSoil() { + super(Material.sand); + setTickRandomly(true); + setHardness(0.5f); + setStepSound(soundTypeGrass); + setCreativeTab(CreativeTabForestry.tabForestry); + } + + @Override + public int tickRate(World world) { + return 500; + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + ArrayList ret = new ArrayList(); + + int type = (metadata & 0x03); + int maturity = metadata >> 2; + + if (maturity >= this.degradeDelimiter && type == 1) { + ret.add(ForestryItem.peat.getItemStack()); + ret.add(new ItemStack(Blocks.dirt)); + } else if (type == 0) + ret.add(new ItemStack(Blocks.dirt)); + else + ret.add(new ItemStack(this, 1, type)); + + return ret; + } + + @Override + public int getDamageValue(World world, int x, int y, int z) { + return (world.getBlockMetadata(x, y, z) & 0x03); + } + + @Override + public void updateTick(World world, int i, int j, int k, Random random) { + if (!Proxies.common.isSimulating(world)) + return; + + int meta = world.getBlockMetadata(i, j, k); + int type = (meta & 0x03); + + if (type == 0) + updateTickHumus(world, i, j, k, random); + else if (type == 1) + updateTickBogEarth(world, i, j, k, random); + else + Proxies.log.warning(this.getClass() + " with unknown type " + type + " encountered."); + } + + private void updateTickHumus(World world, int i, int j, int k, Random random) { + if (isEnrooted(world, i, j, k)) + degradeSoil(world, i, j, k); + } + + private void updateTickBogEarth(World world, int i, int j, int k, Random random) { + if (isMoistened(world, i, j, k)) + matureBog(world, i, j, k); + } + + /** + * + * @param world + * @param x + * @param y + * @param z + * @return + */ + private boolean isEnrooted(World world, int x, int y, int z) { + + for (int i = -1; i < 2; i++) + for (int j = -1; j < 2; j++) { + Block block = world.getBlock(x + i, y + 1, z + j); + if (block == Blocks.log || block == Blocks.sapling || block == ForestryBlock.saplingGE) + // We are not returning true if we are the base of a + // sapling. + if (i == 0 && j == 0) + return false; + else + return true; + } + + return false; + } + + /** + * If a tree or sapling is in the vicinity, there is a chance, that the soil will degrade. + * + * @param world + * @param i + * @param j + * @param k + */ + private void degradeSoil(World world, int i, int j, int k) { + + if (world.rand.nextInt(140) != 0) + return; + + int meta = world.getBlockMetadata(i, j, k); + + // Unpack first + int type = meta & 0x03; + int grade = meta >> 2; + + // Increment (de)gradation + grade++; + + // Repackage in format TTGG + meta = (grade << 2 | type); + + if (grade >= this.degradeDelimiter) + world.setBlock(i, j, k, Blocks.sand, 0, Defaults.FLAG_BLOCK_SYNCH); + else + world.setBlockMetadataWithNotify(i, j, k, meta, Defaults.FLAG_BLOCK_SYNCH); + world.markBlockForUpdate(i, j, k); + } + + public static boolean isMoistened(World world, int x, int y, int z) { + + for (int i = -2; i < 3; i++) + for (int j = -2; j < 3; j++) { + Block block = world.getBlock(x + i, y, z + j); + if (block == Blocks.water || block == Blocks.flowing_water) + return true; + } + + return false; + } + + private void matureBog(World world, int i, int j, int k) { + + if (world.rand.nextInt(13) != 0) + return; + + int meta = world.getBlockMetadata(i, j, k); + + // Unpack first + + int type = meta & 0x03; + int maturity = meta >> 2; + + if (maturity >= this.degradeDelimiter) + return; + + // Increment (de)gradation + maturity++; + + meta = (maturity << 2 | type); + world.setBlockMetadataWithNotify(i, j, k, meta, Defaults.FLAG_BLOCK_SYNCH); + world.markBlockForUpdate(i, j, k); + } + + @Override + public boolean canSustainPlant(IBlockAccess world, int x, int y, int z, ForgeDirection direction, IPlantable plant) { + EnumPlantType plantType = plant.getPlantType(world, x, y, z); + if (plantType != EnumPlantType.Crop && plantType != EnumPlantType.Plains) + return false; + + int meta = world.getBlockMetadata(x, y, z); + + return (meta & 0x03) == 0; + } + + @Override + protected boolean canSilkHarvest() { + return false; + } + + // / CREATIVE INVENTORY + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + itemList.add(new ItemStack(this, 1, 0)); + itemList.add(new ItemStack(this, 1, 1)); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon iconHumus; + @SideOnly(Side.CLIENT) + private IIcon iconBogEarth; + @SideOnly(Side.CLIENT) + private IIcon iconPeat; + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister register) { + iconHumus = TextureManager.getInstance().registerTex(register, "soil/humus"); + iconBogEarth = TextureManager.getInstance().registerTex(register, "soil/bog"); + iconPeat = TextureManager.getInstance().registerTex(register, "soil/peat"); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(int i, int j) { + + int meta = j; + int type = meta & 0x03; + int maturity = meta >> 2; + + if (type == 1) + if (maturity < this.degradeDelimiter) + return iconBogEarth; + else + return iconPeat; + else + return iconHumus; + } + +} diff --git a/forestry_common/core/forestry/core/gadgets/BlockStainedGlass.java b/forestry_common/core/forestry/core/gadgets/BlockStainedGlass.java new file mode 100755 index 000000000..0e9ed4bcb --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/BlockStainedGlass.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.List; +import java.util.Random; + +import net.minecraft.block.BlockBreakable; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.CreativeTabForestry; +import forestry.core.render.TextureManager; + +public class BlockStainedGlass extends BlockBreakable { + + public BlockStainedGlass() { + super("", Material.glass, true); + setHardness(0.3F); + setStepSound(soundTypeGlass); + setCreativeTab(CreativeTabForestry.tabForestry); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubBlocks(Item item, CreativeTabs par2CreativeTabs, List itemList) { + for (int i = 0; i < 16; i++) + itemList.add(new ItemStack(this, 1, i)); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @Override + @SideOnly(Side.CLIENT) + public void registerBlockIcons(IIconRegister register) { + icons = new IIcon[16]; + for (int i = 0; i < 16; i++) + icons[i] = TextureManager.getInstance().registerTex(register, "stained/" + i); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(int side, int meta) { + return icons[15 - meta]; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + return this.getIcon(side, world.getBlockMetadata(x, y, z)); + } + + @Override + public int damageDropped(int meta) { + return meta; + } + + @Override + public int quantityDropped(Random rand) { + return 0; + } + + @Override + public int getRenderBlockPass() { + return 1; + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + +} diff --git a/forestry_common/core/forestry/core/gadgets/BlockStructure.java b/forestry_common/core/forestry/core/gadgets/BlockStructure.java new file mode 100755 index 000000000..0660e4c26 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/BlockStructure.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.world.World; + +import forestry.api.core.ITileStructure; +import forestry.core.proxy.Proxies; + +public abstract class BlockStructure extends BlockForestry { + + public enum EnumStructureState { + VALID, INVALID, INDETERMINATE + } + + public BlockStructure(Material material) { + super(material); + setHardness(1.0f); + } + + @Override + public boolean canSilkHarvest() { + return false; + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block block, int meta) { + TileEntity tile = world.getTileEntity(x, y, z); + + super.breakBlock(world, x, y, z, block, meta); + + if (tile instanceof ITileStructure) { + ITileStructure structure = (ITileStructure) tile; + if (structure.isIntegratedIntoStructure() && !structure.isMaster()) { + ITileStructure central = structure.getCentralTE(); + if (central != null) + central.validateStructure(); + } + } + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) { + + if (player.isSneaking()) + return false; + + TileForestry tile = (TileForestry) world.getTileEntity(x, y, z); + if (!tile.isUseableByPlayer(player)) + return false; + + if (!Proxies.common.isSimulating(world)) + return player.getCurrentEquippedItem() == null || !(player.getCurrentEquippedItem().getItem() instanceof IStructureBlockItem); + + // GUIs can only be opened on integrated structure blocks. + if (tile instanceof ITileStructure) + if (!((ITileStructure) tile).isIntegratedIntoStructure()) + return false; + + if (tile.allowsInteraction(player)) + tile.openGui(player); + else + player.addChatMessage(new ChatComponentTranslation("\u00A7c%s %s", new ChatComponentText(tile.getOwnerName()), new ChatComponentTranslation("chat.accesslocked"))); + return true; + } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbor) { + + if (!Proxies.common.isSimulating(world)) + return; + + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof ITileStructure)) + return; + + ((ITileStructure) tile).validateStructure(); + } +} diff --git a/forestry_common/core/forestry/core/gadgets/Engine.java b/forestry_common/core/forestry/core/gadgets/Engine.java new file mode 100755 index 000000000..b6f861351 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/Engine.java @@ -0,0 +1,432 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; + +import buildcraft.api.core.Position; +import buildcraft.api.power.IPowerEmitter; +import buildcraft.api.power.IPowerReceptor; +import buildcraft.api.power.PowerHandler; +import buildcraft.api.power.PowerHandler.PowerReceiver; +import buildcraft.api.transport.IPipeConnection; +import buildcraft.api.transport.IPipeTile.PipeType; + +import forestry.core.TemperatureState; +import forestry.core.config.Defaults; +import forestry.core.interfaces.IPowerHandler; +import forestry.core.network.PacketPayload; +import forestry.core.proxy.Proxies; +import forestry.core.utils.BlockUtil; +import forestry.core.utils.ForestryTank; +import forestry.plugins.PluginBuildCraft; + +public abstract class Engine extends TileBase implements IPowerHandler, IPipeConnection, IPowerEmitter { + + @Override + public PacketPayload getPacketPayload() { + PacketPayload payload = new PacketPayload(3, 1, 0); + + if (this.isActive) + payload.intPayload[0] = 1; + else + payload.intPayload[0] = 0; + payload.intPayload[1] = (int) storedEnergy; + payload.intPayload[2] = heat; + + payload.floatPayload[0] = pistonSpeedServer; + + return payload; + } + + @Override + public void fromPacketPayload(PacketPayload payload) { + + if (payload.intPayload[0] > 0) + isActive = true; + else + isActive = false; + storedEnergy = payload.intPayload[1]; + heat = payload.intPayload[2]; + + pistonSpeedServer = payload.floatPayload[0]; + } + public boolean isActive = false; // Used for smp. + /** + * Indicates whether the piston is receding from or approaching the + * combustion chamber + */ + public int stagePiston = 0; + /** + * Piston speed as supplied by the server + */ + public float pistonSpeedServer = 0; + protected int currentOutput = 0; + public final int maxEnergy; + public final int maxEnergyExtracted; + public float storedEnergy; + public int heat; + protected final int maxHeat; + protected boolean forceCooldown = false; + public float progress; + private final PowerHandler powerProvider; + + public Engine(int maxHeat, int maxEnergy, int maxEnergyExtracted) { + this.maxHeat = maxHeat; + this.maxEnergy = maxEnergy; + this.maxEnergyExtracted = maxEnergyExtracted; + powerProvider = new PowerHandler(this, PowerHandler.Type.ENGINE); + powerProvider.configure(10, 200, 10, 100000); + } + + protected ItemStack replenishByContainer(ItemStack inventoryStack, FluidContainerData container, ForestryTank tank) { + if (container == null) + return inventoryStack; + + if (tank.fill(container.fluid, false) >= container.fluid.amount) { + tank.fill(container.fluid, true); + if (container.filledContainer != null && container.filledContainer.getItem().hasContainerItem(container.filledContainer)) + inventoryStack = container.emptyContainer.copy(); + else + inventoryStack.stackSize--; + } + + return inventoryStack; + } + + @Override + public void rotateAfterPlacement(World world, int x, int y, int z, EntityLivingBase entityliving, ItemStack itemstack) { + rotateEngine(); + } + + /** + * Adds energy + * + * @param addition + */ + public void addEnergy(float addition) { + storedEnergy += addition; + + if (storedEnergy > maxEnergy) + storedEnergy = maxEnergy; + } + + /** + * + * @param min Minimum energy to extract. Will return 0 if storedEnergy less + * than min. + * @param max Maximum energy to extract. + * @param doExtract Determines whether energy will actually be removed from + * the engine. + * + * @return + */ + public double extractEnergy(double min, double max, boolean doExtract) { + if (storedEnergy < min) + return 0; + + double ceiling = max > maxEnergyExtracted ? maxEnergyExtracted : max; + + double extracted; + + if (storedEnergy >= ceiling) { + extracted = ceiling; + if (doExtract) + storedEnergy -= ceiling; + } else { + extracted = storedEnergy; + if (doExtract) + storedEnergy = 0; + } + + return extracted; + } + + /** + * Adds heat + * + * @param i + */ + protected void addHeat(int i) { + heat += i; + + if (heat > maxHeat) + heat = maxHeat; + } + + public abstract int dissipateHeat(); + + public abstract int generateHeat(); + + public int maxEnergyReceived() { + return 200; + } + + public boolean mayBurn() { + return !forceCooldown; + } + + public abstract void burn(); + + @Override + public void updateClientSide() { + if (stagePiston != 0) { + progress += pistonSpeedServer; + + if (progress > 1) { + stagePiston = 0; + progress = 0; + } + } else if (this.isActive) + stagePiston = 1; + return; + } + + @Override + public void updateServerSide() { + TemperatureState energyState = getTemperatureState(); + if (energyState == TemperatureState.MELTING && heat > 0) + forceCooldown = true; + else if (forceCooldown && heat <= 0) + forceCooldown = false; + + // Determine targeted tile + Position posTarget = new Position(xCoord, yCoord, zCoord, this.getOrientation()); + posTarget.moveForwards(1.0); + TileEntity tile = worldObj.getTileEntity((int) posTarget.x, (int) posTarget.y, (int) posTarget.z); + + float newPistonSpeed = getPistonSpeed(); + if (newPistonSpeed != pistonSpeedServer) { + pistonSpeedServer = newPistonSpeed; + sendNetworkUpdate(); + } + + if (stagePiston != 0) { + + progress += pistonSpeedServer; + + if (progress > 0.5 && stagePiston == 1) { + stagePiston = 2; + + if (BlockUtil.isPoweredTile(getOrientation().getOpposite(), tile)) { + IPowerReceptor receptor = (IPowerReceptor) tile; + double extractedEnergy = extractEnergy(receptor.getPowerReceiver(getOrientation().getOpposite()).getMinEnergyReceived(), receptor.getPowerReceiver(getOrientation().getOpposite()).getMaxEnergyReceived(), + true); + if (extractedEnergy > 0) + PluginBuildCraft.instance.invokeReceiveEnergyMethod(PowerHandler.Type.ENGINE, receptor.getPowerReceiver(getOrientation().getOpposite()), extractedEnergy, getOrientation().getOpposite()); + // receptor.getPowerProvider().receiveEnergy(extractedEnergy); + } + + } else if (progress >= 1) { + progress = 0; + stagePiston = 0; + } + + } else if (canPowerTo(tile)) { // If we are not already running, check if + IPowerReceptor receptor = (IPowerReceptor) tile; + if (extractEnergy(receptor.getPowerReceiver(getOrientation().getOpposite()).getMinEnergyReceived(), receptor.getPowerReceiver(getOrientation().getOpposite()).getMaxEnergyReceived(), false) > 0) { + stagePiston = 1; // If we can transfer energy, start running + setActive(true); + } else + setActive(false); + } else + setActive(false); + + dissipateHeat(); + generateHeat(); + // Now let's fire up the engine: + if (mayBurn()) + burn(); + else + extractEnergy(0, 2, true); + + } + + private boolean canPowerTo(TileEntity tile) { + return isActivated() && BlockUtil.isPoweredTile(getOrientation().getOpposite(), tile); + } + + private void setActive(boolean isActive) { + if (this.isActive == isActive) + return; + + this.isActive = isActive; + sendNetworkUpdate(); + } + + /* INTERACTION */ + public void rotateEngine() { + + for (int i = getOrientation().ordinal() + 1; i <= getOrientation().ordinal() + 6; ++i) { + ForgeDirection orient = ForgeDirection.values()[i % 6]; + + Position pos = new Position(xCoord, yCoord, zCoord, orient); + pos.moveForwards(1.0F); + + TileEntity tile = worldObj.getTileEntity((int) pos.x, (int) pos.y, (int) pos.z); + + if (BlockUtil.isPoweredTile(getOrientation().getOpposite(), tile)) { + setOrientation(orient); + worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord)); + worldObj.func_147479_m(xCoord, yCoord, zCoord); + break; + } + } + } + + // STATE INFORMATION + protected double getHeatLevel() { + return (double) heat / (double) maxHeat; + } + + public abstract boolean isBurning(); + + public int getBurnTimeRemainingScaled(int i) { + return 0; + } + + public boolean hasFuelMin(float percentage) { + return false; + } + + public int getCurrentOutput() { + if (isBurning() && isActivated()) + return currentOutput; + else + return 0; + } + + public float getEnergyStored() { + return storedEnergy; + } + + public int getHeat() { + return heat; + } + + /** + * Returns the current energy state of the engine + * + * @return + */ + public TemperatureState getTemperatureState() { + // double scaledStorage = (double)storedEnergy / (double)maxEnergy; + double scaledHeat = (double) heat / (double) maxHeat; + + if (scaledHeat < 0.20) + return TemperatureState.COOL; + else if (scaledHeat < 0.45) + return TemperatureState.WARMED_UP; + else if (scaledHeat < 0.65) + return TemperatureState.OPERATING_TEMPERATURE; + else if (scaledHeat < 0.85) + return TemperatureState.RUNNING_HOT; + else if (scaledHeat < 1.0) + return TemperatureState.OVERHEATING; + else + return TemperatureState.MELTING; + } + + /** + * Piston speed + * + * @return + */ + public float getPistonSpeed() { + switch (getTemperatureState()) { + case COOL: + return 0.03f; + case WARMED_UP: + return 0.04f; + case OPERATING_TEMPERATURE: + return 0.05f; + case RUNNING_HOT: + return 0.06f; + case OVERHEATING: + return 0.07f; + case MELTING: + return Defaults.ENGINE_PISTON_SPEED_MAX; + default: + return 0; + } + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + + heat = nbt.getInteger("EngineHeat"); + if (nbt.hasKey("EngineStoredEnergy")) + storedEnergy = nbt.getInteger("EngineStoredEnergy"); + else + storedEnergy = nbt.getFloat("EngineStored"); + + progress = nbt.getFloat("EngineProgress"); + forceCooldown = nbt.getBoolean("ForceCooldown"); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + + nbt.setInteger("EngineHeat", heat); + nbt.setFloat("EngineStored", storedEnergy); + nbt.setFloat("EngineProgress", progress); + nbt.setBoolean("ForceCooldown", forceCooldown); + } + + /* SMP GUI */ + public abstract void getGUINetworkData(int i, int j); + + public abstract void sendGUINetworkData(Container containerEngine, ICrafting iCrafting); + + /* IPOWERRECEPTOR */ + @Override + public PowerReceiver getPowerReceiver(ForgeDirection side) { + return powerProvider.getPowerReceiver(); + } + + @Override + public PowerHandler getPowerHandler() { + return powerProvider; + } + + @Override + public void doWork(PowerHandler workProvider) { + if (!Proxies.common.isSimulating(worldObj)) + return; + + addEnergy((int) (PluginBuildCraft.instance.invokeUseEnergyMethod(workProvider, 1, maxEnergyReceived(), true) * 0.95F)); + } + + /* IPIPECONNECTION */ + @Override + public ConnectOverride overridePipeConnection(PipeType type, ForgeDirection with) { + if (type == PipeType.POWER) + return ConnectOverride.DEFAULT; + if (with == getOrientation()) + return ConnectOverride.DISCONNECT; + return ConnectOverride.DEFAULT; + } + + /* IPOWEREMITTER */ + @Override + public boolean canEmitPowerFrom(ForgeDirection side) { + return side == getOrientation(); + } +} diff --git a/forestry_common/core/forestry/core/gadgets/IStructureBlockItem.java b/forestry_common/core/forestry/core/gadgets/IStructureBlockItem.java new file mode 100755 index 000000000..391ca34c2 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/IStructureBlockItem.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +/** + * + * @author CovertJaguar + */ +public interface IStructureBlockItem { + +} diff --git a/forestry_common/core/forestry/core/gadgets/MachineDefinition.java b/forestry_common/core/forestry/core/gadgets/MachineDefinition.java new file mode 100755 index 000000000..bab2d3ba6 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/MachineDefinition.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; + +/** + * This will replace the whole {@link Gadget}-nonsense at some point, using the proper Forge hook. Will hopefully sort out any issues with interfaces. + */ +public class MachineDefinition { + + public final Class teClass; + + public final String teIdent; + public Block block; + public final int meta; + + public final IBlockRenderer renderer; + + /* CRAFTING */ + public IRecipe[] recipes; + + public MachineDefinition(int meta, String teIdent, Class teClass, IRecipe... recipes) { + this(meta, teIdent, teClass, null, recipes); + } + + public MachineDefinition(int meta, String teIdent, Class teClass, IBlockRenderer renderer, IRecipe... recipes) { + this.meta = meta; + this.teIdent = teIdent; + this.teClass = teClass; + this.renderer = renderer; + + this.recipes = recipes; + + this.faceMap = new int[8]; + for (int i = 0; i < 8; i++) + faceMap[i] = 0; + + } + + public void setBlock(Block block) { + this.block = block; + } + + public void register() { + registerTileEntity(); + registerCrafting(); + if (renderer != null) + Proxies.render.registerTESR(this); + } + + @SuppressWarnings("unchecked") + private void registerCrafting() { + for (IRecipe recipe : recipes) + if(recipe != null) + CraftingManager.getInstance().getRecipeList().add(recipe); + } + + /** + * Registers the tile entity with MC. + */ + private void registerTileEntity() { + GameRegistry.registerTileEntity(teClass, teIdent); + } + + public TileEntity createMachine() { + try { + return teClass.getConstructor().newInstance(); + } catch (Exception ex) { + throw new RuntimeException("Failed to instantiate tile entity of class " + teClass.getName()); + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void getSubBlocks(Item item, CreativeTabs tab, List list) { + list.add(new ItemStack(item, 1, meta)); + } + + /* BLOCK DROPS */ + public boolean handlesDrops() { + return false; + } + + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + return new ArrayList(); + } + + /* INTERACTION */ + public boolean isSolidOnSide(IBlockAccess world, int x, int y, int z, int side) { + return true; + } + + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float fXplayerClick, float fY, float fZ) { + return false; + } + + public void onBlockAdded(World world, int x, int y, int z) { + } + + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + return true; + } + + public boolean canConnectRedstone(IBlockAccess world, int x, int y, int z, int side) { + return false; + } + + public boolean rotateBlock(World world, int x, int y, int z, ForgeDirection axis) { + return false; + } + + /* TEXTURES */ + private final int[] faceMap; + + public MachineDefinition setFaces(int... faces) { + + if (faces.length > 6) + for (int i = 0; i < faces.length; i++) + faceMap[i] = faces[i]; + else { + for (int i = 0; i < 6; i++) + faceMap[i] = faces[i]; + faceMap[6] = faces[0]; + faceMap[7] = faces[1]; + } + + return this; + } + + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + icons = new IIcon[8]; + + for (int i = 0; i < 8; i++) + icons[i] = TextureManager.getInstance().registerTex(register, teIdent.replace("forestry.", "").toLowerCase(Locale.ENGLISH) + "." + faceMap[i]); + } + + @SideOnly(Side.CLIENT) + public IIcon getBlockTextureFromSideAndMetadata(int side, int metadata) { + return icons[side]; + } + + /** + * 0 - Bottom 1 - Top 2 - Back 3 - Front 4,5 - Sides, 7 - Reversed ?, 8 - Reversed ? + */ + @SideOnly(Side.CLIENT) + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side, int metadata) { + + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TileForestry)) + return getBlockTextureFromSideAndMetadata(side, metadata); + + ForgeDirection dir = ((TileForestry) tile).getOrientation(); + switch (dir) { + case WEST: + side = side == 2 ? 4 : side == 3 ? 5 : side == 4 ? 3 : side == 5 ? 2 : side == 0 ? 6 : 7; + break; + case EAST: + side = side == 2 ? 5 : side == 3 ? 4 : side == 4 ? 2 : side == 5 ? 3 : side == 0 ? 6 : 7; + break; + case SOUTH: + break; + case NORTH: + side = side == 2 ? 3 : side == 3 ? 2 : side == 4 ? 5 : side == 5 ? 4 : side; + break; + default: + } + + return getBlockTextureFromSideAndMetadata(side, metadata); + } +} diff --git a/forestry_common/core/forestry/core/gadgets/MachineNBTDefinition.java b/forestry_common/core/forestry/core/gadgets/MachineNBTDefinition.java new file mode 100755 index 000000000..998cad07f --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/MachineNBTDefinition.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class MachineNBTDefinition extends MachineDefinition { + + public MachineNBTDefinition(int meta, String teIdent, Class teClass, IRecipe... recipes) { + super(meta, teIdent, teClass, recipes); + } + + public MachineNBTDefinition(int meta, String teIdent, Class teClass, IBlockRenderer renderer, IRecipe... recipes) { + super(meta, teIdent, teClass, renderer, recipes); + } + + /* BLOCK DROPS */ + @Override + public boolean handlesDrops() { + return true; + } + + /* INTERACTION */ + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + int meta = world.getBlockMetadata(x, y, z); + if (Proxies.common.isSimulating(world) && block.canHarvestBlock(player, meta)) { + TileForestry tile = (TileForestry)world.getTileEntity(x, y, z); + Utils.dropInventory(tile, world, x, y, z); + + ItemStack stack = new ItemStack(block, 1, meta); + NBTTagCompound compound = new NBTTagCompound(); + tile.writeToNBT(compound); + stack.setTagCompound(compound); + StackUtils.dropItemStackAsEntity(stack, world, x, y, z); + } + + return world.setBlockToAir(x, y, z); + } + +} diff --git a/forestry_common/core/forestry/core/gadgets/Mill.java b/forestry_common/core/forestry/core/gadgets/Mill.java new file mode 100755 index 000000000..162960a34 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/Mill.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import forestry.core.network.EntityNetData; + +public abstract class Mill extends TilePowered { + + @EntityNetData + public int charge = 0; + @EntityNetData + public float speed; + @EntityNetData + public int stage = 0; + public float progress; + + public Mill() { + speed = 0.01F; + } + + @Override + public void updateClientSide() { + update(false); + } + + @Override + public void updateServerSide() { + update(true); + } + + private void update(boolean isSimulating) { + + // Stop gracefully if discharged. + if (charge <= 0) { + if (stage > 0) + progress += speed; + if (progress > 0.5) + stage = 2; + if (progress > 1) { + progress = 0; + stage = 0; + } + return; + } + + // Update blades + progress += speed; + if (stage <= 0) + stage = 1; + + if (progress > 0.5 && stage == 1) { + stage = 2; + if (charge < 7 && isSimulating) { + charge++; + sendNetworkUpdate(); + } + } + if (progress > 1) { + progress = 0; + stage = 0; + + // Fully charged! Do something! + if (charge >= 7) + activate(); + } + + } + + protected abstract void activate(); + + @Override + public boolean isWorking() { + return charge != 0; + } + +} diff --git a/forestry_common/core/forestry/core/gadgets/NaturalistGame.java b/forestry_common/core/forestry/core/gadgets/NaturalistGame.java new file mode 100755 index 000000000..7cfe97562 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/NaturalistGame.java @@ -0,0 +1,411 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Random; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import forestry.api.core.INBTTagable; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Utils; + +public class NaturalistGame implements INBTTagable { + + public static final int BOUNTY_MAX = 16; + + public static class GameToken implements INBTTagable { + + private static final String[] OVERLAY_NONE = new String[0]; + private static final String[] OVERLAY_FAILED = new String[] { "errors/errored" }; + + public ItemStack tokenStack; + + protected boolean isFailed = false; + protected boolean isProbed = false; + protected boolean isRevealed = false; + + public GameToken(ItemStack tokenStack) { + this.tokenStack = tokenStack; + } + + public GameToken(NBTTagCompound nbttagcompound) { + readFromNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + isFailed = nbttagcompound.getBoolean("isFailed"); + isProbed = nbttagcompound.getBoolean("isProbed"); + isRevealed = nbttagcompound.getBoolean("isRevealed"); + + if(nbttagcompound.hasKey("tokenStack")) { + tokenStack = ItemStack.loadItemStackFromNBT(nbttagcompound.getCompoundTag("tokenStack")); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + nbttagcompound.setBoolean("isFailed", isFailed); + nbttagcompound.setBoolean("isProbed", isProbed); + nbttagcompound.setBoolean("isRevealed", isRevealed); + + if(tokenStack != null) { + NBTTagCompound stackcompound = new NBTTagCompound(); + tokenStack.writeToNBT(stackcompound); + nbttagcompound.setTag("tokenStack", stackcompound); + } + } + + public boolean isVisible() { + return isRevealed; + } + + public int getTokenColour() { + if(tokenStack == null || !isVisible()) + return 0xffffff; + + if(isProbed) + return Utils.multiplyRGBComponents(AlleleManager.alleleRegistry.getIndividual(tokenStack).getGenome().getPrimary().getIconColour(0), 0.7f); + else + return AlleleManager.alleleRegistry.getIndividual(tokenStack).getGenome().getPrimary().getIconColour(0); + } + + public String getTooltip() { + return tokenStack != null ? tokenStack.getDisplayName() : StringUtil.localize("gui.unknown"); + } + + public String[] getOverlayIcons() { + return isFailed ? OVERLAY_FAILED : OVERLAY_NONE; + } + + public boolean matches(GameToken other) { + return tokenStack.isItemEqual(other.tokenStack) && ItemStack.areItemStackTagsEqual(tokenStack, other.tokenStack); + } + } + + private final Random rand = new Random(); + private GameToken[] gameTokens; + private long lastUpdate; + + private boolean isEnded; + private int bountyLevel; + + public long getLastUpdate() { + return lastUpdate; + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + nbttagcompound.setBoolean("isEnded", isEnded); + nbttagcompound.setInteger("bountyLevel", bountyLevel); + nbttagcompound.setLong("lastUpdate", lastUpdate); + + if(gameTokens != null) { + nbttagcompound.setInteger("TokenCount", gameTokens.length); + NBTTagList nbttaglist = new NBTTagList(); + + for (int i = 0; i < gameTokens.length; i++) { + if(gameTokens[i] == null) + continue; + + NBTTagCompound nbttagcompound2 = new NBTTagCompound(); + nbttagcompound2.setByte("Slot", (byte) i); + gameTokens[i].writeToNBT(nbttagcompound2); + nbttaglist.appendTag(nbttagcompound2); + } + + nbttagcompound.setTag("GameTokens", nbttaglist); + } else + nbttagcompound.setInteger("TokenCount", 0); + + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + isEnded = nbttagcompound.getBoolean("isEnded"); + bountyLevel = nbttagcompound.getInteger("bountyLevel"); + lastUpdate = nbttagcompound.getLong("lastUpdate"); + + int tokenCount = nbttagcompound.getInteger("TokenCount"); + if(tokenCount > 0) { + gameTokens = new GameToken[tokenCount]; + NBTTagList nbttaglist = nbttagcompound.getTagList("GameTokens", 10); + + for (int j = 0; j < nbttaglist.tagCount(); ++j) { + NBTTagCompound nbttagcompound2 = nbttaglist.getCompoundTagAt(j); + int index = nbttagcompound2.getByte("Slot"); + gameTokens[index] = new GameToken(nbttagcompound2); + } + } + + lastUpdate = System.currentTimeMillis(); + } + + /* INTERACTION */ + public void initialize(ItemStack specimen) { + IIndividual individual = AlleleManager.alleleRegistry.getIndividual(specimen); + if(individual == null) { + return; + } + + int boardSize = individual.getGenome().getPrimary().getComplexity() + individual.getGenome().getSecondary().getComplexity(); + if(boardSize % 2 != 0) + boardSize = Math.round((float)boardSize / 2) * 2; + boardSize = boardSize <= 22 ? boardSize >= 6 ? boardSize : 6 : 22; + + isEnded = false; + bountyLevel = BOUNTY_MAX; + gameTokens = new GameToken[boardSize]; + + ISpeciesRoot root = individual.getGenome().getPrimary().getRoot(); + ArrayList pairs = new ArrayList(); + for(int i = 0; i < boardSize / 2; i++) { + IIndividual token = root.templateAsIndividual(root.getRandomTemplate(rand)); + pairs.add(root.getMemberStack(token, 0)); + } + + boolean first = true; + for(ItemStack pair : pairs) { + if(first) { + gameTokens[0] = new GameToken(pair.copy()); + first = false; + } else + gameTokens[getFreeTokenIndex()] = new GameToken(pair.copy()); + gameTokens[getFreeTokenIndex()] = new GameToken(pair.copy()); + } + + lastUpdate = System.currentTimeMillis(); + } + + private int getFreeTokenIndex() { + while(true) { + int probe = rand.nextInt(gameTokens.length); + if(gameTokens[probe] == null) + return probe; + } + } + + private int countUnrevealedTokens() { + int count = 0; + for(GameToken token : gameTokens) + if(!token.isRevealed) + count++; + + return count; + } + + private int[] getUnrevealedTokens(int count) { + ArrayList existing = new ArrayList(); + int remaining = countUnrevealedTokens(); + int[] unrevealed = new int[count < remaining ? count : remaining]; + + for(int i = 0; i < unrevealed.length; i++) { + + int found = -1; + while(found < 0) { + int probe = rand.nextInt(gameTokens.length); + if(gameTokens[probe].isRevealed) + continue; + + boolean taken = false; + for(int exist : existing) { + if(exist == probe) { + taken = true; + break; + } + } + if(!taken) { + existing.add(probe); + found = probe; + } + } + unrevealed[i] = found; + } + + return unrevealed; + } + + public void probe(ItemStack specimen, IInventory inventory, int startSlot, int slotCount) { + if(gameTokens == null) + return; + if(isEnded) + return; + IIndividual individual = AlleleManager.alleleRegistry.getIndividual(specimen); + if(individual == null) + return; + + hideProbedTokens(); + if(bountyLevel > 1) + bountyLevel--; + + int[] tokenIndices = getUnrevealedTokens(getSampleSize() <= slotCount ? getSampleSize() : slotCount); + int processedTokens = 0; + + for(int i = 0; i < slotCount; i++) { + ItemStack sample = inventory.getStackInSlot(startSlot + i); + if(sample == null || sample.stackSize <= 0) + continue; + + sample = inventory.decrStackSize(startSlot + i, 1); + if(rand.nextFloat() >= individual.getGenome().getPrimary().getResearchSuitability(sample)) { + continue; + } + + gameTokens[tokenIndices[processedTokens]].isProbed = true; + gameTokens[tokenIndices[processedTokens]].isRevealed = true; + + processedTokens++; + if(processedTokens >= tokenIndices.length) + break; + } + + lastUpdate = System.currentTimeMillis(); + } + + public void choose(int tokenIndex) { + if(isEnded) + return; + if(gameTokens == null || tokenIndex >= gameTokens.length) + return; + if(gameTokens[tokenIndex].isRevealed && !gameTokens[tokenIndex].isProbed) + return; + hideProbedTokens(); + + Collection singles = getRevealedSingles(gameTokens[tokenIndex]); + if(singles.size() > 0) { + boolean matched = false; + for(GameToken single : singles) { + if(single.matches(gameTokens[tokenIndex])) { + matched = true; + break; + } + } + if(!matched) { + gameTokens[tokenIndex].isFailed = true; + } + } + gameTokens[tokenIndex].isRevealed = true; + checkGameEnd(); + lastUpdate = System.currentTimeMillis(); + } + + public void reset() { + gameTokens = null; + lastUpdate = System.currentTimeMillis(); + } + + public boolean isInited() { + return gameTokens != null; + } + + public boolean isEnded() { + return isEnded; + } + + public int getBountyLevel() { + return bountyLevel; + } + + public boolean isWon() { + if(!isEnded) + return false; + + return !isLost(); + } + + private void checkGameEnd() { + if(isLost()) + isEnded = true; + if(isRevealed()) + isEnded = true; + } + + private boolean isRevealed() { + for(GameToken token : gameTokens) + if(!token.isRevealed) + return false; + + return true; + } + private boolean isLost() { + for(GameToken token : gameTokens) { + if(token.isFailed) + return true; + } + + return false; + } + + private void hideProbedTokens() { + for(GameToken token : gameTokens) { + if(token.isProbed) { + token.isRevealed = false; + token.isProbed = false; + } + } + } + + private Collection getRevealedSingles(GameToken exclude) { + ArrayList singles = new ArrayList(); + + for(GameToken token : gameTokens) { + if(!token.isRevealed) + continue; + if(token == exclude) + continue; + + GameToken matching = null; + for(GameToken single : singles) { + if(!single.matches(token)) + continue; + matching = single; + break; + } + + if(matching == null) + singles.add(token); + else + singles.remove(matching); + } + + return singles; + } + + /* RETRIEVAL */ + public int getBoardSize() { + return gameTokens != null ? gameTokens.length : 0; + } + + public int getSampleSize() { + if(gameTokens == null) + return 0; + + int samples = gameTokens.length / 4; + return samples >= 2 ? samples : 2; + } + + public GameToken getToken(int index) { + return gameTokens != null ? index < gameTokens.length ? gameTokens[index] : null : null; + } + + public void setToken(int index, NBTTagCompound nbttagcompound) { + if(gameTokens == null) + gameTokens = new GameToken[24]; + gameTokens[index] = new GameToken(nbttagcompound); + } +} diff --git a/forestry_common/core/forestry/core/gadgets/StructureLogic.java b/forestry_common/core/forestry/core/gadgets/StructureLogic.java new file mode 100755 index 000000000..fbbed1424 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/StructureLogic.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.HashMap; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; + +import forestry.api.core.IStructureLogic; +import forestry.api.core.ITileStructure; +import forestry.core.config.Defaults; +import forestry.core.gadgets.BlockStructure.EnumStructureState; +import forestry.core.utils.Schemata; +import forestry.core.utils.Schemata.EnumStructureBlock; +import forestry.core.utils.Vect; + +public abstract class StructureLogic implements IStructureLogic { + + protected ITileStructure structure; + protected TileEntity structureTile; + + protected String uid; + protected Schemata[] schematas; + protected short activeSchemata = -1; + protected boolean isRotated = false; + protected HashMap metaOnValid = new HashMap(); + + public StructureLogic(String uid, ITileStructure structure) { + this.uid = uid; + this.structure = structure; + this.structureTile = (TileEntity) structure; + } + + @Override + public String getTypeUID() { + return uid; + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + if (nbttagcompound.hasKey("SchemataOrdinal")) + activeSchemata = nbttagcompound.getShort("SchemataOrdinal"); + isRotated = nbttagcompound.getBoolean("Rotated"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + if (activeSchemata >= 0) + nbttagcompound.setShort("SchemataOrdinal", activeSchemata); + nbttagcompound.setBoolean("Rotated", isRotated); + } + + @Override + public void validateStructure() { + + ITileStructure master = structure.getCentralTE(); + if (!structure.isMaster() && master != null) { + master.validateStructure(); + return; + } + + EnumStructureState state = EnumStructureState.INDETERMINATE; + + boolean rotate = false; + for (int i = 0; i < schematas.length; i++) { + if (!schematas[i].isEnabled()) + continue; + + state = determineMasterState(schematas[i], false); + rotate = false; + if (state == EnumStructureState.INVALID && schematas[i].getWidth() != schematas[i].getDepth()) { + state = determineMasterState(schematas[i], true); + rotate = true; + } + + if (state == EnumStructureState.VALID) { + activeSchemata = (short) i; + isRotated = rotate; + break; + } + + } + + // Structure state is indeterminate, possibly caused by chunkloading. Remain calm, do nothing. + if (state == EnumStructureState.INDETERMINATE) + return; + + if (state == EnumStructureState.VALID) { + // Structure is valid and this block is master, set all other blocks + // System.out.println(String.format("Structure is valid at %s/%s/%s", ((TileEntity)structure).xCoord, ((TileEntity)structure).yCoord, + // ((TileEntity)structure).zCoord)); + if (!structure.isMaster()) { + structure.makeMaster(); + markStructureBlocks(schematas[activeSchemata]); + } + + /* + * int offsetX = schematas[activeSchemata].getxOffset(); int offsetZ = schematas[activeSchemata].getzOffset(); if(isRotated) { offsetX = + * schematas[activeSchemata].getzOffset(); offsetZ = schematas[activeSchemata].getxOffset(); + * + * } + */ + // System.out.println(String.format("Offsets: %s and %s.", offsetX, offsetZ)); + + } else if (structure.isMaster()) + // Structure is invalid, break it up. + resetStructureBlocks(schematas[activeSchemata]); + } + + protected void resetStructureBlocks(Schemata schemata) { + + Vect dimensions = schemata.getDimensions(isRotated); + int offsetX = schemata.getxOffset(); + int offsetZ = schemata.getzOffset(); + if (isRotated) { + offsetX = schemata.getzOffset(); + offsetZ = schemata.getxOffset(); + } + + for (int i = 0; i < dimensions.x; i++) + for (int j = 0; j < schemata.getHeight(); j++) + for (int k = 0; k < dimensions.z; k++) { + int x = structureTile.xCoord + i + offsetX; + int y = structureTile.yCoord + j + schemata.getyOffset(); + int z = structureTile.zCoord + k + offsetZ; + + TileEntity tile = structureTile.getWorldObj().getTileEntity(x, y, z); + if (!(tile instanceof ITileStructure)) + continue; + + ITileStructure part = (ITileStructure) tile; + if (!part.getTypeUID().equals(getTypeUID())) + continue; + + part.onStructureReset(); + } + } + + protected void markStructureBlocks(Schemata schemata) { + + Vect dimensions = schemata.getDimensions(isRotated); + int offsetX = schemata.getxOffset(); + int offsetZ = schemata.getzOffset(); + if (isRotated) { + offsetX = schemata.getzOffset(); + offsetZ = schemata.getxOffset(); + } + + for (int i = 0; i < dimensions.x; i++) + for (int j = 0; j < schemata.getHeight(); j++) + for (int k = 0; k < dimensions.z; k++) { + int x = structureTile.xCoord + i + offsetX; + int y = structureTile.yCoord + j + schemata.getyOffset(); + int z = structureTile.zCoord + k + offsetZ; + + TileEntity tile = structureTile.getWorldObj().getTileEntity(x, y, z); + if (!(tile instanceof ITileStructure)) + continue; + + ITileStructure part = (ITileStructure) tile; + if (!part.getTypeUID().equals(getTypeUID())) + continue; + + part.setCentralTE((TileEntity) structure); + EnumStructureBlock type = schemata.getAt(i, j, k, isRotated); + if (metaOnValid.containsKey(type)) { + structureTile.getWorldObj().setBlockMetadataWithNotify(x, y, z, metaOnValid.get(type), Defaults.FLAG_BLOCK_SYNCH); + structureTile.getWorldObj().markBlockForUpdate(x, y, z); + } + } + } + + protected abstract EnumStructureState determineMasterState(Schemata schemata, boolean rotate); + +} diff --git a/forestry_common/core/forestry/core/gadgets/TileAnalyzer.java b/forestry_common/core/forestry/core/gadgets/TileAnalyzer.java new file mode 100755 index 000000000..f8aedcea1 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileAnalyzer.java @@ -0,0 +1,453 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.Stack; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.network.Packet; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import forestry.core.EnumErrorCode; +import forestry.core.config.Defaults; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketInventoryStack; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.StringUtil; + +public class TileAnalyzer extends TileBase implements ISpecialInventory, ISidedInventory, ILiquidTankContainer { + + /* CONSTANTS */ + public static final int TIME_TO_ANALYZE = 500; + public static final int HONEY_REQUIRED = 100; + + public static final short SLOT_ANALYZE = 0; + public static final short SLOT_CAN = 1; + public static final short SLOT_INPUT_1 = 2; + public static final short SLOT_OUTPUT_1 = 8; + + /* MEMBER */ + private final InventoryAdapter inventory = new InventoryAdapter(12, "Items"); + + private int analyzeTime; + + private final short analyzeSlot = 0; + private final short canSlot = 1; + private final short inputSlot1 = 2; + private final short outputSlot1 = 8; + + public FluidStack resource = FluidRegistry.getFluidStack(Defaults.LIQUID_HONEY, HONEY_REQUIRED); + @EntityNetData + public ForestryTank resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + private final Stack pendingProducts = new Stack(); + + /* CONSTRUCTOR */ + public TileAnalyzer() { + } + + @Override + public String getInventoryName() { + return StringUtil.localize("core.0"); + } + + /* GUI */ + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.AnalyzerGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("AnalyzeTime", analyzeTime); + + // / Resource tank + resourceTank.writeToNBT(nbttagcompound); + + // / Pending Products + NBTTagList nbttaglist = new NBTTagList(); + ItemStack[] pending = pendingProducts.toArray(new ItemStack[pendingProducts.size()]); + for (int i = 0; i < pending.length; i++) + if (pending[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + pending[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("PendingProducts", nbttaglist); + + // / Inventory + inventory.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + analyzeTime = nbttagcompound.getInteger("AnalyzeTime"); + + // / Resource tank + resourceTank.readFromNBT(nbttagcompound); + + // / Pending Products + NBTTagList nbttaglist = nbttagcompound.getTagList("PendingProducts", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + pendingProducts.add(ItemStack.loadItemStackFromNBT(nbttagcompound1)); + } + + // / Inventory + inventory.readFromNBT(nbttagcompound); + } + + /* WORKING */ + @Override + public void updateServerSide() { + // If we add pending products, we skip to the next work cycle. + if (tryAddPending()) + return; + + if (!pendingProducts.isEmpty()) { + setErrorState(EnumErrorCode.NOSPACE); + return; + } + + // Check if we have suitable items waiting in the can slot + if (getStackInSlot(canSlot) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(getStackInSlot(canSlot)); + if (container != null && resource.isFluidEqual(container.fluid)) { + + setInventorySlotContents(canSlot, StackUtils.replenishByContainer(this, getStackInSlot(canSlot), container, resourceTank)); + if (getStackInSlot(canSlot).stackSize <= 0) + setInventorySlotContents(canSlot, null); + } + } + + if (analyzeTime > 0 && getStackInSlot(analyzeSlot) != null && AlleleManager.alleleRegistry.isIndividual(getStackInSlot(analyzeSlot))) { + + analyzeTime--; + + // Still not done + if (analyzeTime > 0) { + setErrorState(EnumErrorCode.OK); + return; + } + + // Analyzation is done. + IIndividual individual = AlleleManager.alleleRegistry.getIndividual(getStackInSlot(analyzeSlot)); + // No bee, abort + if (individual == null) + return; + + individual.analyze(); + NBTTagCompound nbttagcompound = new NBTTagCompound(); + individual.writeToNBT(nbttagcompound); + getStackInSlot(analyzeSlot).setTagCompound(nbttagcompound); + + pendingProducts.push(getStackInSlot(analyzeSlot)); + setInventorySlotContents(analyzeSlot, null); + sendNetworkUpdate(); + + } else { + analyzeTime = 0; + + // Don't start if analyze slot already occupied + if (getStackInSlot(analyzeSlot) != null) + return; + + // We need our liquid honey + if (resourceTank.getFluidAmount() < resource.amount) { + setErrorState(EnumErrorCode.NORESOURCE); + return; + } + + // Look for bees in input slots. + for (int i = inputSlot1; i < outputSlot1; i++) { + if (getStackInSlot(i) == null || !AlleleManager.alleleRegistry.isIndividual(getStackInSlot(i))) + continue; + + // Analyzed bees in the input buffer are added to the output + // queue at once. + IIndividual individual = AlleleManager.alleleRegistry.getIndividual(getStackInSlot(i)); + if (individual.isAnalyzed()) { + pendingProducts.push(getStackInSlot(i)); + setInventorySlotContents(i, null); + continue; + } + + setInventorySlotContents(analyzeSlot, getStackInSlot(i)); + setInventorySlotContents(i, null); + resourceTank.drain(resource.amount, true); + analyzeTime = TIME_TO_ANALYZE; + sendNetworkUpdate(); + return; + } + + // Nothing to analyze + setErrorState(EnumErrorCode.NOTHINGANALYZE); + } + } + + private boolean tryAddPending() { + if (pendingProducts.isEmpty()) + return false; + + ItemStack next = pendingProducts.peek(); + if (inventory.tryAddStack(next, outputSlot1, inventory.getSizeInventory() - outputSlot1, true)) { + pendingProducts.pop(); + return true; + } + return false; + } + + /* STATE INFORMATION */ + // @Override + public boolean isWorking() { + return analyzeTime > 0; + } + + public int getProgressScaled(int i) { + return (analyzeTime * i) / TIME_TO_ANALYZE; + } + + public int getResourceScaled(int i) { + return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + public ItemStack getIndividualOnDisplay() { + return getStackInSlot(analyzeSlot); + } + + /* SMP */ + public void getGUINetworkData(int i, int j) { + switch (i) { + case 0: + analyzeTime = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, analyzeTime); + + } + + @Override + public void sendNetworkUpdate() { + Proxies.net.sendNetworkPacket(new PacketInventoryStack(PacketIds.IINVENTORY_STACK, xCoord, yCoord, zCoord, SLOT_ANALYZE, inventory.getStackInSlot(SLOT_ANALYZE)), + xCoord, yCoord, zCoord); + } + + @Override + public Packet getDescriptionPacket() { + return new PacketInventoryStack(PacketIds.IINVENTORY_STACK, xCoord, yCoord, zCoord, SLOT_ANALYZE, inventory.getStackInSlot(SLOT_ANALYZE)).getPacket(); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + return slotIndex >= SLOT_OUTPUT_1 && slotIndex < SLOT_OUTPUT_1 + 4; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex >= SLOT_INPUT_1 && slotIndex < SLOT_INPUT_1 + 6) + return AlleleManager.alleleRegistry.isIndividual(itemstack); + + if(slotIndex == SLOT_CAN) { + FluidContainerData container = LiquidHelper.getLiquidContainer(itemstack); + return container != null && LiquidHelper.isLiquid(Defaults.LIQUID_HONEY, container.fluid); + } + + return false; + } + + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISPECIALINVENTORY */ + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + + ItemStack product = null; + + for (int i = outputSlot1; i < inventory.getSizeInventory(); i++) { + if (inventory.getStackInSlot(i) == null) + continue; + + product = getStackInSlot(i).copy(); + if (doRemove) { + getStackInSlot(i).stackSize = 0; + setInventorySlotContents(i, null); + } + break; + } + return new ItemStack[] { product }; + } + + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + + if (!AlleleManager.alleleRegistry.isIndividual(stack)) { + + FluidContainerData container = LiquidHelper.getLiquidContainer(stack); + if (container == null || !container.fluid.isFluidEqual(resource)) + return 0; + + if (getStackInSlot(canSlot) == null) { + if (doAdd) + setInventorySlotContents(canSlot, stack.copy()); + + return stack.stackSize; + } + + int space = getStackInSlot(canSlot).getMaxStackSize() - getStackInSlot(canSlot).stackSize; + if (space <= 0) + return 0; + + if (doAdd) { + getStackInSlot(canSlot).stackSize += stack.stackSize; + if (getStackInSlot(canSlot).stackSize > getStackInSlot(canSlot).getMaxStackSize()) + getStackInSlot(canSlot).stackSize = getStackInSlot(canSlot).getMaxStackSize(); + } + + return space; + } + + for (int i = inputSlot1; i < outputSlot1; i++) + if (getStackInSlot(i) == null) { + if (doAdd) + setInventorySlotContents(i, stack.copy()); + + return stack.stackSize; + } + + return 0; + } + + /* ILIQUIDCONTAINER */ + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + + // We only accept what is already in the tank or valid ingredients + if (resourceTank.getFluidAmount() > 0 && !resourceTank.getFluid().isFluidEqual(resource)) + return 0; + else if (!LiquidHelper.isLiquid(Defaults.LIQUID_HONEY, resource)) + return 0; + + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + sendNetworkUpdate(); + + return used; + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank }; + } + + /* + @Override + public ILiquidTank getTank(ForgeDirection direction, LiquidStack type) { + return resourceTank; + } + */ + +} diff --git a/forestry_common/core/forestry/core/gadgets/TileBase.java b/forestry_common/core/forestry/core/gadgets/TileBase.java new file mode 100755 index 000000000..a4181ec18 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileBase.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.core.interfaces.IHintSource; +import forestry.core.network.ClassMap; +import forestry.core.network.IndexInPayload; +import forestry.core.network.PacketPayload; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Utils; + +public abstract class TileBase extends TileForestry implements IHintSource { + + @Override + public String getInventoryName() { + return null; + } + + @Override + public boolean isOwnable() { + return true; + } + + /* UPDATING */ + @Override + public void initialize() { + } + + @Override + public void updateEntity() { + + super.updateEntity(); + + if (!Proxies.common.isSimulating(worldObj)) + updateClientSide(); + else + updateServerSide(); + } + + protected void updateClientSide() { + } + + protected void updateServerSide() { + } + + /* NETWORK */ + @Override + public PacketPayload getPacketPayload() { + if (!ClassMap.classMappers.containsKey(this.getClass())) + ClassMap.classMappers.put(this.getClass(), new ClassMap(this.getClass())); + + ClassMap classmap = ClassMap.classMappers.get(this.getClass()); + PacketPayload payload = new PacketPayload(classmap.intSize, classmap.floatSize, classmap.stringSize); + + try { + classmap.setData(this, payload.intPayload, payload.floatPayload, payload.stringPayload, new IndexInPayload(0, 0, 0)); + } catch (Exception ex) { + ex.printStackTrace(); + } + + return payload; + } + + @Override + public void fromPacketPayload(PacketPayload payload) { + + if (payload.isEmpty()) + return; + + if (!ClassMap.classMappers.containsKey(this.getClass())) + ClassMap.classMappers.put(this.getClass(), new ClassMap(this.getClass())); + + ClassMap classmap = ClassMap.classMappers.get(this.getClass()); + + try { + classmap.fromData(this, payload.intPayload, payload.floatPayload, payload.stringPayload, new IndexInPayload(0, 0, 0)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /* INTERACTION */ + public void openGui(EntityPlayer player, TileBase tile) { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return Utils.isUseableByPlayer(player, this, worldObj, xCoord, yCoord, zCoord); + } + + public boolean canDrainWithBucket() { + return false; + } + + /* IHINTSOURCE */ + private String[] hints; + + public void setHints(String[] hints) { + this.hints = hints; + } + + @Override + public boolean hasHints() { + return hints != null && hints.length > 0; + } + + @Override + public String[] getHints() { + return hints; + } +} diff --git a/forestry_common/core/forestry/core/gadgets/TileEngine.java b/forestry_common/core/forestry/core/gadgets/TileEngine.java new file mode 100755 index 000000000..267651ca4 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileEngine.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +public class TileEngine extends TileMachine { +} diff --git a/forestry_common/core/forestry/core/gadgets/TileEscritoire.java b/forestry_common/core/forestry/core/gadgets/TileEscritoire.java new file mode 100755 index 000000000..ed0662cb5 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileEscritoire.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import forestry.core.interfaces.ICrafter; +import forestry.core.interfaces.IRenderableMachine; +import forestry.core.network.ForestryPacket; +import forestry.core.network.GuiId; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketTileNBT; +import forestry.core.network.PacketTileUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.StringUtil; +import forestry.core.utils.TileInventoryAdapter; +import forestry.core.utils.Utils; + +public class TileEscritoire extends TileBase implements ISidedInventory, IRenderableMachine, ICrafter { + + public static final short SLOT_ANALYZE = 0; + public static final short SLOT_RESULTS_1 = 1; + public static final short SLOTS_RESULTS_COUNT = 6; + public static final short SLOT_INPUT_1 = 7; + public static final short SLOTS_INPUT_COUNT = 5; + + /* MEMBER */ + private final NaturalistGame game = new NaturalistGame(); + private final InventoryAdapter inventory; + @Override + public String getInventoryName() { + return StringUtil.localize("core.1"); + } + + public TileEscritoire() { + inventory = new TileInventoryAdapter(this, 12, "Items"); + } + + /* GUI */ + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.NaturalistBenchGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + game.writeToNBT(nbttagcompound); + inventory.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + game.readFromNBT(nbttagcompound); + inventory.readFromNBT(nbttagcompound); + } + + /* GAME */ + public NaturalistGame getGame() { + return game; + } + + public void processTurnResult(String researcher) { + if(!game.isWon()) + return; + + IIndividual individual = AlleleManager.alleleRegistry.getIndividual(inventory.getStackInSlot(SLOT_ANALYZE)); + if(individual == null) + return; + + for(ItemStack itemstack : individual.getGenome().getPrimary().getResearchBounty(worldObj, researcher, individual, game.getBountyLevel())) + inventory.addStack(itemstack, SLOT_RESULTS_1, SLOTS_RESULTS_COUNT, false, true); + } + + private boolean areProbeSlotsFilled() { + int filledSlots = 0; + int required = game.getSampleSize() < SLOTS_INPUT_COUNT ? game.getSampleSize() : SLOTS_INPUT_COUNT; + for(int i = SLOT_INPUT_1; i < SLOT_INPUT_1 + required; i++) + if(inventory.getStackInSlot(i) != null) + filledSlots++; + + return filledSlots >= required; + } + + public void probe() { + if (!worldObj.isRemote && inventory.getStackInSlot(SLOT_ANALYZE) != null && areProbeSlotsFilled()) { + game.probe(inventory.getStackInSlot(SLOT_ANALYZE), this, SLOT_INPUT_1, SLOTS_INPUT_COUNT); + } + } + + /* NETWORK */ + @Override + public void fromPacket(ForestryPacket packetRaw) { + if(packetRaw instanceof PacketTileUpdate) { + super.fromPacket(packetRaw); + return; + } + + PacketTileNBT packet = (PacketTileNBT)packetRaw; + readFromNBT(packet.getTagCompound()); + } + + public void sendBoard(EntityPlayer player) { + Proxies.net.sendToPlayer(new PacketTileNBT(PacketIds.TILE_NBT, this), player); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + if(slotIndex >= SLOT_INPUT_1 && slotIndex < SLOT_INPUT_1 + SLOTS_INPUT_COUNT) + return slotIndex < SLOT_INPUT_1 + game.getSampleSize(); + + return true; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + return slotIndex >= SLOT_RESULTS_1 && slotIndex < SLOT_RESULTS_1 + SLOTS_RESULTS_COUNT; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + int samples = game.getSampleSize(); + return slotIndex >= SLOT_INPUT_1 && slotIndex < SLOT_INPUT_1 + (samples < SLOTS_INPUT_COUNT ? samples : SLOTS_INPUT_COUNT); + } + + @Override + public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { + inventory.setInventorySlotContents(slotIndex, itemstack); + if(slotIndex == SLOT_ANALYZE && Proxies.common.isSimulating(worldObj)) { + if(!AlleleManager.alleleRegistry.isIndividual(inventory.getStackInSlot(SLOT_ANALYZE)) + && inventory.getStackInSlot(SLOT_ANALYZE) != null) { + ItemStack ersatz = Utils.convertSaplingToGeneticEquivalent(inventory.getStackInSlot(SLOT_ANALYZE)); + if(ersatz != null) + inventory.setInventorySlotContents(SLOT_ANALYZE, ersatz); + } + game.initialize(inventory.getStackInSlot(SLOT_ANALYZE)); + } + } + + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + @Override + public EnumTankLevel getPrimaryLevel() { + return EnumTankLevel.EMPTY; + } + + @Override + public EnumTankLevel getSecondaryLevel() { + return EnumTankLevel.EMPTY; + } + + @Override + public ItemStack takenFromSlot(int slotIndex, boolean consumeRecipe, EntityPlayer player) { + if(slotIndex == SLOT_ANALYZE) + game.reset(); + return null; + } + + @Override + public ItemStack getResult() { + return null; + } + + @Override + public boolean canTakeStack(int slotIndex) { + return true; + } + + +} diff --git a/forestry_common/core/forestry/core/gadgets/TileForestry.java b/forestry_common/core/forestry/core/gadgets/TileForestry.java new file mode 100755 index 000000000..2df1d64f6 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileForestry.java @@ -0,0 +1,371 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.LinkedList; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.Packet; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; + +import buildcraft.api.gates.ITrigger; + +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.interfaces.IOwnable; +import forestry.core.interfaces.IPowerHandler; +import forestry.core.network.ForestryPacket; +import forestry.core.network.INetworkedEntity; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketTileUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.EnumAccess; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.Vect; + +public abstract class TileForestry extends TileEntity implements INetworkedEntity, IOwnable, IErrorSource { + + protected boolean isInited = false; + protected int energyConsumed; + protected int energyLast; + protected int energyReceived; + + public Vect Coords() { + return new Vect(xCoord, yCoord, zCoord); + } + + public World getWorld() { + return this.getWorldObj(); + } + + public void openGui(EntityPlayer player) { + } + + public void rotateAfterPlacement(World world, int x, int y, int z, EntityLivingBase entityliving, ItemStack stack) { + + int l = MathHelper.floor_double(((entityliving.rotationYaw * 4F) / 360F) + 0.5D) & 3; + if (l == 0) + setOrientation(ForgeDirection.NORTH); + if (l == 1) + setOrientation(ForgeDirection.EAST); + if (l == 2) + setOrientation(ForgeDirection.SOUTH); + if (l == 3) + setOrientation(ForgeDirection.WEST); + + } + + // / UPDATING + @Override + public void updateEntity() { + if (!isInited) { + initialize(); + isInited = true; + } + + if (!Proxies.common.isSimulating(worldObj)) + return; + + if (this instanceof IPowerHandler) { + IPowerHandler receptor = (IPowerHandler) this; + if (receptor.getPowerHandler() != null) { + receptor.getPowerHandler().update(); + } + } + } + + public abstract void initialize(); + + // / SAVING & LOADING + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("Access")) + access = EnumAccess.values()[nbttagcompound.getInteger("Access")]; + else + access = EnumAccess.SHARED; + if (nbttagcompound.hasKey("Owner")) + owner = nbttagcompound.getString("Owner"); + + if (nbttagcompound.hasKey("Orientation")) + orientation = ForgeDirection.values()[nbttagcompound.getInteger("Orientation")]; + else + orientation = ForgeDirection.WEST; + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + nbttagcompound.setInteger("Access", access.ordinal()); + if (owner != null) + nbttagcompound.setString("Owner", owner); + if (orientation != null) + nbttagcompound.setInteger("Orientation", orientation.ordinal()); + } + + // / SMP + @Override + public void sendNetworkUpdate() { + PacketTileUpdate packet = new PacketTileUpdate(this); + Proxies.net.sendNetworkPacket(packet, xCoord, yCoord, zCoord); + } + + @Override + public Packet getDescriptionPacket() { + PacketTileUpdate packet = new PacketTileUpdate(this); + return packet.getPacket(); + } + + public abstract PacketPayload getPacketPayload(); + + public abstract void fromPacketPayload(PacketPayload payload); + + @Override + public void fromPacket(ForestryPacket packetRaw) { + PacketTileUpdate packet = (PacketTileUpdate) packetRaw; + if (orientation != packet.getOrientation()) { + orientation = packet.getOrientation(); + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + errorState = packet.getErrorState(); + owner = packet.getOwner(); + access = packet.getAccess(); + fromPacketPayload(packet.payload); + } + + public LinkedList getCustomTriggers() { + return null; + } + + public void onRemoval() { + } + + // / REDSTONE INFO + /** + * @return true if tile is activated by redstone current. + */ + public boolean isActivated() { + return worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord); + } + // / ORIENTATION + private ForgeDirection orientation = ForgeDirection.WEST; + + public ForgeDirection getOrientation() { + return this.orientation; + } + + public void setOrientation(ForgeDirection orientation) { + if (this.orientation == orientation) + return; + this.orientation = orientation; + this.sendNetworkUpdate(); + } + // / ERROR HANDLING + public EnumErrorCode errorState = EnumErrorCode.OK; + + public void setErrorState(EnumErrorCode state) { + if (this.errorState == state) + return; + this.errorState = state; + this.sendNetworkUpdate(); + } + + @Override + public boolean throwsErrors() { + return true; + } + + @Override + public EnumErrorCode getErrorState() { + return errorState; + } + // / OWNERSHIP + public String owner = null; + private EnumAccess access = EnumAccess.SHARED; + + @Override + public boolean allowsRemoval(EntityPlayer player) { + if (!isOwnable()) + return true; + if (!isOwned()) + return true; + if (isOwner(player)) + return true; + if (Proxies.common.isOp(player)) + return true; + + return getAccess() == EnumAccess.SHARED; + } + + @Override + public boolean allowsInteraction(EntityPlayer player) { + if (Config.disablePermissions) + return true; + if (!isOwnable()) + return true; + if (!isOwned()) + return true; + if (isOwner(player)) + return true; + if (Proxies.common.isOp(player)) + return true; + + return getAccess() == EnumAccess.SHARED || getAccess() == EnumAccess.VIEWABLE; + } + + @Override + public EnumAccess getAccess() { + return access; + } + + @Override + public boolean isOwnable() { + return false; + } + + @Override + public boolean isOwned() { + return owner != null && !owner.isEmpty(); + } + + @Override + public String getOwnerName() { + return owner; + } + + public EntityPlayer getOwnerEntity() { + if (owner != null) + return worldObj.getPlayerEntityByName(owner); + else + return null; + } + + @Override + public void setOwner(EntityPlayer player) { + this.owner = player.getGameProfile().getId(); + } + + @Override + public boolean isOwner(EntityPlayer player) { + if (owner != null) + return owner.equals(player.getGameProfile().getId()); + else + return false; + } + + @Override + public boolean switchAccessRule(EntityPlayer player) { + if (owner != null && !owner.isEmpty() && !owner.equals(player.getGameProfile().getId())) + return false; + + if (access.ordinal() < EnumAccess.values().length - 1) + access = EnumAccess.values()[access.ordinal() + 1]; + else + access = EnumAccess.values()[0]; + + return true; + } + + /* NAME */ + public abstract String getInventoryName(); + + public boolean hasCustomInventoryName() { + return true; + } + + /* ACCESS */ + public abstract boolean isUseableByPlayer(EntityPlayer player); + + /* INVENTORY BASICS */ + public InventoryAdapter getInternalInventory() { + return null; + } + + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return true; + } + + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return canPutStackFromSide(i, itemstack, j); + } + + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if (getAccess() == EnumAccess.PRIVATE) + return false; + + return true; + } + + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return canTakeStackFromSide(i, itemstack, j); + } + + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if (getAccess() == EnumAccess.PRIVATE) + return false; + + return true; + } + + public int[] getAccessibleSlotsFromSide(int side) { + if (getInternalInventory() == null) + return Defaults.FACINGS_NONE; + else + return getInternalInventory().getSizeInventorySide(side); + + } + + /* IFLUIDHANDLER BASICS */ + public FluidTankInfo[] getTankInfo(ForgeDirection from) { + if (this instanceof ILiquidTankContainer) { + ForestryTank[] tanks = ((ILiquidTankContainer) this).getTanks(); + FluidTankInfo[] info = new FluidTankInfo[tanks.length]; + for (int i = 0; i < info.length; i++) { + info[i] = tanks[i].getInfo(); + } + return info; + } + return ForestryTank.DUMMY_TANKINFO_ARRAY; + } + + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + return 0; + } + + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + return null; + } + + public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { + return resource != null ? drain(from, resource.amount, doDrain) : null; + } + + public boolean canFill(ForgeDirection from, Fluid fluid) { + return true; + } + + public boolean canDrain(ForgeDirection from, Fluid fluid) { + return true; + } +} diff --git a/forestry_common/core/forestry/core/gadgets/TileMachine.java b/forestry_common/core/forestry/core/gadgets/TileMachine.java new file mode 100755 index 000000000..139b809d7 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileMachine.java @@ -0,0 +1,388 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import java.util.HashMap; +import java.util.LinkedList; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.interfaces.IClimatised; +import forestry.core.interfaces.IHintSource; +import forestry.core.network.PacketPayload; +import forestry.core.proxy.Proxies; +import forestry.core.utils.EnumAccess; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.Utils; +import forestry.plugins.PluginApiculture; +import forestry.plugins.PluginCore; +import forestry.plugins.PluginEnergy; +import forestry.plugins.PluginFactory; +import forestry.plugins.PluginMail; + +public class TileMachine extends TileForestry implements ISpecialInventory, IClimatised, IHintSource { + + public TileMachine() { + } + + // / IERRORSOURCE + @Override + public boolean throwsErrors() { + return false; + } + + // / IHINTSOURCE + @Override + public boolean hasHints() { + return false; + } + + @Override + public String[] getHints() { + return null; + } + + // / ICLIMATISED + @Override + public boolean isClimatized() { + return false; + } + + @Override + public EnumTemperature getTemperature() { + return EnumTemperature.NORMAL; + } + + @Override + public EnumHumidity getHumidity() { + return EnumHumidity.NORMAL; + } + + @Override + public float getExactTemperature() { + return 0; + } + + @Override + public float getExactHumidity() { + return 0; + } + + // / IOWNABLE + @Override + public boolean isOwnable() { + return true; + } + + protected void createMachine() { + } + + int oldkind; + NBTTagCompound olddata; + + @Override + public void initialize() { + + if (!Proxies.common.isSimulating(worldObj)) + return; + + if (olddata != null) + legacyConversion(oldkind, olddata); + + } + + @Override + public void updateEntity() { + + super.updateEntity(); + } + + @Override + public void onRemoval() { + } + + /** + * Read saved data + */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + super.readFromNBT(nbttagcompound); + + int kind = nbttagcompound.getInteger("Kind"); + oldkind = kind; + olddata = nbttagcompound; + + } + + private HashMap> definitionMap; + + private void createDefinitionMap() { + definitionMap = new HashMap>(); + + HashMap machineMap = new HashMap(); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_BOTTLER, PluginFactory.definitionBottler); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_CARPENTER, PluginFactory.definitionCarpenter); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_CENTRIFUGE, PluginFactory.definitionCentrifuge); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_FABRICATOR, PluginFactory.definitionFabricator); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_FERMENTER, PluginFactory.definitionFermenter); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_MOISTENER, PluginFactory.definitionMoistener); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_RAINTANK, PluginFactory.definitionRaintank); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_SQUEEZER, PluginFactory.definitionSqueezer); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_STILL, PluginFactory.definitionStill); + machineMap.put(Defaults.ID_PACKAGE_MACHINE_APIARY, PluginApiculture.definitionApiary); + machineMap.put(4, PluginEnergy.definitionGenerator); + definitionMap.put(ForestryBlock.factoryTESR, machineMap); + + HashMap millMap = new HashMap(); + millMap.put(Defaults.ID_PACKAGE_MILL_MAILBOX, PluginMail.definitionMailbox); + millMap.put(Defaults.ID_PACKAGE_MILL_TRADER, PluginMail.definitionTradestation); + millMap.put(Defaults.ID_PACKAGE_MILL_PHILATELIST, PluginMail.definitionPhilatelist); + millMap.put(Defaults.ID_PACKAGE_MILL_APIARIST_CHEST, PluginApiculture.definitionChest); + millMap.put(Defaults.ID_PACKAGE_MILL_ANALYZER, PluginCore.definitionAnalyzer); + millMap.put(Defaults.ID_PACKAGE_MILL_RAINMAKER, PluginFactory.definitionRainmaker); + definitionMap.put(ForestryBlock.factoryPlain, millMap); + + HashMap engineMap = new HashMap(); + engineMap.put(0, PluginEnergy.definitionEngineBronze); + engineMap.put(1, PluginEnergy.definitionEngineCopper); + engineMap.put(2, PluginEnergy.definitionEngineTin); + definitionMap.put(ForestryBlock.engine, engineMap); + + } + + private void legacyConversion(int kind, NBTTagCompound nbttagcompound) { + if (definitionMap == null) + createDefinitionMap(); + + Block block = worldObj.getBlock(xCoord, yCoord, zCoord); + if (!definitionMap.containsKey(block) || !definitionMap.get(block).containsKey(kind)) { + commitSeppuku(block, kind); + return; + } + + MachineDefinition definition = definitionMap.get(block).get(kind); + Proxies.log.info("Converting obsolete gadget %s-%s to new '%s' %s-%s", block.getUnlocalizedName(), kind, definition.teIdent, definition.block.getUnlocalizedName(), definition.meta); + + Proxies.log.info("Removing old tile entity..."); + worldObj.removeTileEntity(xCoord, yCoord, zCoord); + worldObj.setBlockToAir(xCoord, yCoord, zCoord); + Proxies.log.info("Setting to new block id..."); + worldObj.setBlock(xCoord, yCoord, zCoord, definition.block, definition.meta, Defaults.FLAG_BLOCK_SYNCH); + TileEntity tile = worldObj.getTileEntity(xCoord, yCoord, zCoord); + if (tile == null) + throw new RuntimeException("Failed to set new block tile entity!"); + else if (tile.getClass() != definition.teClass) + throw new RuntimeException(String.format("Converted tile entity was '%s' instead of expected '%s'", tile.getClass(), definition.teClass)); + Proxies.log.info("Refreshing converted tile entity %s with nbt data...", tile.getClass()); + if (nbttagcompound.hasKey("Machine")) + tile.readFromNBT(complementNBT(nbttagcompound, nbttagcompound.getCompoundTag("Machine"), definition)); + else + tile.readFromNBT(nbttagcompound); + } + + private NBTTagCompound complementNBT(NBTTagCompound parent, NBTTagCompound inner, MachineDefinition definition) { + + inner.setString("id", definition.teIdent); + inner.setInteger("x", this.xCoord); + inner.setInteger("y", this.yCoord); + inner.setInteger("z", this.zCoord); + + inner.setInteger("Access", parent.getInteger("Access")); + if (parent.hasKey("Owner")) + inner.setString("Owner", parent.getString("Owner")); + if (parent.hasKey("Orientation")) + inner.setInteger("Orientation", parent.getInteger("Orientation")); + + return inner; + } + + private void commitSeppuku(Block block, int meta) { + Proxies.log.info("Obsolete gadget %s-%s has no replacement defined. Committing sepukku.", block.getUnlocalizedName(), meta); + worldObj.removeTileEntity(xCoord, yCoord, zCoord); + worldObj.setBlockToAir(xCoord, yCoord, zCoord); + } + + /** + * Write save data + */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + super.writeToNBT(nbttagcompound); + + // Legacy for old fermenter with strange meta data + int kind = worldObj.getBlockMetadata(xCoord, yCoord, zCoord); + nbttagcompound.setInteger("Kind", kind); + + /* + * if (machine != null) { NBTTagCompound NBTmachine = new NBTTagCompound(); machine.writeToNBT(NBTmachine); nbttagcompound.setTag("Machine", + * NBTmachine); } else { Proxies.log.warning("Saved a " + getClass() + " without machine."); } + */ + } + + @Override + public void validate() { + super.validate(); + } + + public boolean isWorking() { + return false; + } + + public int getChargeReceivedScaled(int i) { + return 0; + } + + public static EnumTankLevel rateTankLevel(int scaled) { + + if (scaled < 5) + return EnumTankLevel.EMPTY; + else if (scaled < 30) + return EnumTankLevel.LOW; + else if (scaled < 60) + return EnumTankLevel.MEDIUM; + else if (scaled < 90) + return EnumTankLevel.HIGH; + else + return EnumTankLevel.MAXIMUM; + } + + // / REDSTONE SIGNALS + public boolean isIndirectlyPoweringTo(IBlockAccess world, int i, int j, int k, int l) { + return false; + } + + public boolean isPoweringTo(IBlockAccess iblockaccess, int i, int j, int k, int l) { + return false; + } + + // IINVENTORY IMPLEMENTATION + @Override + public int getSizeInventory() { + return 0; + } + + @Override + public ItemStack getStackInSlot(int i) { + return null; + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return null; + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + } + + @Override + public String getInventoryName() { + return "[Unknown]"; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return null; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return Utils.isUseableByPlayer(player, this, worldObj, xCoord, yCoord, zCoord); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + // IPARTICULARINVENTORY IMPLEMENTATION + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + if (getAccess() == EnumAccess.PRIVATE) + return 0; + + return 0; + } + + // @Override + // public boolean canAccess(String username) { + // return isOwned() && getOwnerName().equals(username); + // } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + if (getAccess() == EnumAccess.PRIVATE) + return new ItemStack[0]; + + return new ItemStack[0]; + } + + // INETWORKEDTILE IMPLEMENTATION + @Override + public PacketPayload getPacketPayload() { + + PacketPayload payload = null; + + return payload; + } + + @Override + public void fromPacketPayload(PacketPayload payload) { + } + + // NEIGHBOUR CHANGE + public void onNeighborBlockChange() { + } + + // ITRIGGERPROVIDER + @Override + public LinkedList getCustomTriggers() { + return null; + } + +} diff --git a/forestry_common/core/forestry/core/gadgets/TileMill.java b/forestry_common/core/forestry/core/gadgets/TileMill.java new file mode 100755 index 000000000..51f937b50 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileMill.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +public class TileMill extends TileMachine { +} diff --git a/forestry_common/core/forestry/core/gadgets/TileNaturalistChest.java b/forestry_common/core/forestry/core/gadgets/TileNaturalistChest.java new file mode 100755 index 000000000..47c371f94 --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TileNaturalistChest.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.GuiHandler; +import forestry.core.config.Config; +import forestry.core.gui.IPagedInventory; +import forestry.core.utils.StringUtil; + +public abstract class TileNaturalistChest extends TileBase implements IInventory, IPagedInventory { + + private ItemStack[] inventoryStacks = new ItemStack[125]; + private final ISpeciesRoot speciesRoot; + private final int guiID; + + public TileNaturalistChest(ISpeciesRoot speciesRoot, int guiId) { + setHints(Config.hints.get("apiarist.chest")); + this.speciesRoot = speciesRoot; + this.guiID = guiId; + } + + @Override + public String getInventoryName() { + return StringUtil.localize("tile.mill.3"); + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, guiID, player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + public void flipPage(EntityPlayer player, int page) { + player.openGui(ForestryAPI.instance, GuiHandler.encodeGuiData(guiID, page), player.worldObj, xCoord, yCoord, zCoord); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + NBTTagList nbttaglist = new NBTTagList(); + for (int i = 0; i < inventoryStacks.length; i++) { + if (inventoryStacks[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + inventoryStacks[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + } + nbttagcompound.setTag("Items", nbttaglist); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + NBTTagList nbttaglist = nbttagcompound.getTagList("Items", 10); + inventoryStacks = new ItemStack[getSizeInventory()]; + for (int i = 0; i < nbttaglist.tagCount(); i++) { + + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + byte byte0 = nbttagcompound1.getByte("Slot"); + if (byte0 >= 0 && byte0 < inventoryStacks.length) + inventoryStacks[byte0] = ItemStack.loadItemStackFromNBT(nbttagcompound1); + } + } + + /* UPDATING */ + @Override + public void updateServerSide() { + } + + /* ERROR HANDLING */ + @Override + public boolean throwsErrors() { + return false; + } + + /* IINVENTORY */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return itemstack == null || speciesRoot.isMember(itemstack); + } + + @Override + public int getSizeInventory() { + return inventoryStacks.length; + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventoryStacks[i]; + } + + @Override + public ItemStack decrStackSize(int i, int j) { + if (inventoryStacks[i] == null) + return null; + + ItemStack product; + if (inventoryStacks[i].stackSize <= j) { + product = inventoryStacks[i]; + inventoryStacks[i] = null; + return product; + } else { + product = inventoryStacks[i].splitStack(j); + if (inventoryStacks[i].stackSize == 0) + inventoryStacks[i] = null; + + return product; + } + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventoryStacks[i] = itemstack; + if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) + itemstack.stackSize = getInventoryStackLimit(); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + if (inventoryStacks[slot] == null) + return null; + ItemStack toReturn = inventoryStacks[slot]; + inventoryStacks[slot] = null; + return toReturn; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } +} diff --git a/forestry_common/core/forestry/core/gadgets/TilePowered.java b/forestry_common/core/forestry/core/gadgets/TilePowered.java new file mode 100755 index 000000000..4ff2a374b --- /dev/null +++ b/forestry_common/core/forestry/core/gadgets/TilePowered.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gadgets; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; + +import buildcraft.api.power.PowerHandler; +import buildcraft.api.power.PowerHandler.PowerReceiver; +import buildcraft.api.power.PowerHandler.Type; + +import forestry.core.GameMode; +import forestry.core.config.Defaults; +import forestry.core.interfaces.IPowerHandler; +import forestry.core.interfaces.IRenderableMachine; +import forestry.core.network.ClassMap; +import forestry.core.network.IndexInPayload; +import forestry.core.network.PacketPayload; +import forestry.core.proxy.Proxies; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; + +public abstract class TilePowered extends TileBase implements IPowerHandler, IRenderableMachine { + + public static int WORK_CYCLES = 4; + + @Override + public PacketPayload getPacketPayload() { + if (!ClassMap.classMappers.containsKey(this.getClass())) + ClassMap.classMappers.put(this.getClass(), new ClassMap(this.getClass())); + + ClassMap classmap = ClassMap.classMappers.get(this.getClass()); + PacketPayload payload = new PacketPayload(classmap.intSize, classmap.floatSize, classmap.stringSize); + + try { + classmap.setData(this, payload.intPayload, payload.floatPayload, payload.stringPayload, new IndexInPayload(0, 0, 0)); + } catch (Exception ex) { + ex.printStackTrace(); + } + + return payload; + } + + @Override + public void fromPacketPayload(PacketPayload payload) { + + if (payload.isEmpty()) + return; + + if (!ClassMap.classMappers.containsKey(this.getClass())) + ClassMap.classMappers.put(this.getClass(), new ClassMap(this.getClass())); + + ClassMap classmap = ClassMap.classMappers.get(this.getClass()); + + try { + classmap.fromData(this, payload.intPayload, payload.floatPayload, payload.stringPayload, new IndexInPayload(0, 0, 0)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + private final PowerHandler powerHandler; + + public TilePowered() { + powerHandler = new PowerHandler(this, Type.MACHINE); + configurePowerProvider(powerHandler); + adjustPowerProvider(powerHandler); + } + + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(Defaults.MACHINE_MIN_ENERGY_RECEIVED, Defaults.MACHINE_MAX_ENERGY_RECEIVED, + Defaults.MACHINE_MIN_ACTIVATION_ENERGY, Defaults.MACHINE_MAX_ENERGY); + } + + private void adjustPowerProvider(PowerHandler provider) { + provider.configure( + provider.getMinEnergyReceived(), + Math.round(provider.getMaxEnergyReceived() * GameMode.getGameMode().getFloatSetting("energy.demand.modifier")), + Math.round(provider.getActivationEnergy() * GameMode.getGameMode().getFloatSetting("energy.demand.modifier")), + Math.round(provider.getMaxEnergyStored() * GameMode.getGameMode().getFloatSetting("energy.demand.modifier"))); + } + + /* STATE INFORMATION */ + public abstract boolean isWorking(); + + public boolean hasResourcesMin(float percentage) { + return false; + } + + public boolean hasFuelMin(float percentage) { + return false; + } + + public boolean hasWork() { + return false; + } + + /* IPOWERRECEPTOR */ + @Override + public PowerHandler getPowerHandler() { + return powerHandler; + } + private int workCounter; + + @Override + public void updateEntity() { + super.updateEntity(); + if (worldObj.isRemote) + return; + + if (workCounter >= WORK_CYCLES && worldObj.getTotalWorldTime() % 5 == 0) { + if (workCycle()) + workCounter = 0; + } + } + + @Override + public void doWork(PowerHandler workProvider) { + + if (!Proxies.common.isSimulating(worldObj)) + return; + + // Hard limit to 4 cycles / second. + if (workCounter < WORK_CYCLES) { + powerHandler.useEnergy(powerHandler.getActivationEnergy(), powerHandler.getActivationEnergy(), true); + workCounter++; + } + + /* + // Hard limit to 4 cycles / second. + if (worldObj.getTotalWorldTime() % 5 * 10 != 0) + return; + + PluginBuildCraft.instance.invokeUseEnergyMethod(powerHandler, powerHandler.getActivationEnergy(), powerHandler.getActivationEnergy(), false); + + // Do not consume energy if the boiler didn't do any work. + if (!workCycle()) + return; + + // Use up energy since we did some work. + PluginBuildCraft.instance.invokeUseEnergyMethod(powerHandler, powerHandler.getActivationEnergy(), powerHandler.getActivationEnergy(), true); + */ + } + + public abstract boolean workCycle(); + + @Override + public PowerReceiver getPowerReceiver(ForgeDirection side) { + return powerHandler.getPowerReceiver(); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + powerHandler.writeToNBT(nbt); + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + powerHandler.readFromNBT(nbt); + } + + /* + @Override + public int powerRequest(ForgeDirection direction) { + float needed = powerProvider.getMaxEnergyStored() - powerProvider.getEnergyStored(); + return (int) Math.ceil(Math.min(powerProvider.getMaxEnergyReceived(), needed)); + } */ + + /* LIQUID CONTAINER HANDLING */ + protected ItemStack bottleIntoContainer(ItemStack canStack, ItemStack outputStack, FluidContainerData container, ForestryTank tank) { + if (tank.getFluidAmount() < container.fluid.amount) + return outputStack; + if (canStack.stackSize <= 0) + return outputStack; + if (outputStack != null && !outputStack.isItemEqual(container.filledContainer)) + return outputStack; + if (outputStack != null && outputStack.stackSize >= outputStack.getMaxStackSize()) + return outputStack; + + tank.drain(container.fluid.amount, true); + canStack.stackSize--; + + if (outputStack == null) + outputStack = container.filledContainer.copy(); + else + outputStack.stackSize++; + + return outputStack; + } + + // / ADDITIONAL LIQUID HANDLING + @Override + public EnumTankLevel getPrimaryLevel() { + return EnumTankLevel.EMPTY; + } + + @Override + public EnumTankLevel getSecondaryLevel() { + return EnumTankLevel.EMPTY; + } +} diff --git a/forestry_common/core/forestry/core/genetics/Allele.java b/forestry_common/core/forestry/core/genetics/Allele.java new file mode 100755 index 000000000..1ed39f080 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/Allele.java @@ -0,0 +1,693 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.EnumSet; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.ILegacyHandler; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class Allele implements IAllele { + + protected String uid; + boolean isDominant; + protected String name; + + public Allele(String uid, boolean isDominant) { + this(uid, isDominant, false); + } + + protected Allele(String uid, boolean isDominant, boolean skipRegister) { + this.uid = uid; + this.isDominant = isDominant; + this.name = "allele."+uid; + + if (!skipRegister) + AlleleManager.alleleRegistry.registerAllele(this); + } + + @Override + public String getUID() { + return "forestry." + this.uid; + } + + @Override + public boolean isDominant() { + return isDominant; + } + + // / BEES // SPECIES + // Common Branch + public static AlleleSpecies speciesForest; + public static AlleleSpecies speciesMeadows; + public static AlleleSpecies speciesCommon; + public static AlleleSpecies speciesCultivated; + + // Noble Branch + public static AlleleSpecies speciesNoble; + public static AlleleSpecies speciesMajestic; + public static AlleleSpecies speciesImperial; + + // Industrious Branch + public static AlleleSpecies speciesDiligent; + public static AlleleSpecies speciesUnweary; + public static AlleleSpecies speciesIndustrious; + + // Heroic Branch + public static AlleleSpecies speciesSteadfast; + public static AlleleSpecies speciesValiant; + public static AlleleSpecies speciesHeroic; + + // Infernal Branch + public static AlleleSpecies speciesSinister; + public static AlleleSpecies speciesFiendish; + public static AlleleSpecies speciesDemonic; + + // Austere Branch + public static AlleleSpecies speciesModest; + public static AlleleSpecies speciesFrugal; + public static AlleleSpecies speciesAustere; + + // / Tropical Branch + public static AlleleSpecies speciesTropical; + public static AlleleSpecies speciesExotic; + public static AlleleSpecies speciesEdenic; + + // End Branch + public static AlleleSpecies speciesEnded; + public static AlleleSpecies speciesSpectral; + public static AlleleSpecies speciesPhantasmal; + + // Frozen Branch + public static AlleleSpecies speciesWintry; + public static AlleleSpecies speciesIcy; + public static AlleleSpecies speciesGlacial; + + // Vengeful Branch + public static AlleleSpecies speciesVindictive; + public static AlleleSpecies speciesVengeful; + public static AlleleSpecies speciesAvenging; + + // Reddened Branch (EE) + public static AlleleSpecies speciesDarkened; + public static AlleleSpecies speciesReddened; + public static AlleleSpecies speciesOmega; + + // Festive branch + public static AlleleSpecies speciesLeporine; // Easter + public static AlleleSpecies speciesMerry; // Christmas + public static AlleleSpecies speciesTipsy; // New Year + // 35 Solstice + public static AlleleSpecies speciesTricky; // Halloween + // 37 Thanksgiving + // 39 New Year + + // Agrarian branch + public static AlleleSpecies speciesRural; + // 41 Farmerly + // 42 Agrarian + + // Boggy branch + public static AlleleSpecies speciesMarshy; + // 44 speciesMiry + // 45 speciesBoggy + + // Monastic branch + public static AlleleSpecies speciesMonastic; + public static AlleleSpecies speciesSecluded; + public static AlleleSpecies speciesHermitic; + + // / TREES // SPECIES 512 - 1023 + public static AlleleSpecies treeOak; + public static AlleleSpecies treeBirch; + public static AlleleSpecies treeSpruce; + public static AlleleSpecies treePine; + public static AlleleSpecies treeJungle; + + public static AlleleSpecies treeLarch; + public static AlleleSpecies treeTeak; + public static AlleleSpecies treeAcacia; + public static AlleleSpecies treeLime; + public static AlleleSpecies treeChestnut; + public static AlleleSpecies treeWenge; + public static AlleleSpecies treeBaobab; + public static AlleleSpecies treeSequioa; + public static AlleleSpecies treeGiganteum; + + public static AlleleSpecies treeKapok; + public static AlleleSpecies treeEbony; + public static AlleleSpecies treeMahogany; + public static AlleleSpecies treeBalsa; + public static AlleleSpecies treePapaya; + public static AlleleSpecies treeWalnut; + public static AlleleSpecies treeDate; + public static AlleleSpecies treeCherry; + + public static AlleleSpecies treeWillow; + public static AlleleSpecies treeSipiri; + + public static AlleleSpecies treeMahoe; + public static AlleleSpecies treePoplar; + + public static AlleleSpecies treeLemon; + public static AlleleSpecies treePlum; + + public static AlleleSpecies treeMaple; + + /// BUTTERFLIES // SPECIES + // Moths + public static AlleleSpecies mothBrimstone; + public static AlleleSpecies mothLatticedHeath; + public static AlleleSpecies mothAtlas; + + // Butterflies + public static AlleleSpecies lepiCabbageWhite; + public static AlleleSpecies lepiGlasswing; + public static AlleleSpecies lepiEmeraldPeacock; + public static AlleleSpecies lepiThoasSwallow; + public static AlleleSpecies lepiCitrusSwallow; + public static AlleleSpecies lepiZebraSwallow; + public static AlleleSpecies lepiBlackSwallow; + public static AlleleSpecies lepiDianaFrit; + + public static AlleleSpecies lepiSpeckledWood; + public static AlleleSpecies lepiMadeiranSpeckledWood; + public static AlleleSpecies lepiCanarySpeckledWood; + + public static AlleleSpecies lepiMenelausBlueMorpho; + public static AlleleSpecies lepiPeleidesBlueMorpho; + public static AlleleSpecies lepiRhetenorBlueMorpho; + + public static AlleleSpecies lepiBrimstone; + public static AlleleSpecies lepiAurora; + public static AlleleSpecies lepiPostillion; + public static AlleleSpecies lepiPalaenoSulphur; + public static AlleleSpecies lepiReseda; + public static AlleleSpecies lepiSpringAzure; + public static AlleleSpecies lepiGozoraAzure; + public static AlleleSpecies lepiComma; + public static AlleleSpecies lepiBatesia; + public static AlleleSpecies lepiBlueWing; + + public static AlleleSpecies lepiMonarch; + public static AlleleSpecies lepiBlueDuke; + public static AlleleSpecies lepiGlassyTiger; + public static AlleleSpecies lepiPostman; + public static AlleleSpecies lepiSpicebush; + public static AlleleSpecies lepiMalachite; + public static AlleleSpecies lepiLLacewing; + + // / ALL // GENERIC + public static Allele boolFalse; + public static Allele boolTrue; + + public static Allele int1; + public static Allele int2; + public static Allele int3; + public static Allele int4; + public static Allele int5; + public static Allele int6; + public static Allele int7; + public static Allele int8; + public static Allele int9; + public static Allele int10; + + // / BEES // SPEED 1100 - 1199 + public static Allele speedSlowest; + public static Allele speedSlower; + public static Allele speedSlow; + public static Allele speedNorm; + public static Allele speedFast; + public static Allele speedFaster; + public static Allele speedFastest; + + // / BEES // LIFESPAN 1200 - 1299 + public static Allele lifespanShortest; + public static Allele lifespanShorter; + public static Allele lifespanShort; + public static Allele lifespanShortened; + public static Allele lifespanNormal; + public static Allele lifespanElongated; + public static Allele lifespanLong; + public static Allele lifespanLonger; + public static Allele lifespanLongest; + + // / BEES // FERTILITY 1300 - 1349 + public static Allele fertilityLow; + public static Allele fertilityNormal; + public static Allele fertilityHigh; + public static Allele fertilityMaximum; + + // / TREES // GROWTH PROVIDER 1350 - 1399 + public static Allele growthLightlevel; + public static Allele growthAcacia; + public static Allele growthTropical; + + // TREES FRUIT PROVIDERS + public static Allele fruitNone; + public static Allele fruitApple; + public static Allele fruitCocoa; + public static Allele fruitChestnut; + public static Allele fruitCoconut; + public static Allele fruitWalnut; + public static Allele fruitCherry; + public static Allele fruitDates; + public static Allele fruitPapaya; + public static Allele fruitLemon; + public static Allele fruitPlum; + public static Allele fruitJujube; + + // / TREES // HEIGHT 1400 - 1449 + public static Allele heightSmallest; + public static Allele heightSmaller; + public static Allele heightSmall; + public static Allele heightAverage; + public static Allele heightLarge; + public static Allele heightLarger; + public static Allele heightLargest; + public static Allele heightGigantic; + + /// BUTTERFLIES // SIZE + public static Allele sizeSmallest; + public static Allele sizeSmaller; + public static Allele sizeSmall; + public static Allele sizeAverage; + public static Allele sizeLarge; + public static Allele sizeLarger; + public static Allele sizeLargest; + + // / BOTH // TOLERANCE 1450 - 1499 + public static Allele toleranceNone; + public static Allele toleranceBoth1; + public static Allele toleranceBoth2; + public static Allele toleranceBoth3; + public static Allele toleranceBoth4; + public static Allele toleranceBoth5; + public static Allele toleranceUp1; + public static Allele toleranceUp2; + public static Allele toleranceUp3; + public static Allele toleranceUp4; + public static Allele toleranceUp5; + public static Allele toleranceDown1; + public static Allele toleranceDown2; + public static Allele toleranceDown3; + public static Allele toleranceDown4; + public static Allele toleranceDown5; + + // / BEES // FLOWER PROVIDERS 1500 - 1599 + public static Allele flowersVanilla; + public static Allele flowersNether; + public static Allele flowersCacti; + public static Allele flowersMushrooms; + public static Allele flowersEnd; + public static Allele flowersJungle; + public static Allele flowersSnow; + public static Allele flowersWheat; + public static Allele flowersGourd; + + // / TREES // FERTILITY 1600 - 1649 + public static Allele saplingsLowest; + public static Allele saplingsLower; + public static Allele saplingsLow; + public static Allele saplingsAverage; + public static Allele saplingsHigh; + public static Allele saplingsHigher; + public static Allele saplingsHighest; + + // / TREES // YIELD 1650 - 1699 + public static Allele yieldLowest; + public static Allele yieldLower; + public static Allele yieldLow; + public static Allele yieldAverage; + public static Allele yieldHigh; + public static Allele yieldHigher; + public static Allele yieldHighest; + + // TREES // SAPPINESS + public static Allele sappinessLowest; + public static Allele sappinessLower; + public static Allele sappinessLow; + public static Allele sappinessAverage; + public static Allele sappinessHigh; + public static Allele sappinessHigher; + public static Allele sappinessHighest; + + // TREES // MATURATION TIME + public static Allele maturationSlowest; + public static Allele maturationSlower; + public static Allele maturationSlow; + public static Allele maturationAverage; + public static Allele maturationFast; + public static Allele maturationFaster; + public static Allele maturationFastest; + + // / BEES // FLOWER GROWTH 1700 - 1749 + public static Allele floweringSlowest; + public static Allele floweringSlower; + public static Allele floweringSlow; + public static Allele floweringAverage; + public static Allele floweringFast; + public static Allele floweringFaster; + public static Allele floweringFastest; + public static Allele floweringMaximum; + + // / BOTH // TERRITORY 1750 - 1799 + public static Allele territoryDefault; + public static Allele territoryLarge; + public static Allele territoryLarger; + public static Allele territoryLargest; + + // / BEES // EFFECTS 1800 - 1899 + public static Allele effectNone; + public static Allele effectAggressive; + public static Allele effectHeroic; + public static Allele effectBeatific; + public static Allele effectMiasmic; + public static Allele effectMisanthrope; + public static Allele effectGlacial; + public static Allele effectRadioactive; + public static Allele effectCreeper; + public static Allele effectIgnition; + public static Allele effectExploration; + public static Allele effectFestiveEaster; + public static Allele effectSnowing; + public static Allele effectDrunkard; + public static Allele effectReanimation; + public static Allele effectResurrection; + public static Allele effectRepulsion; + + // / TREES // EFFECTS + public static Allele leavesNone; + + // / BUTTERFLIES // EFFECTS + public static Allele butterflyNone; + + // These are "secondary" plant attributes, i.e. the tree can double as one. + public static Allele plantTypeNone; + public static Allele plantTypePlains; + public static Allele plantTypeDesert; + public static Allele plantTypeBeach; + public static Allele plantTypeCave; + public static Allele plantTypeWater; + public static Allele plantTypeNether; + public static Allele plantTypeCrop; + + public static void initialize() { + // ALL // GENERIC + boolFalse = new AlleleBoolean("boolFalse", false); + boolTrue = new AlleleBoolean("boolTrue", true); + + int1 = new AlleleInteger("i1d", 1, true); + int2 = new AlleleInteger("i2d", 2, true); + int3 = new AlleleInteger("i3d", 3, true); + int4 = new AlleleInteger("i4d", 4, true); + int5 = new AlleleInteger("i5d", 5, true); + int6 = new AlleleInteger("i6d", 6, true); + int7 = new AlleleInteger("i7d", 7, true); + int8 = new AlleleInteger("i8d", 8, true); + int9 = new AlleleInteger("i9d", 9, true); + int10 = new AlleleInteger("i10d", 10, true); + + // BEES // SPEED + speedSlowest = new AlleleFloat("speedSlowest", 0.3f, true).setName("gui.slowest"); + speedSlower = new AlleleFloat("speedSlower", 0.6f, true).setName("gui.slower"); + speedSlow = new AlleleFloat("speedSlow", 0.8f, true).setName("gui.slow"); + speedNorm = new AlleleFloat("speedNorm", 1.0f).setName("gui.normal"); + speedFast = new AlleleFloat("speedFast", 1.2f, true).setName("gui.fast"); + speedFaster = new AlleleFloat("speedFaster", 1.4f).setName("gui.faster"); + speedFastest = new AlleleFloat("speedFastest", 1.7f).setName("gui.fastest"); + + // BEES // LIFESPAN + lifespanShortest = new AlleleInteger("lifespanShortest", 10, false).setName("gui.shortestlife"); + lifespanShorter = new AlleleInteger("lifespanShorter", 20, true).setName("gui.shorterlife"); + lifespanShort = new AlleleInteger("lifespanShort", 30, true).setName("gui.shortlife"); + lifespanShortened = new AlleleInteger("lifespanShortened", 35, true).setName("gui.shortenedlife"); + lifespanNormal = new AlleleInteger("lifespanNormal", 40).setName("gui.normallife"); + lifespanElongated = new AlleleInteger("lifespanElongated", 45, true).setName("gui.elongatedlife"); + lifespanLong = new AlleleInteger("lifespanLong", 50).setName("gui.longlife"); + lifespanLonger = new AlleleInteger("lifespanLonger", 60).setName("gui.longerlife"); + lifespanLongest = new AlleleInteger("lifespanLongest", 70).setName("gui.longestlife"); + + // BEES // FERTILITY + fertilityLow = new AlleleInteger("fertilityLow", 1, true); + fertilityNormal = new AlleleInteger("fertilityNormal", 2, true); + fertilityHigh = new AlleleInteger("fertilityHigh", 3); + fertilityMaximum = new AlleleInteger("fertilityMaximum", 4); + + // TREES // HEIGHT + heightSmallest = new AlleleFloat("heightSmallest", 0.25f).setName("gui.smallest"); + heightSmaller = new AlleleFloat("heightSmaller", 0.5f).setName("gui.smaller"); + heightSmall = new AlleleFloat("heightSmall", 0.75f).setName("gui.small"); + heightAverage = new AlleleFloat("heightMax10", 1.0f).setName("gui.average"); + heightLarge = new AlleleFloat("heightLarge", 1.25f).setName("gui.large"); + heightLarger = new AlleleFloat("heightLarger", 1.5f).setName("gui.larger"); + heightLargest = new AlleleFloat("heightLargest", 1.75f).setName("gui.largest"); + heightGigantic = new AlleleFloat("heightGigantic", 2.0f).setName("gui.gigantic"); + + // BUTTERFLIES // SIZE + sizeSmallest = new AlleleFloat("sizeSmallest", 0.3f).setName("gui.smallest"); + sizeSmaller = new AlleleFloat("sizeSmaller", 0.4f).setName("gui.smaller"); + sizeSmall = new AlleleFloat("sizeSmall", 0.5f).setName("gui.small"); + sizeAverage = new AlleleFloat("sizeAverage", 0.6f).setName("gui.average"); + sizeLarge = new AlleleFloat("sizeLarge", 0.75f).setName("gui.large"); + sizeLarger = new AlleleFloat("sizeLarger", 0.9f).setName("gui.larger"); + sizeLargest = new AlleleFloat("sizeLargest", 1.0f).setName("gui.largest"); + + // BEES // TOLERANCE + toleranceNone = new AlleleTolerance("toleranceNone", EnumTolerance.NONE); + toleranceBoth1 = new AlleleTolerance("toleranceBoth1", EnumTolerance.BOTH_1, true); + toleranceBoth2 = new AlleleTolerance("toleranceBoth2", EnumTolerance.BOTH_2); + toleranceBoth3 = new AlleleTolerance("toleranceBoth3", EnumTolerance.BOTH_3); + toleranceBoth4 = new AlleleTolerance("toleranceBoth4", EnumTolerance.BOTH_4); + toleranceBoth5 = new AlleleTolerance("toleranceBoth5", EnumTolerance.BOTH_5); + toleranceUp1 = new AlleleTolerance("toleranceUp1", EnumTolerance.UP_1, true); + toleranceUp2 = new AlleleTolerance("toleranceUp2", EnumTolerance.UP_2); + toleranceUp3 = new AlleleTolerance("toleranceUp3", EnumTolerance.UP_3); + toleranceUp4 = new AlleleTolerance("toleranceUp4", EnumTolerance.UP_4); + toleranceUp5 = new AlleleTolerance("toleranceUp5", EnumTolerance.UP_5); + toleranceDown1 = new AlleleTolerance("toleranceDown1", EnumTolerance.DOWN_1, true); + toleranceDown2 = new AlleleTolerance("toleranceDown2", EnumTolerance.DOWN_2); + toleranceDown3 = new AlleleTolerance("toleranceDown3", EnumTolerance.DOWN_3); + toleranceDown4 = new AlleleTolerance("toleranceDown4", EnumTolerance.DOWN_4); + toleranceDown5 = new AlleleTolerance("toleranceDown5", EnumTolerance.DOWN_5); + + // TREES // FERTILITY + saplingsLowest = new AlleleFloat("saplingsLowest", 0.01f, true).setName("gui.lowest"); + saplingsLower = new AlleleFloat("saplingsLower", 0.025f, true).setName("gui.lower"); + saplingsLow = new AlleleFloat("saplingsLow", 0.035f, true).setName("gui.low"); + saplingsAverage = new AlleleFloat("saplingsDefault", 0.05f, true).setName("gui.average"); + saplingsHigh = new AlleleFloat("saplingsDouble", 0.1f, true).setName("gui.high"); + saplingsHigher = new AlleleFloat("saplingsTriple", 0.2f, true).setName("gui.higher"); + saplingsHighest = new AlleleFloat("saplingsHighest", 0.3f, true).setName("gui.highest"); + + // TREES // YIELD + yieldLowest = new AlleleFloat("yieldLowest", 0.025f, true).setName("gui.lowest"); + yieldLower = new AlleleFloat("yieldLower", 0.05f, true).setName("gui.lower"); + yieldLow = new AlleleFloat("yieldLow", 0.1f, true).setName("gui.low"); + yieldAverage = new AlleleFloat("yieldDefault", 0.2f, true).setName("gui.average"); + yieldHigh = new AlleleFloat("yieldHigh", 0.3f, false).setName("gui.high"); + yieldHigher = new AlleleFloat("yieldHigher", 0.35f, false).setName("gui.higher"); + yieldHighest = new AlleleFloat("yieldHighest", 0.4f, false).setName("gui.highest"); + + // TREES // SAPPINESS + sappinessLowest = new AlleleFloat("sappinessLowest", 0.1f, true).setName("gui.lowest"); + sappinessLower = new AlleleFloat("sappinessLower", 0.2f, true).setName("gui.lower"); + sappinessLow = new AlleleFloat("sappinessLow", 0.3f, true).setName("gui.low"); + sappinessAverage = new AlleleFloat("sappinessAverage", 0.4f, true).setName("gui.average"); + sappinessHigh = new AlleleFloat("sappinessHigh", 0.6f, true).setName("gui.high"); + sappinessHigher = new AlleleFloat("sappinessHigher", 0.8f, false).setName("gui.higher"); + sappinessHighest = new AlleleFloat("sappinessHighest", 1.0f, false).setName("gui.highest"); + + // TREES // MATURATION TIME + maturationSlowest = new AlleleInteger("maturationSlowest", 10, true).setName("gui.slowest"); + maturationSlower = new AlleleInteger("maturationSlower", 7).setName("gui.slower"); + maturationSlow = new AlleleInteger("maturationSlow", 5, true).setName("gui.slow"); + maturationAverage = new AlleleInteger("maturationAverage", 4).setName("gui.average"); + maturationFast = new AlleleInteger("maturationFast", 3).setName("gui.fast"); + maturationFaster = new AlleleInteger("maturationFaster", 2).setName("gui.faster"); + maturationFastest = new AlleleInteger("maturationFastest", 1).setName("gui.fastest"); + + // BEES // FLOWER GROWTH + floweringSlowest = new AlleleInteger("floweringSlowest", 5, true).setName("gui.slowest"); + floweringSlower = new AlleleInteger("floweringSlower", 10).setName("gui.slower"); + floweringSlow = new AlleleInteger("floweringSlow", 15).setName("gui.slow"); + floweringAverage = new AlleleInteger("floweringAverage", 20).setName("gui.average"); + floweringFast = new AlleleInteger("floweringFast", 25).setName("gui.fast"); + floweringFaster = new AlleleInteger("floweringFaster", 30).setName("gui.faster"); + floweringFastest = new AlleleInteger("floweringFastest", 35).setName("gui.fastest"); + floweringMaximum = new AlleleInteger("floweringMaximum", 99, true).setName("gui.maximum"); + + // BOTH // TERRITORY + territoryDefault = new AlleleArea("territoryDefault", new int[] {9, 6, 9}).setName("gui.average"); + territoryLarge = new AlleleArea("territoryLarge", new int[] {11, 8, 11}).setName("gui.large"); + territoryLarger = new AlleleArea("territoryLarger", new int[] {13, 12, 13}).setName("gui.larger"); + territoryLargest = new AlleleArea("territoryLargest", new int[] {15, 13, 15}).setName("gui.largest"); + + // TREES // PLANTS + plantTypeNone = new AllelePlantType("plantTypeNone", EnumSet.noneOf(EnumPlantType.class), true); + plantTypePlains = new AllelePlantType("plantTypePlains", EnumPlantType.Plains); + ; + plantTypeDesert = new AllelePlantType("plantTypeDesert", EnumPlantType.Desert); + plantTypeBeach = new AllelePlantType("plantTypeBeach", EnumPlantType.Beach); + plantTypeCave = new AllelePlantType("plantTypeCave", EnumPlantType.Cave); + plantTypeWater = new AllelePlantType("plantTypeWater", EnumPlantType.Water); + plantTypeNether = new AllelePlantType("plantTypeNether", EnumPlantType.Nether); + plantTypeCrop = new AllelePlantType("plantTypeCrop", EnumPlantType.Crop); + + // LEGACY MAPPINGS + ILegacyHandler legacy = (ILegacyHandler) AlleleManager.alleleRegistry; + + legacy.registerLegacyMapping(0, "forestry.speciesForest"); + legacy.registerLegacyMapping(1, "forestry.speciesMeadows"); + legacy.registerLegacyMapping(2, "forestry.speciesCommon"); + legacy.registerLegacyMapping(3, "forestry.speciesCultivated"); + + legacy.registerLegacyMapping(4, "forestry.speciesNoble"); + legacy.registerLegacyMapping(5, "forestry.speciesMajestic"); + legacy.registerLegacyMapping(6, "forestry.speciesImperial"); + + legacy.registerLegacyMapping(7, "forestry.speciesDiligent"); + legacy.registerLegacyMapping(8, "forestry.speciesUnweary"); + legacy.registerLegacyMapping(9, "forestry.speciesIndustrious"); + + legacy.registerLegacyMapping(10, "forestry.speciesSteadfast"); + legacy.registerLegacyMapping(11, "forestry.speciesValiant"); + legacy.registerLegacyMapping(12, "forestry.speciesHeroic"); + + legacy.registerLegacyMapping(13, "forestry.speciesSinister"); + legacy.registerLegacyMapping(14, "forestry.speciesFiendish"); + legacy.registerLegacyMapping(15, "forestry.speciesDemonic"); + + legacy.registerLegacyMapping(16, "forestry.speciesModest"); + legacy.registerLegacyMapping(17, "forestry.speciesFrugal"); + legacy.registerLegacyMapping(18, "forestry.speciesAustere"); + + legacy.registerLegacyMapping(19, "forestry.speciesTropical"); + legacy.registerLegacyMapping(20, "forestry.speciesExotic"); + legacy.registerLegacyMapping(21, "forestry.speciesEdenic"); + + legacy.registerLegacyMapping(22, "forestry.speciesEnded"); + + legacy.registerLegacyMapping(25, "forestry.speciesWintry"); + + legacy.registerLegacyMapping(28, "forestry.speciesVindictive"); + legacy.registerLegacyMapping(29, "forestry.speciesVengeful"); + legacy.registerLegacyMapping(30, "forestry.speciesAvenging"); + + legacy.registerLegacyMapping(Defaults.ID_BEE_SPECIES_DARKENED, "forestry.speciesDarkened"); + legacy.registerLegacyMapping(Defaults.ID_BEE_SPECIES_REDDENED, "forestry.speciesReddened"); + legacy.registerLegacyMapping(Defaults.ID_BEE_SPECIES_OMEGA, "forestry.speciesOmega"); + + legacy.registerLegacyMapping(34, "forestry.speciesLeporine"); + + legacy.registerLegacyMapping(40, "forestry.speciesRural"); + + legacy.registerLegacyMapping(43, "forestry.speciesMarshy"); + + // Flowers + legacy.registerLegacyMapping(1500, "forestry.flowersVanilla"); + legacy.registerLegacyMapping(1501, "forestry.flowersNether"); + legacy.registerLegacyMapping(1502, "forestry.flowersCacti"); + legacy.registerLegacyMapping(1503, "forestry.flowersMushrooms"); + legacy.registerLegacyMapping(1504, "forestry.flowersEnd"); + legacy.registerLegacyMapping(1505, "forestry.flowersJungle"); + legacy.registerLegacyMapping(1506, "forestry.flowersSnow"); + legacy.registerLegacyMapping(1507, "forestry.flowersWheat"); + + // Effects + legacy.registerLegacyMapping(1800, "forestry.effectNone"); + legacy.registerLegacyMapping(1801, "forestry.effectAggressive"); + legacy.registerLegacyMapping(1802, "forestry.effectHeroic"); + legacy.registerLegacyMapping(1803, "forestry.effectBeatific"); + legacy.registerLegacyMapping(1804, "forestry.effectMiasmic"); + legacy.registerLegacyMapping(1805, "forestry.effectMisanthrope"); + legacy.registerLegacyMapping(1806, "forestry.effectGlacial"); + legacy.registerLegacyMapping(1807, "forestry.effectRadioactive"); + legacy.registerLegacyMapping(1808, "forestry.effectCreeper"); + legacy.registerLegacyMapping(1809, "forestry.effectIgnition"); + legacy.registerLegacyMapping(1810, "forestry.effectExploration"); + legacy.registerLegacyMapping(1811, "forestry.effectFestiveEaster"); + + // Generic + legacy.registerLegacyMapping(1024, "forestry.boolFalse"); + legacy.registerLegacyMapping(1025, "forestry.boolTrue"); + + // Speed + legacy.registerLegacyMapping(1100, "forestry.speedSlowest"); + legacy.registerLegacyMapping(1101, "forestry.speedSlower"); + legacy.registerLegacyMapping(1102, "forestry.speedSlow"); + legacy.registerLegacyMapping(1103, "forestry.speedNorm"); + legacy.registerLegacyMapping(1104, "forestry.speedFast"); + legacy.registerLegacyMapping(1105, "forestry.speedFaster"); + legacy.registerLegacyMapping(1106, "forestry.speedFastest"); + + // Lifespan + legacy.registerLegacyMapping(1200, "forestry.lifespanShortest"); + legacy.registerLegacyMapping(1201, "forestry.lifespanShorter"); + legacy.registerLegacyMapping(1202, "forestry.lifespanShort"); + legacy.registerLegacyMapping(1203, "forestry.lifespanShortened"); + legacy.registerLegacyMapping(1204, "forestry.lifespanNormal"); + legacy.registerLegacyMapping(1205, "forestry.lifespanElongated"); + legacy.registerLegacyMapping(1206, "forestry.lifespanLong"); + legacy.registerLegacyMapping(1207, "forestry.lifespanLonger"); + legacy.registerLegacyMapping(1208, "forestry.lifespanLongest"); + + // Fertility + legacy.registerLegacyMapping(1300, "forestry.fertilityLow"); + legacy.registerLegacyMapping(1301, "forestry.fertilityNormal"); + legacy.registerLegacyMapping(1302, "forestry.fertilityHigh"); + legacy.registerLegacyMapping(1303, "forestry.fertilityMaximum"); + + // Tolerance + legacy.registerLegacyMapping(1450, "forestry.toleranceNone"); + legacy.registerLegacyMapping(1451, "forestry.toleranceBoth1"); + legacy.registerLegacyMapping(1452, "forestry.toleranceBoth2"); + legacy.registerLegacyMapping(1453, "forestry.toleranceBoth3"); + legacy.registerLegacyMapping(1454, "forestry.toleranceBoth4"); + legacy.registerLegacyMapping(1455, "forestry.toleranceBoth5"); + legacy.registerLegacyMapping(1456, "forestry.toleranceUp1"); + legacy.registerLegacyMapping(1457, "forestry.toleranceUp2"); + legacy.registerLegacyMapping(1458, "forestry.toleranceUp3"); + legacy.registerLegacyMapping(1459, "forestry.toleranceUp4"); + legacy.registerLegacyMapping(1460, "forestry.toleranceUp5"); + legacy.registerLegacyMapping(1461, "forestry.toleranceDown1"); + legacy.registerLegacyMapping(1462, "forestry.toleranceDown2"); + legacy.registerLegacyMapping(1463, "forestry.toleranceDown3"); + legacy.registerLegacyMapping(1464, "forestry.toleranceDown4"); + legacy.registerLegacyMapping(1465, "forestry.toleranceDown5"); + + // Flower growth + legacy.registerLegacyMapping(1700, "forestry.floweringSlowest"); + legacy.registerLegacyMapping(1701, "forestry.floweringSlower"); + legacy.registerLegacyMapping(1702, "forestry.floweringSlow"); + legacy.registerLegacyMapping(1710, "forestry.floweringMaximum"); + + // Territory + legacy.registerLegacyMapping(1750, "forestry.territoryDefault"); + legacy.registerLegacyMapping(1751, "forestry.territoryLarge"); + legacy.registerLegacyMapping(1752, "forestry.territoryLarger"); + legacy.registerLegacyMapping(1753, "forestry.territoryLargest"); + + } + + @Override + public String getName() { + return StringUtil.localize(name); + } + + public Allele setName(String string) { + name = string; + return this; + } +} diff --git a/forestry_common/core/forestry/core/genetics/AlleleArea.java b/forestry_common/core/forestry/core/genetics/AlleleArea.java new file mode 100755 index 000000000..0b5d4a41f --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AlleleArea.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import forestry.api.genetics.IAlleleArea; +import forestry.core.utils.Vect; + +public class AlleleArea extends Allele implements IAlleleArea { + + private int[] area; + + public AlleleArea(String uid, int[] value) { + this(uid, value, false); + } + + public AlleleArea(String uid, int[] value, boolean isDominant) { + super(uid, isDominant); + this.area = value; + } + + public int[] getValue() { + return area; + } + + public Vect getArea() { + return new Vect(area); + } + +} diff --git a/forestry_common/core/forestry/core/genetics/AlleleBoolean.java b/forestry_common/core/forestry/core/genetics/AlleleBoolean.java new file mode 100755 index 000000000..cb1de069e --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AlleleBoolean.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import forestry.api.genetics.IAlleleBoolean; + +public class AlleleBoolean extends Allele implements IAlleleBoolean { + + boolean value; + boolean isDominant; + + public AlleleBoolean(String uid, boolean value) { + this(uid, value, false); + } + + public AlleleBoolean(String uid, boolean value, boolean isDominant) { + super(uid, isDominant); + this.value = value; + } + + public boolean getValue() { + return value; + } + +} diff --git a/forestry_common/core/forestry/core/genetics/AlleleFloat.java b/forestry_common/core/forestry/core/genetics/AlleleFloat.java new file mode 100755 index 000000000..6b9038033 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AlleleFloat.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import forestry.api.genetics.IAlleleFloat; + +public class AlleleFloat extends Allele implements IAlleleFloat { + + float value; + + public AlleleFloat(String uid, float value) { + this(uid, value, false); + } + + public AlleleFloat(String uid, float value, boolean isDominant) { + super(uid, isDominant); + this.value = value; + } + + @Override + public float getValue() { + return value; + } + +} diff --git a/forestry_common/core/forestry/core/genetics/AlleleInteger.java b/forestry_common/core/forestry/core/genetics/AlleleInteger.java new file mode 100755 index 000000000..6cc5568e6 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AlleleInteger.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import forestry.api.genetics.IAlleleInteger; + +public class AlleleInteger extends Allele implements IAlleleInteger { + + int value; + + public AlleleInteger(String uid, int value) { + this(uid, value, false); + } + + public AlleleInteger(String uid, int value, boolean isDominant) { + super(uid, isDominant); + this.value = value; + } + + @Override + public int getValue() { + return value; + } + +} diff --git a/forestry_common/core/forestry/core/genetics/AllelePlantType.java b/forestry_common/core/forestry/core/genetics/AllelePlantType.java new file mode 100755 index 000000000..b5b294ccb --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AllelePlantType.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.EnumSet; + +import net.minecraftforge.common.EnumPlantType; + +import forestry.api.genetics.IAllelePlantType; + +public class AllelePlantType extends Allele implements IAllelePlantType { + + private EnumSet types; + + protected AllelePlantType(String uid, EnumPlantType type) { + this(uid, type, false); + } + + protected AllelePlantType(String uid, EnumPlantType type, boolean isDominant) { + this(uid, EnumSet.of(type), isDominant); + } + + protected AllelePlantType(String uid, EnumSet types, boolean isDominant) { + super(uid, isDominant); + this.types = types; + } + + public EnumSet getPlantTypes() { + return types; + } +} diff --git a/forestry_common/core/forestry/core/genetics/AlleleRegistry.java b/forestry_common/core/forestry/core/genetics/AlleleRegistry.java new file mode 100755 index 000000000..a4a685826 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AlleleRegistry.java @@ -0,0 +1,296 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleHandler; +import forestry.api.genetics.IAlleleRegistry; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IClassification.EnumClassLevel; +import forestry.api.genetics.IFruitFamily; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.ILegacyHandler; +import forestry.api.genetics.IMutation; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.ItemResearchNote.EnumNoteType; +import forestry.core.utils.IDAllocator; + +public class AlleleRegistry implements IAlleleRegistry, ILegacyHandler { + + public static final int ALLELE_ARRAY_SIZE = 2048; + + /* SPECIES ROOT */ + private LinkedHashMap rootMap = new LinkedHashMap(16); + + @Override + public void registerSpeciesRoot(ISpeciesRoot root) { + rootMap.put(root.getUID(), root); + } + + @Override + public Map getSpeciesRoot() { + return Collections.unmodifiableMap(rootMap); + } + + @Override + public ISpeciesRoot getSpeciesRoot(String uid) { + if(rootMap.containsKey(uid)) + return rootMap.get(uid); + return null; + } + + @Override + public ISpeciesRoot getSpeciesRoot(ItemStack stack) { + for(ISpeciesRoot root : rootMap.values()) + if(root.isMember(stack)) + return root; + return null; + } + + @Override + public ISpeciesRoot getSpeciesRoot(Class clz) { + for(ISpeciesRoot root : rootMap.values()) + if(root.getMemberClass().isAssignableFrom(clz)) + return root; + return null; + } + + /* INDIVIDUALS */ + public boolean isIndividual(ItemStack stack) { + return getSpeciesRoot(stack) != null; + } + + public IIndividual getIndividual(ItemStack stack) { + ISpeciesRoot root = getSpeciesRoot(stack); + if(root == null) + return null; + + return root.getMember(stack); + } + + /* ALLELES */ + private LinkedHashMap alleleMap = new LinkedHashMap(ALLELE_ARRAY_SIZE); + private LinkedHashMap deprecatedAlleleMap = new LinkedHashMap(32); + private LinkedHashMap classificationMap = new LinkedHashMap(128); + private LinkedHashMap fruitMap = new LinkedHashMap(64); + + private HashMap metaMapToUID = new HashMap(); + private HashMap uidMapToMeta = new HashMap(); + + private HashMap legacyMap = new HashMap(); + + /* + * Internal HashSet of all alleleHandlers, which trigger when an allele or branch is registered + */ + private HashSet alleleHandlers = new HashSet(); + + public void initialize() { + + createAndRegisterClassification(EnumClassLevel.DOMAIN, "archaea", "Archaea"); + createAndRegisterClassification(EnumClassLevel.DOMAIN, "bacteria", "Bacteria"); + IClassification eukarya = createAndRegisterClassification(EnumClassLevel.DOMAIN, "eukarya", "Eukarya"); + + eukarya.addMemberGroup(createAndRegisterClassification(EnumClassLevel.KINGDOM, "animalia", "Animalia")); + eukarya.addMemberGroup(createAndRegisterClassification(EnumClassLevel.KINGDOM, "plantae", "Plantae")); + eukarya.addMemberGroup(createAndRegisterClassification(EnumClassLevel.KINGDOM, "fungi", "Fungi")); + eukarya.addMemberGroup(createAndRegisterClassification(EnumClassLevel.KINGDOM, "protista", "Protista")); + + getClassification("kingdom.animalia").addMemberGroup(createAndRegisterClassification(EnumClassLevel.PHYLUM, "arthropoda", "Arthropoda")); + + // Animalia + getClassification("phylum.arthropoda").addMemberGroup(createAndRegisterClassification(EnumClassLevel.CLASS, "insecta", "Insecta")); + + } + + @Override + public Map getRegisteredAlleles() { + return Collections.unmodifiableMap(alleleMap); + } + + @Override + public Map getDeprecatedAlleleReplacements() { + return Collections.unmodifiableMap(deprecatedAlleleMap); + } + + @Override + public void registerAllele(IAllele allele) { + alleleMap.put(allele.getUID(), allele); + if (allele instanceof IAlleleSpecies) { + IClassification branch = ((IAlleleSpecies) allele).getBranch(); + if (branch != null) + branch.addMemberSpecies((IAlleleSpecies) allele); + } + for (IAlleleHandler handler : this.alleleHandlers) + handler.onRegisterAllele(allele); + } + + @Override + public void registerDeprecatedAlleleReplacement(String deprecatedUID, IAllele replacementAllele) { + if (deprecatedAlleleMap.containsKey(deprecatedUID)) { + return; + } + + deprecatedAlleleMap.put(deprecatedUID, replacementAllele); + } + + @Override + public IAllele getAllele(String uid) { + IAllele allele = alleleMap.get(uid); + + if (allele == null) { + allele = deprecatedAlleleMap.get(uid); + } + + return allele; + } + + @Override + public void reloadMetaMap(World world) { + metaMapToUID.clear(); + uidMapToMeta.clear(); + + Iterator> it = alleleMap.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + if (!(entry.getValue() instanceof IAlleleSpecies)) + continue; + + int meta = IDAllocator.getIDAllocator(world, "speciesMetaMap").getId(entry.getKey()); + metaMapToUID.put(meta, entry.getKey()); + uidMapToMeta.put(entry.getKey(), meta); + + } + } + + @Override + public IAllele getFromMetaMap(int meta) { + if (!metaMapToUID.containsKey(meta)) + return null; + + return getAllele(metaMapToUID.get(meta)); + } + + @Override + public int getFromUIDMap(String uid) { + if (!uidMapToMeta.containsKey(uid)) + return 0; + + return uidMapToMeta.get(uid); + } + + /* CLASSIFICATIONS */ + @Override + public void registerClassification(IClassification branch) { + + if (classificationMap.containsKey(branch.getUID())) + throw new RuntimeException(String.format("Could not add new classification '%s', because the key is already taken by %s.", branch.getUID(), + classificationMap.get(branch.getUID()))); + + classificationMap.put(branch.getUID(), branch); + for (IAlleleHandler handler : this.alleleHandlers) + handler.onRegisterClassification(branch); + } + + @Override + public Map getRegisteredClassifications() { + return Collections.unmodifiableMap(classificationMap); + } + + @Override + public IClassification createAndRegisterClassification(EnumClassLevel level, String uid, String scientific) { + return new Classification(level, uid, scientific); + } + + @Override + public IClassification getClassification(String uid) { + return classificationMap.get(uid); + } + + /* FRUIT FAMILIES */ + @Override + public void registerFruitFamily(IFruitFamily family) { + fruitMap.put(family.getUID(), family); + for (IAlleleHandler handler : this.alleleHandlers) + handler.onRegisterFruitFamily(family); + } + + @Override + public Map getRegisteredFruitFamilies() { + return Collections.unmodifiableMap(fruitMap); + } + + @Override + public IFruitFamily getFruitFamily(String uid) { + return fruitMap.get(uid); + } + + /* LEGACY MAPPINGS */ + @Override + public void registerLegacyMapping(int id, String uid) { + this.legacyMap.put(id, uid); + } + + @Override + public IAllele getFromLegacyMap(int id) { + if (!legacyMap.containsKey(id)) + return null; + + return getAllele(legacyMap.get(id)); + } + + /* ALLELE HANDLERS */ + @Override + public void registerAlleleHandler(IAlleleHandler handler) { + this.alleleHandlers.add(handler); + } + + /* BLACKLIST */ + private ArrayList blacklist = new ArrayList(); + + @Override + public void blacklistAllele(String uid) { + blacklist.add(uid); + } + + @Override + public Collection getAlleleBlacklist() { + return Collections.unmodifiableCollection(blacklist); + } + + @Override + public boolean isBlacklisted(String uid) { + return blacklist.contains(uid); + } + + /* RESEARCH */ + @Override + public ItemStack getSpeciesNoteStack(String researcher, IAlleleSpecies species) { + return EnumNoteType.createSpeciesNoteStack(ForestryItem.researchNote.item(), researcher, species); + } + + @Override + public ItemStack getMutationNoteStack(String researcher, IMutation mutation) { + return EnumNoteType.createMutationNoteStack(ForestryItem.researchNote.item(), researcher, mutation); + } + +} diff --git a/forestry_common/core/forestry/core/genetics/AlleleSpecies.java b/forestry_common/core/forestry/core/genetics/AlleleSpecies.java new file mode 100755 index 000000000..14255a662 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AlleleSpecies.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.Collection; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.IIconProvider; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.core.config.ForestryItem; +import forestry.core.utils.Localization; +import forestry.core.utils.StackUtils; +import forestry.core.utils.StringUtil; + +public abstract class AlleleSpecies extends Allele implements IAlleleSpecies { + + private String name; + private String binomial; + private String description = null; + private int complexity = 3; + private boolean hasEffect = false; + private boolean isSecret = false; + private boolean isCounted = true; + private IClassification branch = null; + private EnumTemperature climate = EnumTemperature.NORMAL; + private EnumHumidity humidity = EnumHumidity.NORMAL; + + public AlleleSpecies(String uid, boolean isDominant, String name, IClassification branch, String binomial) { + super(uid, isDominant, true); + + this.branch = branch; + this.name = name; + this.binomial = binomial; + + if (Localization.instance.hasMapping("description." + uid)) + description = StringUtil.localize("description." + uid); + + AlleleManager.alleleRegistry.registerAllele(this); + } + + @Override + public String getName() { + return StringUtil.localize(name); + } + + @Override + public String getDescription() { + return description; + } + + @Override + public int getComplexity() { + return complexity; + } + + @Override + public float getResearchSuitability(ItemStack itemstack) { + if (itemstack == null) + return 0f; + + if (ForestryItem.honeyDrop.isItemEqual(itemstack)) + return 0.5f; + else if (ForestryItem.honeydew.isItemEqual(itemstack)) + return 0.7f; + else if (ForestryItem.beeComb.isItemEqual(itemstack)) + return 0.4f; + else if (AlleleManager.alleleRegistry.isIndividual(itemstack)) + return 1.0f; + + for (Map.Entry entry : getRoot().getResearchCatalysts().entrySet()) { + if (StackUtils.isIdenticalItem(entry.getKey(), itemstack)) + return entry.getValue(); + } + + return 0f; + } + + @Override + public ItemStack[] getResearchBounty(World world, String researcher, IIndividual individual, int bountyLevel) { + + ItemStack research = null; + if (world.rand.nextFloat() < ((float) 10 / bountyLevel)) { + Collection combinations = getRoot().getCombinations(this); + if (combinations.size() > 0) { + IMutation[] candidates = combinations.toArray(new IMutation[0]); + research = AlleleManager.alleleRegistry.getMutationNoteStack(researcher, candidates[world.rand.nextInt(candidates.length)]); + } + } + + if (research != null) + return new ItemStack[] { research }; + else + return StackUtils.EMPTY_STACK_ARRAY; + + } + + @Override + public EnumTemperature getTemperature() { + return climate; + } + + @Override + public EnumHumidity getHumidity() { + return humidity; + } + + @Override + public boolean hasEffect() { + return hasEffect; + } + + @Override + public boolean isSecret() { + return isSecret; + } + + @Override + public boolean isCounted() { + return isCounted; + } + + @Override + public String getBinomial() { + return binomial; + } + + @Override + public String getAuthority() { + return "Sengir"; + } + + @Override + public IClassification getBranch() { + return this.branch; + } + + public AlleleSpecies setComplexity(int complexity) { + this.complexity = complexity; + return this; + } + + public AlleleSpecies setTemperature(EnumTemperature temperature) { + climate = temperature; + return this; + } + + public AlleleSpecies setHumidity(EnumHumidity humidity) { + this.humidity = humidity; + return this; + } + + public AlleleSpecies setHasEffect() { + hasEffect = true; + return this; + } + + public AlleleSpecies setIsSecret() { + isSecret = true; + return this; + } + + public AlleleSpecies setIsNotCounted() { + isCounted = false; + return this; + } + + @Override + @SideOnly(Side.CLIENT) + public abstract IIconProvider getIconProvider(); +} diff --git a/forestry_common/core/forestry/core/genetics/AlleleTolerance.java b/forestry_common/core/forestry/core/genetics/AlleleTolerance.java new file mode 100755 index 000000000..d43b746d0 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/AlleleTolerance.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IAlleleTolerance; + +public class AlleleTolerance extends Allele implements IAlleleTolerance { + + EnumTolerance value; + + public AlleleTolerance(String uid, EnumTolerance value) { + this(uid, value, false); + } + + public AlleleTolerance(String uid, EnumTolerance value, boolean isDominant) { + super(uid, isDominant); + this.value = value; + } + + public EnumTolerance getValue() { + return value; + } + + public String getName() { + switch(value) { + case BOTH_1: + return "Both 1"; + case BOTH_2: + return "Both 2"; + case BOTH_3: + return "Both 3"; + case BOTH_4: + return "Both 4"; + case BOTH_5: + return "Both 5"; + case DOWN_1: + return "Down 1"; + case DOWN_2: + return "Down 2"; + case DOWN_3: + return "Down 3"; + case DOWN_4: + return "Down 4"; + case DOWN_5: + return "Down 5"; + case NONE: + return "None"; + case UP_1: + return "Up 1"; + case UP_2: + return "Up 2"; + case UP_3: + return "Up 3"; + case UP_4: + return "Up 4"; + case UP_5: + return "Up 5"; + default: + return ""; + + } + } + +} diff --git a/forestry_common/core/forestry/core/genetics/Branch.java b/forestry_common/core/forestry/core/genetics/Branch.java new file mode 100755 index 000000000..a13c77898 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/Branch.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +public class Branch extends Classification { + + public Branch(String uid, String scientific) { + super(EnumClassLevel.GENUS, uid, scientific); + } + +} diff --git a/forestry_common/core/forestry/core/genetics/BreedingTracker.java b/forestry_common/core/forestry/core/genetics/BreedingTracker.java new file mode 100755 index 000000000..c7ef359ea --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/BreedingTracker.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.ArrayList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.WorldSavedData; + +import net.minecraftforge.common.MinecraftForge; + +import forestry.api.core.ForestryEvent; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketNBT; +import forestry.core.proxy.Proxies; + +public abstract class BreedingTracker extends WorldSavedData implements IBreedingTracker { + + private ArrayList discoveredSpecies = new ArrayList(); + private ArrayList discoveredMutations = new ArrayList(); + private String modeName; + + String username; + + public BreedingTracker(String s, String username) { + super(s); + this.username = username; + } + + @Override + public String getModeName() { + return modeName; + } + + @Override + public void setModeName(String name) { + this.modeName = name; + markDirty(); + } + + /** + * Returns the common tracker + * + * @param player + * used to get worldObj + * @return common tracker for this breeding system + */ + protected abstract IBreedingTracker getCommonTracker(EntityPlayer player); + + /** + * Tag stored in NBT to identify the type of the tracker being synced + */ + protected abstract String getPacketTag(); + + @Override + public void synchToPlayer(EntityPlayer player) { + setModeName(getCommonTracker(player).getModeName()); + NBTTagCompound nbttagcompound = new NBTTagCompound(); + encodeToNBT(nbttagcompound); + Proxies.net.sendToPlayer(new PacketNBT(PacketIds.GENOME_TRACKER_UPDATE, nbttagcompound), player); + } + + /* HELPER FUNCTIONS TO PREVENT OBFUSCATION OF INTERFACE METHODS */ + @Override + public void decodeFromNBT(NBTTagCompound nbttagcompound) { + readFromNBT(nbttagcompound); + } + + @Override + public void encodeToNBT(NBTTagCompound nbttagcompound) { + writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + if (nbttagcompound.hasKey("BMS")) + modeName = nbttagcompound.getString("BMS"); + + // / SPECIES + discoveredSpecies = new ArrayList(); + int count = nbttagcompound.getInteger("SpeciesCount"); + for (int i = 0; i < count; i++) + discoveredSpecies.add(nbttagcompound.getString("SD" + i)); + + // / MUTATIONS + discoveredMutations = new ArrayList(); + count = nbttagcompound.getInteger("MutationsCount"); + for (int i = 0; i < count; i++) + discoveredMutations.add(nbttagcompound.getString("MD" + i)); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + if (modeName != null && !modeName.isEmpty()) + nbttagcompound.setString("BMS", modeName); + + nbttagcompound.setString("TYPE", getPacketTag()); + + // / SPECIES + nbttagcompound.setInteger("SpeciesCount", discoveredSpecies.size()); + for (int i = 0; i < discoveredSpecies.size(); i++) + if (discoveredSpecies.get(i) != null) + nbttagcompound.setString("SD" + i, discoveredSpecies.get(i)); + + // / MUTATIONS + nbttagcompound.setInteger("MutationsCount", discoveredMutations.size()); + for (int i = 0; i < discoveredMutations.size(); i++) + if (discoveredMutations.get(i) != null) + nbttagcompound.setString("MD" + i, discoveredMutations.get(i)); + + } + + private static final String MUTATION_FORMAT = "%s-%s=%s"; + @Override + public void registerMutation(IMutation mutation) { + discoveredMutations.add(String.format(MUTATION_FORMAT, mutation.getAllele0().getUID(), mutation.getAllele1().getUID(), mutation.getTemplate()[0].getUID())); + markDirty(); + MinecraftForge.EVENT_BUS.post(new ForestryEvent.MutationDiscovered( + AlleleManager.alleleRegistry.getSpeciesRoot(this.getPacketTag()), + username, + mutation, this)); + } + + @Override + public void registerMutation(IAllele allele0, IAllele allele1) { + discoveredMutations.add(allele0.getUID() + "-" + allele1.getUID()); + markDirty(); + } + + @Override + public boolean isDiscovered(IMutation mutation) { + return discoveredMutations.contains(String.format(MUTATION_FORMAT, mutation.getAllele0().getUID(), mutation.getAllele1().getUID(), mutation.getTemplate()[0].getUID())) + || discoveredMutations.contains(mutation.getAllele0().getUID() + "-" + mutation.getAllele1().getUID()); + } + + @Override + public boolean isDiscovered(IAlleleSpecies species) { + return discoveredSpecies.contains(species.getUID()); + } + + @Override + public int getSpeciesBred() { + return discoveredSpecies.size(); + } + + @Override + public void registerBirth(IIndividual individual) { + registerSpecies(individual.getGenome().getPrimary()); + registerSpecies(individual.getGenome().getSecondary()); + } + + @Override + public void registerSpecies(IAlleleSpecies species) { + if (!discoveredSpecies.contains(species.getUID())) { + discoveredSpecies.add(species.getUID()); + MinecraftForge.EVENT_BUS.post(new ForestryEvent.SpeciesDiscovered( + AlleleManager.alleleRegistry.getSpeciesRoot(this.getPacketTag()), + username, + species, this)); + } + } + +} diff --git a/forestry_common/core/forestry/core/genetics/Chromosome.java b/forestry_common/core/forestry/core/genetics/Chromosome.java new file mode 100755 index 000000000..95ee20bba --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/Chromosome.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.Random; + +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.ILegacyHandler; + +public class Chromosome implements IChromosome { + + private static final String UID0_TAG = "UID0"; + private static final String UID1_TAG = "UID1"; + + private IAllele primary; + private IAllele secondary; + + // / CONSTRUCTOR + private Chromosome() { + } + + public Chromosome(IAllele allele) { + primary = secondary = allele; + } + + public Chromosome(IAllele primary, IAllele secondary) { + this.primary = primary; + this.secondary = secondary; + } + + // / SAVING & LOADING + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + // Legacy + if (nbttagcompound.hasKey("PrimaryId")) { + primary = ((ILegacyHandler) AlleleManager.alleleRegistry).getFromLegacyMap(nbttagcompound.getInteger("PrimaryId")); + secondary = ((ILegacyHandler) AlleleManager.alleleRegistry).getFromLegacyMap(nbttagcompound.getInteger("SecondaryId")); + + if (primary == null || secondary == null) + throw new RuntimeException("Legacy conversion of chromosome failed. Did one of your bee addons not update? No legacy mapping for ids: " + + nbttagcompound.getInteger("PrimaryId") + " - " + nbttagcompound.getInteger("SecondaryId")); + + return; + } + + primary = AlleleManager.alleleRegistry.getAllele(nbttagcompound.getString(UID0_TAG)); + secondary = AlleleManager.alleleRegistry.getAllele(nbttagcompound.getString(UID1_TAG)); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + nbttagcompound.setString(UID0_TAG, primary.getUID()); + nbttagcompound.setString(UID1_TAG, secondary.getUID()); + } + + @Override + public IAllele getPrimaryAllele() { + return primary; + } + + @Override + public IAllele getSecondaryAllele() { + return secondary; + } + + @Override + public IAllele getActiveAllele() { + if (primary.isDominant()) + return primary; + if (secondary.isDominant()) + return secondary; + // Leaves only the case of both being recessive + return primary; + } + + @Override + public IAllele getInactiveAllele() { + if (!secondary.isDominant()) + return secondary; + if (!primary.isDominant()) + return primary; + // Leaves only the case of both being dominant + return secondary; + } + + public IAllele getRandomAllele(Random rand) { + if (rand.nextBoolean()) + return primary; + else + return secondary; + } + + public void overrideInvalidAlleles(IAllele template, Class chromosomeClass) { + if (primary == null || !chromosomeClass.isInstance(primary)) + primary = template; + if (secondary == null || !chromosomeClass.isInstance(secondary)) + secondary = template; + } + + /* HELPER FUNCTIONS */ + public static Chromosome loadChromosomeFromNBT(NBTTagCompound compound) { + Chromosome chromosome = new Chromosome(); + chromosome.readFromNBT(compound); + return chromosome; + } + + public static IChromosome inheritChromosome(Random rand, IChromosome parent1, IChromosome parent2) { + + IAllele choice1; + if (rand.nextBoolean()) + choice1 = parent1.getPrimaryAllele(); + else + choice1 = parent1.getSecondaryAllele(); + + IAllele choice2; + if (rand.nextBoolean()) + choice2 = parent2.getPrimaryAllele(); + else + choice2 = parent2.getSecondaryAllele(); + + if (rand.nextBoolean()) + return new Chromosome(choice1, choice2); + else + return new Chromosome(choice2, choice1); + } + +} diff --git a/forestry_common/core/forestry/core/genetics/Classification.java b/forestry_common/core/forestry/core/genetics/Classification.java new file mode 100755 index 000000000..fdcdaf480 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/Classification.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.ArrayList; +import java.util.Locale; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IClassification; +import forestry.core.utils.StringUtil; + +public class Classification implements IClassification { + + private EnumClassLevel level; + private String uid; + private String scientific; + + private IClassification parent; + + private ArrayList members = new ArrayList(); + private ArrayList groups = new ArrayList(); + + public Classification(EnumClassLevel level, String uid, String scientific) { + this.level = level; + this.uid = level.name().toLowerCase(Locale.ENGLISH) + "." + uid; + this.scientific = scientific; + AlleleManager.alleleRegistry.registerClassification(this); + } + + @Override + public EnumClassLevel getLevel() { + return level; + } + + @Override + public String getUID() { + return uid; + } + + @Override + public IClassification getParent() { + return parent; + } + + @Override + public void setParent(IClassification parent) { + this.parent = parent; + } + + @Override + public String getScientific() { + return this.scientific; + } + + @Override + public String getName() { + return StringUtil.localize(uid); + } + + @Override + public String getDescription() { + return StringUtil.localize(uid + ".description"); + } + + @Override + public IClassification[] getMemberGroups() { + return groups.toArray(new IClassification[0]); + } + + @Override + public void addMemberGroup(IClassification group) { + groups.add(group); + group.setParent(this); + } + + @Override + public IAlleleSpecies[] getMemberSpecies() { + return members.toArray(new IAlleleSpecies[0]); + } + + @Override + public void addMemberSpecies(IAlleleSpecies species) { + members.add(species); + } + +} diff --git a/forestry_common/core/forestry/core/genetics/ClimateHelper.java b/forestry_common/core/forestry/core/genetics/ClimateHelper.java new file mode 100755 index 000000000..15b726f0a --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/ClimateHelper.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.ArrayList; +import java.util.Locale; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.EnumTolerance; +import forestry.core.utils.StringUtil; + +public class ClimateHelper { + + public static boolean isWithinLimits(EnumTemperature temperature, EnumHumidity humidity, + EnumTemperature baseTemp, EnumTolerance tolTemp, + EnumHumidity baseHumid, EnumTolerance tolHumid) { + if(!getToleratedTemperature(baseTemp, tolTemp).contains(temperature)) + return false; + + return getToleratedHumidity(baseHumid, tolHumid).contains(humidity); + } + + public static ArrayList getToleratedHumidity(EnumHumidity prefered, EnumTolerance tolerance) { + + ArrayList tolerated = new ArrayList(); + tolerated.add(prefered); + + switch (tolerance) { + + case BOTH_5: + case BOTH_4: + case BOTH_3: + case BOTH_2: + if (prefered.ordinal() + 2 < EnumHumidity.values().length) + tolerated.add(EnumHumidity.values()[prefered.ordinal() + 2]); + if (prefered.ordinal() - 2 >= 0) + tolerated.add(EnumHumidity.values()[prefered.ordinal() - 2]); + case BOTH_1: + if (prefered.ordinal() + 1 < EnumHumidity.values().length) + tolerated.add(EnumHumidity.values()[prefered.ordinal() + 1]); + if (prefered.ordinal() - 1 >= 0) + tolerated.add(EnumHumidity.values()[prefered.ordinal() - 1]); + return tolerated; + + case UP_5: + case UP_4: + case UP_3: + case UP_2: + if (prefered.ordinal() + 2 < EnumHumidity.values().length) + tolerated.add(EnumHumidity.values()[prefered.ordinal() + 2]); + case UP_1: + if (prefered.ordinal() + 1 < EnumHumidity.values().length) + tolerated.add(EnumHumidity.values()[prefered.ordinal() + 1]); + return tolerated; + + case DOWN_5: + case DOWN_4: + case DOWN_3: + case DOWN_2: + if (prefered.ordinal() - 2 >= 0) + tolerated.add(EnumHumidity.values()[prefered.ordinal() - 2]); + case DOWN_1: + if (prefered.ordinal() - 1 >= 0) + tolerated.add(EnumHumidity.values()[prefered.ordinal() - 1]); + return tolerated; + + default: + return tolerated; + } + + } + + public static ArrayList getToleratedTemperature(EnumTemperature prefered, EnumTolerance tolerance) { + + ArrayList tolerated = new ArrayList(); + tolerated.add(prefered); + + switch (tolerance) { + + case BOTH_5: + if (prefered.ordinal() + 5 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 5]); + if (prefered.ordinal() - 5 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 5]); + case BOTH_4: + if (prefered.ordinal() + 4 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 4]); + if (prefered.ordinal() - 4 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 4]); + case BOTH_3: + if (prefered.ordinal() + 3 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 3]); + if (prefered.ordinal() - 3 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 3]); + case BOTH_2: + if (prefered.ordinal() + 2 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 2]); + if (prefered.ordinal() - 2 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 2]); + case BOTH_1: + if (prefered.ordinal() + 1 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 1]); + if (prefered.ordinal() - 1 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 1]); + return tolerated; + + case UP_5: + if (prefered.ordinal() + 5 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 5]); + case UP_4: + if (prefered.ordinal() + 4 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 4]); + case UP_3: + if (prefered.ordinal() + 3 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 3]); + case UP_2: + if (prefered.ordinal() + 2 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 2]); + case UP_1: + if (prefered.ordinal() + 1 < EnumTemperature.values().length) + tolerated.add(EnumTemperature.values()[prefered.ordinal() + 1]); + return tolerated; + + case DOWN_5: + if (prefered.ordinal() - 5 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 5]); + case DOWN_4: + if (prefered.ordinal() - 4 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 4]); + case DOWN_3: + if (prefered.ordinal() - 3 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 3]); + case DOWN_2: + if (prefered.ordinal() - 2 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 2]); + case DOWN_1: + if (prefered.ordinal() - 1 >= 0) + tolerated.add(EnumTemperature.values()[prefered.ordinal() - 1]); + return tolerated; + + default: + return tolerated; + } + } + + public static String toDisplay(EnumTemperature temperature) { + return StringUtil.localize("gui." + temperature.toString().toLowerCase(Locale.ENGLISH)); + } + + public static String toDisplay(EnumHumidity humidity) { + return StringUtil.localize("gui." + humidity.toString().toLowerCase(Locale.ENGLISH)); + } +} diff --git a/forestry_common/core/forestry/core/genetics/EffectData.java b/forestry_common/core/forestry/core/genetics/EffectData.java new file mode 100755 index 000000000..71bece2d6 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/EffectData.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.genetics.IEffectData; + +public class EffectData implements IEffectData { + + private int[] intData; + private float[] floatData; + private boolean[] boolData; + + public EffectData(int intSize, int boolSize) { + this.intData = new int[intSize]; + this.boolData = new boolean[boolSize]; + } + + @Override + public void setInteger(int index, int val) { + intData[index] = val; + } + + @Override + public void setBoolean(int index, boolean val) { + boolData[index] = val; + } + + @Override + public int getInteger(int index) { + return intData[index]; + } + + @Override + public boolean getBoolean(int index) { + return boolData[index]; + } + + public int getIntSize() { + return intData.length; + } + + @Override + public void setFloat(int index, float val) { + floatData[index] = val; + } + + @Override + public float getFloat(int index) { + return floatData[index]; + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + } +} diff --git a/forestry_common/core/forestry/core/genetics/EnumMutateChance.java b/forestry_common/core/forestry/core/genetics/EnumMutateChance.java new file mode 100755 index 000000000..fe87c3eea --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/EnumMutateChance.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +public enum EnumMutateChance { + NONE(0xffffff), LOWEST(0xffba77), LOW(0xfffd77), NORMAL(0xfffd77), HIGH(0xfffd77), HIGHER(0xbeff77), HIGHEST(0x7bff77); + + public final int colour; + + private EnumMutateChance(int colour) { + this.colour = colour; + } + + public static EnumMutateChance rateChance(float percent) { + + if (percent >= 20) + return HIGHEST; + else if (percent >= 15) + return HIGHER; + else if (percent >= 12) + return HIGH; + else if (percent >= 10) + return NORMAL; + else if (percent >= 5) + return LOW; + else + return LOWEST; + + } +} diff --git a/forestry_common/core/forestry/core/genetics/FruitFamily.java b/forestry_common/core/forestry/core/genetics/FruitFamily.java new file mode 100755 index 000000000..52a1845e5 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/FruitFamily.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IFruitFamily; +import forestry.core.utils.StringUtil; + +public class FruitFamily implements IFruitFamily { + + private String uid; + private String scientific; + + public FruitFamily(String uid, String scientific) { + this.uid = uid; + this.scientific = scientific; + AlleleManager.alleleRegistry.registerFruitFamily(this); + } + + @Override + public String getUID() { + return "forestry." + uid; + } + + @Override + public String getScientific() { + return this.scientific; + } + + @Override + public String getName() { + return StringUtil.localize("family." + uid); + } + + @Override + public String getDescription() { + return null; + } + +} diff --git a/forestry_common/core/forestry/core/genetics/GenericRatings.java b/forestry_common/core/forestry/core/genetics/GenericRatings.java new file mode 100755 index 000000000..95ec88a88 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/GenericRatings.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import forestry.core.utils.StringUtil; + +public class GenericRatings { + + public static String rateMetabolism(int metabolism) { + if (metabolism >= 19) + return StringUtil.localize("gui.highest"); + else if (metabolism >= 16) + return StringUtil.localize("gui.higher"); + else if (metabolism >= 13) + return StringUtil.localize("gui.high"); + else if (metabolism >= 10) + return StringUtil.localize("gui.average"); + else if (metabolism >= 7) + return StringUtil.localize("gui.slow"); + else if (metabolism >= 4) + return StringUtil.localize("gui.slower"); + else + return StringUtil.localize("gui.slowest"); + } + + public static String rateActivityTime(boolean nocturnalTrait, boolean naturalNocturnal) { + String active = naturalNocturnal ? StringUtil.localize("gui.nocturnal") : StringUtil.localize("gui.diurnal"); + if(nocturnalTrait) + active = StringUtil.append(", ", active, naturalNocturnal ? StringUtil.localize("gui.diurnal") : StringUtil.localize("gui.nocturnal")); + + return active; + } +} diff --git a/forestry_common/core/forestry/core/genetics/Genome.java b/forestry_common/core/forestry/core/genetics/Genome.java new file mode 100755 index 000000000..616549576 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/Genome.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IGenome; +import forestry.core.config.Config; + +public abstract class Genome implements IGenome { + + private static final String SLOT_TAG = "Slot"; + + private IChromosome[] chromosomes; + + // / CONSTRUCTOR + public Genome(NBTTagCompound nbttagcompound) { + this.chromosomes = new Chromosome[getDefaultTemplate().length]; + readFromNBT(nbttagcompound); + } + + private IAllele[] getDefaultTemplate() { + return getSpeciesRoot().getDefaultTemplate(); + } + + public Genome(IChromosome[] chromosomes) { + if(chromosomes.length != getDefaultTemplate().length) + throw new IllegalArgumentException(String.format("Tried to create a genome for '%s' from an invalid chromosome template.", getSpeciesRoot().getUID())); + this.chromosomes = chromosomes; + } + + // / SAVING & LOADING + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = nbttagcompound.getTagList("Chromosomes", 10); + chromosomes = new Chromosome[chromosomes.length]; + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + byte byte0 = nbttagcompound1.getByte(SLOT_TAG); + if (byte0 >= 0 && byte0 < chromosomes.length) { + Chromosome chromosome = Chromosome.loadChromosomeFromNBT(nbttagcompound1); + chromosomes[byte0] = chromosome; + if (Config.clearInvalidChromosomes) + chromosome.overrideInvalidAlleles(getDefaultTemplate()[byte0], getSpeciesRoot().getKaryotype()[byte0].getAlleleClass()); + } + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = new NBTTagList(); + for (int i = 0; i < chromosomes.length; i++) + if (chromosomes[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte(SLOT_TAG, (byte) i); + chromosomes[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("Chromosomes", nbttaglist); + + } + + // / INFORMATION RETRIEVAL + @Override + public IChromosome[] getChromosomes() { + return chromosomes; + } + + @Override + public IAllele getActiveAllele(int chromosome) { + return chromosomes[chromosome].getActiveAllele(); + } + + @Override + public IAllele getInactiveAllele(int chromosome) { + return chromosomes[chromosome].getInactiveAllele(); + } + + @Override + public boolean isGeneticEqual(IGenome other) { + IChromosome[] genetics = other.getChromosomes(); + if (chromosomes.length != genetics.length) + return false; + + for (int i = 0; i < chromosomes.length; i++) { + IChromosome chromosome = chromosomes[i]; + if (chromosome == null && genetics[i] != null) + return false; + if (chromosome != null && genetics[i] == null) + return false; + if (chromosome == null && genetics[i] == null) + continue; + + if (!chromosome.getPrimaryAllele().getUID().equals(genetics[i].getPrimaryAllele().getUID())) + return false; + if (!chromosome.getSecondaryAllele().getUID().equals(genetics[i].getSecondaryAllele().getUID())) + return false; + } + + return true; + } +} diff --git a/forestry_common/core/forestry/core/genetics/Individual.java b/forestry_common/core/forestry/core/genetics/Individual.java new file mode 100755 index 000000000..50f79f35d --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/Individual.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.genetics.IIndividual; + +public abstract class Individual implements IIndividual { + + protected boolean isAnalyzed = false; + + @Override + public boolean isAnalyzed() { + return isAnalyzed; + } + + @Override + public boolean analyze() { + if (isAnalyzed) + return false; + + isAnalyzed = true; + return true; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + if (nbttagcompound == null) + return; + + isAnalyzed = nbttagcompound.getBoolean("IsAnalyzed"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + nbttagcompound.setBoolean("IsAnalyzed", isAnalyzed); + } + + /* IDENTIFICATION */ + @Override + public String getIdent() { + return getGenome().getPrimary().getUID(); + } + + @Override + public String getDisplayName() { + return getGenome().getPrimary().getName(); + } + + /* INFORMATION */ + @Override + public boolean hasEffect() { + return getGenome().getPrimary().hasEffect(); + } + + @Override + public boolean isSecret() { + return getGenome().getPrimary().isSecret(); + } + + @Override + public boolean isGeneticEqual(IIndividual other) { + return getGenome().isGeneticEqual(other.getGenome()); + } + + @Override + public boolean isPureBred(int chromosomeOrdinal) { + return getGenome().getActiveAllele(chromosomeOrdinal).getUID().equals(getGenome().getInactiveAllele(chromosomeOrdinal).getUID()); + } + +} diff --git a/forestry_common/core/forestry/core/genetics/IndividualLiving.java b/forestry_common/core/forestry/core/genetics/IndividualLiving.java new file mode 100755 index 000000000..1898a7246 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/IndividualLiving.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.genetics.IGenome; +import forestry.api.genetics.IIndividualLiving; + +public abstract class IndividualLiving extends Individual implements IIndividualLiving { + + protected int generation; + protected boolean isNatural; + protected boolean isIrregularMating; + + protected int health; + protected int maxHealth; + + public IndividualLiving() {} + + public IndividualLiving(int newHealth, boolean isNatural, int generation) { + health = maxHealth = newHealth; + this.isNatural = isNatural; + this.generation = generation; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("NA")) + isNatural = nbttagcompound.getBoolean("NA"); + else + isNatural = true; + isIrregularMating = nbttagcompound.getBoolean("IM"); + generation = nbttagcompound.getInteger("GEN"); + + health = nbttagcompound.getInteger("Health"); + maxHealth = nbttagcompound.getInteger("MaxH"); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + super.writeToNBT(nbttagcompound); + + nbttagcompound.setBoolean("NA", isNatural); + nbttagcompound.setBoolean("IM", isIrregularMating); + nbttagcompound.setInteger("GEN", generation); + + nbttagcompound.setInteger("Health", health); + nbttagcompound.setInteger("MaxH", maxHealth); + + if (getGenome() != null) { + NBTTagCompound NBTmachine = new NBTTagCompound(); + getGenome().writeToNBT(NBTmachine); + nbttagcompound.setTag("Genome", NBTmachine); + } + if (getMate() != null) { + NBTTagCompound NBTmachine = new NBTTagCompound(); + getMate().writeToNBT(NBTmachine); + nbttagcompound.setTag("Mate", NBTmachine); + } + + } + + /* GENERATION */ + public abstract IGenome getMate(); + + public void setIsNatural(boolean flag) { + this.isNatural = flag; + } + + public boolean isIrregularMating() { + return this.isIrregularMating; + } + + public boolean isNatural() { + return this.isNatural; + } + + public int getGeneration() { + return generation; + } + + @Override + public boolean isAlive() { + return health > 0; + } + + @Override + public int getHealth() { + return health; + } + + @Override + public int getMaxHealth() { + return this.maxHealth; + } + + @Override + public void age(World world, float lifespanModifier) { + + if (lifespanModifier < 0.001f) { + this.health = 0; + return; + } + + float ageModifier = 1.0f / lifespanModifier; + + while (ageModifier > 1.0f) { + decreaseHealth(); + ageModifier--; + } + if (world.rand.nextFloat() < ageModifier) + decreaseHealth(); + + } + + public void decreaseHealth() { + if (health > 0) + health--; + } + + +} diff --git a/forestry_common/core/forestry/core/genetics/ItemGE.java b/forestry_common/core/forestry/core/genetics/ItemGE.java new file mode 100755 index 000000000..dcdbf22d5 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/ItemGE.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IIndividual; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StringUtil; + +public abstract class ItemGE extends Item { + + protected ItemGE() { + super(); + // maxStackSize = 1; + hasSubtypes = true; + } + + protected abstract int getDefaultPrimaryColour(); + + protected abstract int getDefaultSecondaryColour(); + + protected abstract IIndividual getIndividual(ItemStack itemstack); + + @Override + public boolean isDamageable() { + return false; + } + + @Override + public boolean isRepairable() { + return false; + } + + @Override + public boolean getShareTag() { + return true; + } + + @Override + public boolean hasEffect(ItemStack itemstack) { + if (!itemstack.hasTagCompound()) + return false; + + IIndividual individual = getIndividual(itemstack); + return individual.hasEffect(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + if(!itemstack.hasTagCompound()) + return; + + IIndividual individual = getIndividual(itemstack); + + if(individual.isAnalyzed()) { + if(Proxies.common.isShiftDown()) + individual.addTooltip(list); + else + list.add("\u00A7o<" + StringUtil.localize("gui.tooltip.tmi") + ">"); + } else + list.add("<" + StringUtil.localize("gui.unknown") + ">"); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister par1IconRegister) { + // Need to disable normal registration. + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int renderPass) { + + if (renderPass == 0) + return getDefaultPrimaryColour(); + else if (renderPass == 1) + return getDefaultSecondaryColour(); + else + return 0xffffff; + + } + + public int getColourFromSpecies(IAlleleSpecies species, int renderPass) { + return 0xffffff; + } + +} diff --git a/forestry_common/core/forestry/core/genetics/ItemResearchNote.java b/forestry_common/core/forestry/core/genetics/ItemResearchNote.java new file mode 100755 index 000000000..5ca0faf2b --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/ItemResearchNote.java @@ -0,0 +1,264 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IMutation; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.items.ItemForestry; +import forestry.core.proxy.Proxies; + +public class ItemResearchNote extends ItemForestry { + + public static enum EnumNoteType { + NONE, MUTATION, SPECIES; + + public static EnumNoteType[] VALUES = values(); + + private IMutation getEncodedMutation(ISpeciesRoot root, NBTTagCompound compound) { + IAllele allele0 = AlleleManager.alleleRegistry.getAllele(compound.getString("AL0")); + IAllele allele1 = AlleleManager.alleleRegistry.getAllele(compound.getString("AL1")); + if(allele0 == null || allele1 == null) + return null; + + IAllele result = null; + if(compound.hasKey("RST")) + result = AlleleManager.alleleRegistry.getAllele(compound.getString("RST")); + + IMutation encoded = null; + for(IMutation mutation : root.getCombinations(allele0)) + if(mutation.isPartner(allele1)) { + if(result == null + || mutation.getTemplate()[0].getUID().equals(result.getUID())) { + encoded = mutation; + break; + } + } + + return encoded; + } + + public ArrayList getTooltip(NBTTagCompound compound) { + ArrayList tooltips = new ArrayList(); + + if(compound == null || this == NONE) + return tooltips; + + if(this == MUTATION) { + ISpeciesRoot root = AlleleManager.alleleRegistry.getSpeciesRoot(compound.getString("ROT")); + if(root == null) + return tooltips; + + IMutation encoded = getEncodedMutation(root, compound); + if(encoded == null) + return tooltips; + + tooltips.add("\u00A7aMutation discovered!"); + tooltips.add(String.format("\u00A7e'%s'\u00A77 and \u00A7e'%s'\u00A77.", encoded.getAllele0().getName(), encoded.getAllele1().getName())); + tooltips.add(String.format("Chance for success is \u00A79%s\u00A77.", EnumMutateChance.rateChance(encoded.getBaseChance()))); + tooltips.add(String.format("New species is \u00A7d'%s'\u00A77.", (encoded.getTemplate()[root.getKaryotypeKey().ordinal()].getName()))); + + if(encoded.getSpecialConditions() != null && encoded.getSpecialConditions().size() > 0) { + for(String line : encoded.getSpecialConditions()) + tooltips.add("\u00A76" + line); + } + } else if(this == SPECIES) { + IAlleleSpecies allele0 = (IAlleleSpecies)AlleleManager.alleleRegistry.getAllele(compound.getString("AL0")); + if(allele0 == null) + return tooltips; + ISpeciesRoot root = AlleleManager.alleleRegistry.getSpeciesRoot(compound.getString("ROT")); + if(root == null) + return tooltips; + + tooltips.add("\u00A7aSpecies researched!"); + tooltips.add(String.format("\u00A7e'%s'\u00A77 (%s)", allele0.getName(), allele0.getBinomial())); + } + + return tooltips; + } + + public boolean registerResults(World world, EntityPlayer player, NBTTagCompound compound) { + if(compound == null || this == NONE) + return false; + + if(this == MUTATION) { + ISpeciesRoot root = AlleleManager.alleleRegistry.getSpeciesRoot(compound.getString("ROT")); + if(root == null) + return false; + + IMutation encoded = getEncodedMutation(root, compound); + if(encoded == null) + return false; + + IBreedingTracker tracker = encoded.getRoot().getBreedingTracker(world, player.getGameProfile().getId()); + if(tracker.isDiscovered(encoded)) { + player.addChatMessage(new ChatComponentTranslation("chat.cannotmemorizeagain")); + return false; + } + + tracker.registerSpecies((IAlleleSpecies)encoded.getAllele0()); + tracker.registerSpecies((IAlleleSpecies)encoded.getAllele1()); + tracker.registerSpecies((IAlleleSpecies)encoded.getTemplate()[root.getKaryotypeKey().ordinal()]); + tracker.registerMutation(encoded); + player.addChatMessage(new ChatComponentTranslation("chat.memorizednote")); + return true; + } + + return false; + + } + + public static ResearchNote createMutationNote(String researcher, IMutation mutation) { + NBTTagCompound compound = new NBTTagCompound(); + compound.setString("ROT", mutation.getRoot().getUID()); + compound.setString("AL0", mutation.getAllele0().getUID()); + compound.setString("AL1", mutation.getAllele1().getUID()); + compound.setString("RST", mutation.getTemplate()[0].getUID()); + return new ResearchNote(researcher, MUTATION, compound); + } + + public static ItemStack createMutationNoteStack(Item item, String researcher, IMutation mutation) { + ResearchNote note = createMutationNote(researcher, mutation); + NBTTagCompound compound = new NBTTagCompound(); + note.writeToNBT(compound); + ItemStack created = new ItemStack(item); + created.setTagCompound(compound); + return created; + } + + public static ResearchNote createSpeciesNote(String researcher, IAlleleSpecies species) { + NBTTagCompound compound = new NBTTagCompound(); + compound.setString("ROT", species.getRoot().getUID()); + compound.setString("AL0", species.getUID()); + return new ResearchNote(researcher, SPECIES, compound); + } + + public static ItemStack createSpeciesNoteStack(Item item, String researcher, IAlleleSpecies species) { + ResearchNote note = createSpeciesNote(researcher, species); + NBTTagCompound compound = new NBTTagCompound(); + note.writeToNBT(compound); + ItemStack created = new ItemStack(item); + created.setTagCompound(compound); + return created; + } + + } + + public static class ResearchNote { + + private String researcher = "fdssffd"; + private EnumNoteType type = EnumNoteType.NONE; + private NBTTagCompound inner; + + public ResearchNote(String researcher, EnumNoteType type, NBTTagCompound inner) { + this.researcher = researcher; + this.type = type; + this.inner = inner; + } + + public ResearchNote(NBTTagCompound compound) { + if(compound != null) { + this.researcher = compound.getString("RES"); + this.type = EnumNoteType.VALUES[compound.getByte("TYP")]; + this.inner = compound.getCompoundTag("INN"); + } else + this.inner = new NBTTagCompound(); + } + + public void writeToNBT(NBTTagCompound compound) { + compound.setString("RES", researcher); + compound.setByte("TYP", (byte)type.ordinal()); + compound.setTag("INN", inner); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void addTooltip(List list) { + ArrayList tooltips = type.getTooltip(inner); + if(tooltips.size() <= 0) { + list.add("\u00A7o\u00A7cIt is impossible to decipher the washed out scribbles."); + list.add("The note has become unreadable and is worthless."); + return; + } + + list.addAll(tooltips); + } + + public boolean registerResults(World world, EntityPlayer player) { + return type.registerResults(world, player, inner); + } + } + + public ItemResearchNote() { + super(); + setCreativeTab(null); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + ResearchNote note = new ResearchNote(itemstack.getTagCompound()); + return String.format("%s's Notes", note.researcher); + } + + @SuppressWarnings("rawtypes") + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + ResearchNote note = new ResearchNote(itemstack.getTagCompound()); + note.addTooltip(list); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(world)) + return itemstack; + + ResearchNote note = new ResearchNote(itemstack.getTagCompound()); + if(note.registerResults(world, entityplayer)) { + entityplayer.inventory.decrStackSize(entityplayer.inventory.currentItem, 1); + // Notify player that his inventory has changed. + Proxies.net.inventoryChangeNotify(entityplayer); + } + + return itemstack; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int j) { + return 0xffe8a5; + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamage(int meta) { + return Items.paper.getIconFromDamage(0); + } +} diff --git a/forestry_common/core/forestry/core/genetics/Mutation.java b/forestry_common/core/forestry/core/genetics/Mutation.java new file mode 100755 index 000000000..2d912bf22 --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/Mutation.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + + +import java.util.ArrayList; +import java.util.Collection; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IMutation; + +public abstract class Mutation implements IMutation { + + protected int chance; + boolean isSecret = false; + + protected IAllele allele0; + protected IAllele allele1; + + IAllele[] template; + + protected float minTemperature = 0.0f; + protected float maxTemperature = 2.0f; + protected float minRainfall = 0.0f; + protected float maxRainfall = 2.0f; + + protected ArrayList specialConditions = new ArrayList(); + + public Mutation(IAllele allele0, IAllele allele1, IAllele[] template, int chance) { + this.allele0 = allele0; + this.allele1 = allele1; + this.template = template; + this.chance = chance; + } + + + public Mutation setSpecialConditions(Collection conditions) { + specialConditions.addAll(conditions); + return this; + } + + public Collection getSpecialConditions() { + return specialConditions; + } + + public Mutation setIsSecret() { + isSecret = true; + return this; + } + + public Mutation setTemperature(float minTemperature, float maxTemperature) { + this.minTemperature = minTemperature; + this.maxTemperature = maxTemperature; + + EnumTemperature temp1 = EnumTemperature.getFromValue(minTemperature); + EnumTemperature temp2 = EnumTemperature.getFromValue(maxTemperature); + if(temp1 != temp2) + specialConditions.add(String.format("Temperature between %s and %s.", temp1, temp2)); + else + specialConditions.add(String.format("Temperature %s required.", temp1)); + return this; + } + + public Mutation setRainfall(float minRainfall, float maxRainfall) { + this.minRainfall = minRainfall; + this.maxRainfall = maxRainfall; + + EnumHumidity temp1 = EnumHumidity.getFromValue(minRainfall); + EnumHumidity temp2 = EnumHumidity.getFromValue(maxRainfall); + + if(temp1 != temp2) + specialConditions.add(String.format("Humidity between %s and %s.", temp1, temp2)); + else + specialConditions.add(String.format("Humidity %s required.", temp1)); + return this; + } + + public Mutation setTemperatureRainfall(float minTemperature, float maxTemperature, float minRainfall, float maxRainfall) { + setTemperature(minTemperature, maxTemperature); + setRainfall(minRainfall, maxRainfall); + return this; + } + + @Override + public IAllele getAllele0() { + return allele0; + } + + @Override + public IAllele getAllele1() { + return allele1; + } + + @Override + public float getBaseChance() { + return chance; + } + + @Override + public IAllele[] getTemplate() { + return template; + } + + @Override + public boolean isPartner(IAllele allele) { + return allele0.getUID().equals(allele.getUID()) || allele1.getUID().equals(allele.getUID()); + } + + @Override + public IAllele getPartner(IAllele allele) { + if (allele0.getUID().equals(allele.getUID())) + return allele1; + else + return allele0; + } + + @Override + public boolean isSecret() { + return isSecret; + } + +} diff --git a/forestry_common/core/forestry/core/genetics/SpeciesRoot.java b/forestry_common/core/forestry/core/genetics/SpeciesRoot.java new file mode 100755 index 000000000..965880a8d --- /dev/null +++ b/forestry_common/core/forestry/core/genetics/SpeciesRoot.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.genetics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Random; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IMutation; +import forestry.api.genetics.ISpeciesRoot; + +public abstract class SpeciesRoot implements ISpeciesRoot { + + /* RESEARCH */ + LinkedHashMap researchCatalysts = new LinkedHashMap(); + + @Override + public Map getResearchCatalysts() { + return Collections.unmodifiableMap(researchCatalysts); + } + + @Override + public void setResearchSuitability(ItemStack itemstack, float suitability) { + researchCatalysts.put(itemstack, suitability); + } + + /* TEMPLATES */ + public HashMap speciesTemplates = new HashMap(); + + @Override + public Map getGenomeTemplates() { + return speciesTemplates; + } + + @Override + public void registerTemplate(IAllele[] template) { + registerTemplate(template[0].getUID(), template); + } + + @Override + public IAllele[] getRandomTemplate(Random rand) { + return speciesTemplates.values().toArray(new IAllele[0][])[rand.nextInt(speciesTemplates.values().size())]; + } + + @Override + public IAllele[] getTemplate(String identifier) { + return speciesTemplates.get(identifier); + } + + /* MUTATIONS */ + @Override + public Collection getCombinations(IAllele other) { + ArrayList combinations = new ArrayList(); + for (IMutation mutation : getMutations(false)) + if (mutation.isPartner(other)) + combinations.add(mutation); + + return combinations; + } + + @Override + public Collection getPaths(IAllele result, int chromosomeOrdinal) { + ArrayList paths = new ArrayList(); + for (IMutation mutation : getMutations(false)) + if(mutation.getTemplate()[chromosomeOrdinal] == result) + paths.add(mutation); + + return paths; + } + + /* GENOME CONVERSIONS */ + @Override + public IChromosome[] templateAsChromosomes(IAllele[] template) { + Chromosome[] chromosomes = new Chromosome[template.length]; + for (int i = 0; i < template.length; i++) + if (template[i] != null) + chromosomes[i] = new Chromosome(template[i]); + + return chromosomes; + } + + @Override + public IChromosome[] templateAsChromosomes(IAllele[] templateActive, IAllele[] templateInactive) { + Chromosome[] chromosomes = new Chromosome[templateActive.length]; + for (int i = 0; i < templateActive.length; i++) + if (templateActive[i] != null) + chromosomes[i] = new Chromosome(templateActive[i], templateInactive[i]); + + return chromosomes; + } + +} diff --git a/forestry_common/core/forestry/core/gui/ClimateLedger.java b/forestry_common/core/forestry/core/gui/ClimateLedger.java new file mode 100755 index 000000000..143d673e2 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ClimateLedger.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import forestry.api.core.EnumTemperature; +import forestry.core.genetics.ClimateHelper; +import forestry.core.interfaces.IClimatised; +import forestry.core.utils.StringUtil; + +/** + * A ledger containing climate information. + */ +public class ClimateLedger extends Ledger { + + IClimatised tile; + + public ClimateLedger(LedgerManager manager, IClimatised tile) { + super(manager); + this.tile = tile; + maxHeight = 72; + overlayColor = manager.gui.fontColor.get("ledger.climate.background"); + } + + @Override + public void draw(int x, int y) { + + EnumTemperature temperature = tile.getTemperature(); + + // Draw background + drawBackground(x, y); + + // Draw icon + drawIcon(temperature.getIcon(), x + 3, y + 4); + + if (!isFullyOpened()) + return; + + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.climate"), x + 22, y + 8, + manager.gui.fontColor.get("ledger.climate.header")); + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.temperature") + ":", x + 22, y + 20, + manager.gui.fontColor.get("ledger.climate.subheader")); + manager.minecraft.fontRenderer.drawString(ClimateHelper.toDisplay(temperature) + " " + StringUtil.floatAsPercent(tile.getExactTemperature()), x + 22, + y + 32, manager.gui.fontColor.get("ledger.climate.text")); + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.humidity") + ":", x + 22, y + 44, + manager.gui.fontColor.get("ledger.climate.subheader")); + manager.minecraft.fontRenderer.drawString(ClimateHelper.toDisplay(tile.getHumidity()) + " " + StringUtil.floatAsPercent(tile.getExactHumidity()), + x + 22, y + 56, manager.gui.fontColor.get("ledger.climate.text")); + } + + @Override + public String getTooltip() { + return "T: " + ClimateHelper.toDisplay(tile.getTemperature()) + " / H: " + ClimateHelper.toDisplay(tile.getHumidity()); + } + +} diff --git a/forestry_common/core/forestry/core/gui/ContainerAnalyzer.java b/forestry_common/core/forestry/core/gui/ContainerAnalyzer.java new file mode 100755 index 000000000..9f6e40ff6 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerAnalyzer.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gadgets.TileAnalyzer; +import forestry.core.genetics.ItemGE; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.gui.slots.SlotLiquidContainer; + +public class ContainerAnalyzer extends ContainerLiquidTanks { + + private TileAnalyzer tile; + + public ContainerAnalyzer(InventoryPlayer player, TileAnalyzer tile) { + super(tile, tile); + + this.tile = tile; + + // Input buffer + for (int i = 0; i < 3; i++) + for (int k = 0; k < 2; k++) + addSlot(new SlotCustom(tile, TileAnalyzer.SLOT_INPUT_1 + i * 2 + k, 8 + k * 18, 28 + i * 18, new Object[] { ItemGE.class })); + + // Analyze slot + addSlot(new SlotCustom(tile, TileAnalyzer.SLOT_ANALYZE, 73, 59, new Object[] {})); + + // Can slot + addSlot(new SlotLiquidContainer(tile, TileAnalyzer.SLOT_CAN, 143, 24)); + + // Output buffer + for (int i = 0; i < 2; i++) + for (int k = 0; k < 2; k++) + addSlot(new SlotCustom(tile, TileAnalyzer.SLOT_OUTPUT_1 + i * 2 + k, 134 + k * 18, 48 + i * 18, new Object[] { ItemGE.class })); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSlot(new Slot(player, l1 + i1 * 9 + 9, 8 + l1 * 18, 94 + i1 * 18)); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSlot(new Slot(player, j1, 8 + j1 * 18, 152)); + + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/core/forestry/core/gui/ContainerDummy.java b/forestry_common/core/forestry/core/gui/ContainerDummy.java new file mode 100755 index 000000000..6484986f4 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerDummy.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; + +public class ContainerDummy extends Container { + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return true; + } + +} diff --git a/forestry_common/core/forestry/core/gui/ContainerEscritoire.java b/forestry_common/core/forestry/core/gui/ContainerEscritoire.java new file mode 100755 index 000000000..7aaeefa50 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerEscritoire.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.Slot; + +import forestry.api.genetics.AlleleManager; +import forestry.core.gadgets.TileEscritoire; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; + +public class ContainerEscritoire extends ContainerForestry implements IGuiSelectable { + + final EntityPlayer player; + final TileEscritoire tile; + + public long lastUpdate; + + public ContainerEscritoire(EntityPlayer player, TileEscritoire t) { + super(t); + + this.player = player; + this.tile = t; + + Collection filters = new ArrayList(); + filters.add(Blocks.sapling); + filters.addAll(AlleleManager.alleleRegistry.getSpeciesRoot().values()); + // Analyze slot + addSlot(new SlotCustom(tile, TileEscritoire.SLOT_ANALYZE, 97, 67, filters.toArray()).setCrafter(tile)); + + for (int i = 0; i < TileEscritoire.SLOTS_INPUT_COUNT; i++) { + addSlot(new SlotCustom(tile, TileEscritoire.SLOT_INPUT_1 + i, 17, 49 + i * 18, true).setBlockedTexture("slots/blocked_2")); + } + + for(int i = 0; i < 3; i++) + for(int j = 0; j < 2; j++) { + addSlot(new SlotClosed(tile, TileEscritoire.SLOT_RESULTS_1 + (i*2) + j, 177 + j*18, 85 + i*18)); + } + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSlot(new Slot(player.inventory, j + i * 9 + 9, 34 + j * 18, 153 + i * 18)); + // Player hotbar + for (int k = 0; k < 9; k++) + addSlot(new Slot(player.inventory, k, 34 + k * 18, 211)); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if(lastUpdate == tile.getGame().getLastUpdate()) + return; + + lastUpdate = tile.getGame().getLastUpdate(); + tile.sendBoard(player); + } + + public void sendTokenClick(int index) { + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = index; + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + } + + public void sendProbeClick() { + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = -1; + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + } + + @Override + public void handleSelectionChange(EntityPlayer player, PacketUpdate packet) { + if (!tile.getGame().isEnded()) { + int index = packet.payload.intPayload[0]; + if (index == -1) { + tile.probe(); + } else { + tile.getGame().choose(packet.payload.intPayload[0]); + tile.processTurnResult(player.getGameProfile().getId()); + } + } + } + + @Override + public void setSelection(PacketUpdate packet) { + } + +} diff --git a/forestry_common/core/forestry/core/gui/ContainerForestry.java b/forestry_common/core/forestry/core/gui/ContainerForestry.java new file mode 100755 index 000000000..3a65b5bff --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerForestry.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.core.gui.slots.SlotForestry; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.StackUtils; + +public class ContainerForestry extends Container { + + protected IInventory inventory; + + public ContainerForestry(IInventory inventory) { + this.inventory = inventory; + } + + /** + * Adds a slot to the container, shortcut for addSlotToContainer(slot). + * + * @param slot + */ + protected Slot addSlot(Slot slot) { + return addSlotToContainer(slot); + } + + @Override + public ItemStack slotClick(int slotIndex, int button, int modifier, EntityPlayer player) { + Slot slot = slotIndex < 0 ? null : (Slot) this.inventorySlots.get(slotIndex); + if (slot instanceof SlotForestry) { + ((SlotForestry) slot).onSlotClick(slotIndex, button, modifier, player); + + if (((SlotForestry) slot).isPhantom()) { + return slotClickPhantom(slot, button, modifier, player); + } + } + return super.slotClick(slotIndex, button, modifier, player); + } + + private ItemStack slotClickPhantom(Slot slot, int mouseButton, int modifier, EntityPlayer player) { + ItemStack stack = null; + + if (mouseButton == 2) { + if (((SlotForestry) slot).canAdjustPhantom()) + slot.putStack(null); + } else if (mouseButton == 0 || mouseButton == 1) { + InventoryPlayer playerInv = player.inventory; + slot.onSlotChanged(); + ItemStack stackSlot = slot.getStack(); + ItemStack stackHeld = playerInv.getItemStack(); + + if (stackSlot != null) + stack = stackSlot.copy(); + + if (stackSlot == null) { + if (stackHeld != null && slot.isItemValid(stackHeld)) + fillPhantomSlot(slot, stackHeld, mouseButton, modifier); + } else if (stackHeld == null) { + adjustPhantomSlot(slot, mouseButton, modifier); + slot.onPickupFromSlot(player, playerInv.getItemStack()); + } else if (slot.isItemValid(stackHeld)) + if (StackUtils.isIdenticalItem(stackSlot, stackHeld)) + adjustPhantomSlot(slot, mouseButton, modifier); + else + fillPhantomSlot(slot, stackHeld, mouseButton, modifier); + } + return stack; + } + + protected void adjustPhantomSlot(Slot slot, int mouseButton, int modifier) { + if (!((SlotForestry) slot).canAdjustPhantom()) + return; + ItemStack stackSlot = slot.getStack(); + int stackSize; + if (modifier == 1) + stackSize = mouseButton == 0 ? (stackSlot.stackSize + 1) / 2 : stackSlot.stackSize * 2; + else + stackSize = mouseButton == 0 ? stackSlot.stackSize - 1 : stackSlot.stackSize + 1; + + if (stackSize > slot.getSlotStackLimit()) + stackSize = slot.getSlotStackLimit(); + + stackSlot.stackSize = stackSize; + + if (stackSlot.stackSize <= 0) + slot.putStack((ItemStack) null); + } + + protected void fillPhantomSlot(Slot slot, ItemStack stackHeld, int mouseButton, int modifier) { + if (!((SlotForestry) slot).canAdjustPhantom()) + return; + int stackSize = mouseButton == 0 ? stackHeld.stackSize : 1; + if (stackSize > slot.getSlotStackLimit()) + stackSize = slot.getSlotStackLimit(); + ItemStack phantomStack = stackHeld.copy(); + phantomStack.stackSize = stackSize; + + slot.putStack(phantomStack); + } + + protected boolean shiftItemStack(ItemStack stackToShift, int start, int end) { + boolean changed = false; + if (stackToShift.isStackable()) + for (int slotIndex = start; stackToShift.stackSize > 0 && slotIndex < end; slotIndex++) { + Slot slot = (Slot) inventorySlots.get(slotIndex); + ItemStack stackInSlot = slot.getStack(); + if (stackInSlot != null && StackUtils.isIdenticalItem(stackInSlot, stackToShift)) { + int resultingStackSize = stackInSlot.stackSize + stackToShift.stackSize; + int max = Math.min(stackToShift.getMaxStackSize(), slot.getSlotStackLimit()); + if (resultingStackSize <= max) { + stackToShift.stackSize = 0; + stackInSlot.stackSize = resultingStackSize; + slot.onSlotChanged(); + changed = true; + } else if (stackInSlot.stackSize < max) { + stackToShift.stackSize -= max - stackInSlot.stackSize; + stackInSlot.stackSize = max; + slot.onSlotChanged(); + changed = true; + } + } + } + if (stackToShift.stackSize > 0) + for (int slotIndex = start; stackToShift.stackSize > 0 && slotIndex < end; slotIndex++) { + Slot slot = (Slot) inventorySlots.get(slotIndex); + ItemStack stackInSlot = slot.getStack(); + if (stackInSlot == null) { + int max = Math.min(stackToShift.getMaxStackSize(), slot.getSlotStackLimit()); + stackInSlot = stackToShift.copy(); + stackInSlot.stackSize = Math.min(stackToShift.stackSize, max); + stackToShift.stackSize -= stackInSlot.stackSize; + slot.putStack(stackInSlot); + slot.onSlotChanged(); + changed = true; + } + } + return changed; + } + + private boolean tryShiftItem(ItemStack stackToShift, int numSlots) { + for (int machineIndex = 0; machineIndex < numSlots - 9 * 4; machineIndex++) { + Slot slot = (Slot) inventorySlots.get(machineIndex); + if (slot instanceof SlotForestry) { + SlotForestry slotForestry = (SlotForestry) slot; + if (!slotForestry.canShift()) + continue; + if (slotForestry.isPhantom()) + continue; + } + if (!slot.isItemValid(stackToShift)) + continue; + if (shiftItemStack(stackToShift, machineIndex, machineIndex + 1)) + return true; + } + return false; + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer player, int slotIndex) { + ItemStack originalStack = null; + Slot slot = (Slot) inventorySlots.get(slotIndex); + int numSlots = inventorySlots.size(); + if (slot != null && slot.getHasStack()) { + ItemStack stackInSlot = slot.getStack(); + originalStack = stackInSlot.copy(); + if (slotIndex >= numSlots - 9 * 4 && tryShiftItem(stackInSlot, numSlots)) { + // NOOP + } else if (slotIndex >= numSlots - 9 * 4 && slotIndex < numSlots - 9) { + if (!shiftItemStack(stackInSlot, numSlots - 9, numSlots)) + return null; + } else if (slotIndex >= numSlots - 9 && slotIndex < numSlots) { + if (!shiftItemStack(stackInSlot, numSlots - 9 * 4, numSlots - 9)) + return null; + } else if (!shiftItemStack(stackInSlot, numSlots - 9 * 4, numSlots)) + return null; + slot.onSlotChange(stackInSlot, originalStack); + if (stackInSlot.stackSize <= 0) + slot.putStack(null); + else + slot.onSlotChanged(); + if (stackInSlot.stackSize == originalStack.stackSize) + return null; + slot.onPickupFromSlot(player, stackInSlot); + } + return originalStack; + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return inventory.isUseableByPlayer(entityplayer); + } + + public void onTankUpdate(NBTTagCompound nbt) { + } + + public ForestryTank getTank(int slot) { + return ForestryTank.FAKETANK; + } +} diff --git a/forestry_common/core/forestry/core/gui/ContainerItemInventory.java b/forestry_common/core/forestry/core/gui/ContainerItemInventory.java new file mode 100755 index 000000000..b2335d6e9 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerItemInventory.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +import forestry.core.gui.slots.SlotItemInventory; +import forestry.core.gui.slots.SlotLocked; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ItemInventory; + +public abstract class ContainerItemInventory extends ContainerForestry { + + protected final EntityPlayer player; + protected final ItemInventory inventory; + + public ContainerItemInventory(ItemInventory inventory, EntityPlayer player) { + super(inventory); + this.inventory = inventory; + this.player = player; + } + + public ItemInventory getItemInventory() { + return inventory; + } + + protected void addSecuredSlot(IInventory other, int slot, int x, int y) { + if (other.getStackInSlot(slot) != null && inventory.itemClass.isAssignableFrom(other.getStackInSlot(slot).getItem().getClass())) + addSlot(new SlotLocked(other, slot, x, y)); + else + addSlot(new SlotItemInventory(this, other, player, slot, x, y)); + } + + protected abstract boolean isAcceptedItem(EntityPlayer player, ItemStack stack); + + public void purgeBag(EntityPlayer player) { + for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + if (isAcceptedItem(player, stack)) + continue; + + Proxies.common.dropItemPlayer(player, stack); + inventory.setInventorySlotContents(i, null); + } + } + + public void saveInventory(EntityPlayer entityplayer) { + if (inventory.isItemInventory) + inventory.onGuiSaved(entityplayer); + } + + @Override + public void onContainerClosed(EntityPlayer player) { + super.onContainerClosed(player); + if (!Proxies.common.isSimulating(player.worldObj)) + return; + + purgeBag(player); + saveInventory(player); + } +} diff --git a/forestry_common/core/forestry/core/gui/ContainerLiquidTanks.java b/forestry_common/core/forestry/core/gui/ContainerLiquidTanks.java new file mode 100755 index 000000000..8155cd2bd --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerLiquidTanks.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; + +import buildcraft.api.tools.IToolPipette; + +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketTankUpdate; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryTank; + +public class ContainerLiquidTanks extends ContainerForestry { + + private ILiquidTankContainer tanks; + + public ContainerLiquidTanks(IInventory inventory, ILiquidTankContainer tanks) { + super(inventory); + this.tanks = tanks; + } + + public void handlePipetteClick(int slot, EntityPlayer player) { + + ItemStack itemstack = player.inventory.getItemStack(); + if (itemstack == null) + return; + + Item held = itemstack.getItem(); + if (!(held instanceof IToolPipette)) + return; + + if (!Proxies.common.isSimulating(player.worldObj)) { + + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = slot; + Proxies.net.sendToServer(new PacketUpdate(PacketIds.PIPETTE_CLICK, payload)); + return; + + } + + IToolPipette pipette = (IToolPipette) held; + int liquidAmount = tanks.getTanks()[slot].getFluid().amount; + if (pipette.canPipette(itemstack) && liquidAmount > 0) { + + if (liquidAmount > 0) { + int filled = pipette.fill(itemstack, tanks.getTanks()[slot].drain(1000, false), + true); + tanks.getTanks()[slot].drain(filled, true); + } + + } else { + + IFluidTank tank = tanks.getTanks()[slot]; + FluidStack potential = pipette.drain(itemstack, pipette.getCapacity(itemstack), false); + if (potential != null) + pipette.drain(itemstack, tank.fill(potential, true), true); + + } + } + private Map syncedFluids = new HashMap(); + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < tanks.getTanks().length; i++) { + ForestryTank tank = tanks.getTanks()[i]; + + // If null has been synced + if (tank.getFluid() == null && getTank(i).getFluidAmount() <= 0) + continue; + // If fluid has been synced + if (tank.getFluid() != null && tank.getFluid().isFluidStackIdentical(getTank(i).getFluid())) + continue; + + for (int j = 0; j < this.crafters.size(); ++j) { + if (this.crafters.get(j) instanceof EntityPlayerMP) { + EntityPlayerMP player = (EntityPlayerMP) this.crafters.get(j); + Proxies.net.sendToPlayer(new PacketTankUpdate(i, tank), player); + } + } + + syncedFluids.put(i, new ForestryTank(tank.getFluid() == null ? null : tank.getFluid().copy(), tank.getCapacity())); + + } + } + + @Override + public void onTankUpdate(NBTTagCompound nbt) { + int tankID = nbt.getByte("tank"); + int capacity = nbt.getShort("capacity"); + tanks.getTanks()[tankID].readFromNBT(nbt); + + ForestryTank tank = new ForestryTank(capacity); + tank.readFromNBT(nbt); + syncedFluids.put(tankID, tank); + } + + @Override + public ForestryTank getTank(int slot) { + return syncedFluids.get(slot) == null ? ForestryTank.FAKETANK : syncedFluids.get(slot); + } +} diff --git a/forestry_common/core/forestry/core/gui/ContainerNaturalistInventory.java b/forestry_common/core/forestry/core/gui/ContainerNaturalistInventory.java new file mode 100755 index 000000000..3eecb2a09 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerNaturalistInventory.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; + +public class ContainerNaturalistInventory extends ContainerForestry implements IGuiSelectable { + + private final IPagedInventory inv; + private ISpeciesRoot speciesRoot; + + public ContainerNaturalistInventory(ISpeciesRoot speciesRoot, InventoryPlayer player, IPagedInventory inventory, int page, int pageSize) { + super(inventory); + this.inv = inventory; + this.speciesRoot = speciesRoot; + + // Inventory + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) { + addSlot(new SlotCustom(inventory, y + page * pageSize + x * 5, 100 + y * 18, 21 + x * 18, new Object[]{speciesRoot})); + } + } + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) { + for (int l1 = 0; l1 < 9; l1++) { + addSlot(new Slot(player, l1 + i1 * 9 + 9, 18 + l1 * 18, 120 + i1 * 18)); + } + } + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) { + addSlot(new Slot(player, j1, 18 + j1 * 18, 178)); + } + } + + public void purgeBag(EntityPlayer player) { + for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + if (speciesRoot.isMember(stack)) + continue; + + Proxies.common.dropItemPlayer(player, stack); + inventory.setInventorySlotContents(i, null); + } + } + + @Override + public void handleSelectionChange(EntityPlayer player, PacketUpdate packet) { + inv.flipPage(player, packet.payload.intPayload[0]); + } + + @Override + public void setSelection(PacketUpdate packet) { + } +} diff --git a/forestry_common/core/forestry/core/gui/ContainerSocketed.java b/forestry_common/core/forestry/core/gui/ContainerSocketed.java new file mode 100755 index 000000000..0ff47e3fd --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ContainerSocketed.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import forestry.core.interfaces.ISocketable; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketSocketUpdate; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; + +public class ContainerSocketed extends ContainerForestry { + + ISocketable tile; + + public ContainerSocketed(IInventory inventory, ISocketable tile) { + super(inventory); + this.tile = tile; + } + + public void handleChipsetClick(int slot, EntityPlayer player, ItemStack itemstack) { + if (!Proxies.common.isSimulating(player.worldObj)) { + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = slot; + Proxies.net.sendToServer(new PacketUpdate(PacketIds.CHIPSET_CLICK, payload)); + player.inventory.setItemStack(null); + return; + } + + ItemStack toSocket = itemstack.copy(); + toSocket.stackSize = 1; + tile.setSocket(slot, toSocket); + + if (Proxies.common.isSimulating(player.worldObj)) { + ItemStack stack = player.inventory.getItemStack(); + stack.stackSize--; + if(stack.stackSize <= 0) + player.inventory.setItemStack(null); + Proxies.net.inventoryChangeNotify(player); + + TileEntity te = (TileEntity) tile; + Proxies.net.sendToPlayer(new PacketSocketUpdate(PacketIds.SOCKET_UPDATE, te.xCoord, te.yCoord, te.zCoord, tile), player); + } + + } + + public void handleSolderingIronClick(int slot, EntityPlayer player, ItemStack itemstack) { + if (!Proxies.common.isSimulating(player.worldObj)) { + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = slot; + Proxies.net.sendToServer(new PacketUpdate(PacketIds.SOLDERING_IRON_CLICK, payload)); + return; + } + + ItemStack socket = tile.getSocket(slot); + if (socket == null) + return; + + StackUtils.stowInInventory(socket, player.inventory, true); + // Not sufficient space in player's inventory. failed to stow. + if (socket.stackSize > 0) + return; + + tile.setSocket(slot, null); + itemstack.damageItem(1, player); + if (itemstack.stackSize <= 0) + player.inventory.setItemStack(null); + + TileEntity te = (TileEntity) tile; + Proxies.net.sendToPlayer(new PacketSocketUpdate(PacketIds.SOCKET_UPDATE, te.xCoord, te.yCoord, te.zCoord, tile), player); + + } + +} diff --git a/forestry_common/core/forestry/core/gui/ErrorLedger.java b/forestry_common/core/forestry/core/gui/ErrorLedger.java new file mode 100755 index 000000000..9dd062be7 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/ErrorLedger.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import forestry.core.EnumErrorCode; +import forestry.core.interfaces.IErrorSource; +import forestry.core.utils.StringUtil; + +/** + * A ledger displaying error messages and help text. + */ +public class ErrorLedger extends Ledger { + + IErrorSource tile; + + public ErrorLedger(LedgerManager manager, IErrorSource tile) { + super(manager); + this.tile = tile; + maxHeight = 72; + overlayColor = manager.gui.fontColor.get("ledger.error.background"); + } + + @Override + public void draw(int x, int y) { + EnumErrorCode state = tile.getErrorState(); + if (state == EnumErrorCode.OK) + return; + + // Draw background + drawBackground(x, y); + + // Draw icon + drawIcon(state.getIcon(), x + 3, y + 4); + + // Write description if fully opened + if (isFullyOpened()) { + // fontRendererObj.drawStringWithShadow(getTooltip(), x + 22, y + + // 8, 0xe1c92f); + manager.minecraft.fontRenderer.drawStringWithShadow(getTooltip(), x + 22, y + 8, manager.gui.fontColor.get("ledger.error.header")); + manager.minecraft.fontRenderer.drawSplitString(StringUtil.localize(tile.getErrorState().getHelp()), x + 22, y + 20, maxWidth - 28, + manager.gui.fontColor.get("ledger.error.text")); + } + } + + @Override + public boolean isVisible() { + EnumErrorCode state = tile.getErrorState(); + if (state == EnumErrorCode.OK) + return false; + else + return true; + } + + @Override + public String getTooltip() { + return StringUtil.localize(tile.getErrorState().getDescription()); + } + +} diff --git a/forestry_common/core/forestry/core/gui/GuiAlyzer.java b/forestry_common/core/forestry/core/gui/GuiAlyzer.java new file mode 100755 index 000000000..5023671b8 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/GuiAlyzer.java @@ -0,0 +1,376 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Stack; + +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; + +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IClassification.EnumClassLevel; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileForestry; +import forestry.core.genetics.EnumMutateChance; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StringUtil; + +public abstract class GuiAlyzer extends GuiForestry { + + protected static final int COLUMN_0 = 12; + protected static final int COLUMN_1 = 52; + protected static final int COLUMN_2 = 108; + + protected IInventory inventory; + protected ISpeciesRoot speciesRoot; + protected IBreedingTracker breedingTracker; + + protected HashMap iconStacks = new HashMap(); + + public GuiAlyzer(ISpeciesRoot speciesRoot, EntityPlayer player, ContainerForestry container, IInventory inventory, int pageMax, int pageSize) { + super(Defaults.TEXTURE_PATH_GUI + "/beealyzer.png", container); + + this.inventory = inventory; + this.speciesRoot = speciesRoot; + this.breedingTracker = speciesRoot.getBreedingTracker(player.worldObj, player.getGameProfile().getId()); + } + + protected final int getColorCoding(boolean dominant) { + if (dominant) + return fontColor.get("gui.beealyzer.dominant"); + else + return fontColor.get("gui.beealyzer.recessive"); + } + + protected final void drawLine(String text, int x, IIndividual individual, Enum chromosome, boolean inactive) { + if (!inactive) + drawLine(text, x, getColorCoding(individual.getGenome().getActiveAllele(chromosome.ordinal()).isDominant())); + else + drawLine(text, x, getColorCoding(individual.getGenome().getInactiveAllele(chromosome.ordinal()).isDominant())); + } + + protected final void drawSplitLine(String text, int x, int maxWidth, IIndividual individual, Enum chromosome, boolean inactive) { + if (!inactive) + drawSplitLine(text, x, maxWidth, getColorCoding(individual.getGenome().getActiveAllele(chromosome.ordinal()).isDominant())); + else + drawSplitLine(text, x, maxWidth, getColorCoding(individual.getGenome().getInactiveAllele(chromosome.ordinal()).isDominant())); + } + + protected final void drawRow(String text0, String text1, String text2, IIndividual individual, Enum chromosome) { + drawRow(text0, text1, text2, fontColor.get("gui.screen"), getColorCoding(individual.getGenome().getActiveAllele(chromosome.ordinal()).isDominant()), + getColorCoding(individual.getGenome().getInactiveAllele(chromosome.ordinal()).isDominant())); + } + + protected final void drawSpeciesRow(String text0, IIndividual individual, Enum chromosome) { + IAlleleSpecies primary = individual.getGenome().getPrimary(); + IAlleleSpecies secondary = individual.getGenome().getSecondary(); + + drawLine(text0, column0); + int columnwidth = column2 - column1 - 16; + + RenderHelper.enableStandardItemLighting(); + drawItemStack(iconStacks.get(primary.getUID()), adjustToFactor(guiLeft + column1 + columnwidth + 2), adjustToFactor(guiTop + getLineY())); + drawItemStack(iconStacks.get(secondary.getUID()), adjustToFactor(guiLeft + column2 + columnwidth + 4), adjustToFactor(guiTop + getLineY())); + RenderHelper.disableStandardItemLighting(); + + drawSplitLine(primary.getName(), column1, columnwidth, individual, chromosome, false); + drawSplitLine(secondary.getName(), column2, columnwidth, individual, chromosome, true); + + newLine(); + newLine(); + + } + + protected final void drawAnalyticsPageClassification(IIndividual individual) { + + startPage(); + + drawLine(StringUtil.localize("gui.alyzer.classification") + ":", 12); + newLine(); + + Stack hierarchy = new Stack(); + IClassification classification = individual.getGenome().getPrimary().getBranch(); + while (classification != null) { + + if (classification.getScientific() != null && !classification.getScientific().isEmpty()) + hierarchy.push(classification); + classification = classification.getParent(); + } + + boolean overcrowded = hierarchy.size() > 5; + int x = 12; + IClassification group = null; + + while (!hierarchy.isEmpty()) { + + group = hierarchy.pop(); + if (overcrowded && group.getLevel().isDroppable()) + continue; + + drawLine(group.getScientific(), x, group.getLevel().getColour()); + drawLine(group.getLevel().name(), 130, group.getLevel().getColour()); + newLine(); + x += 8; + } + + // Add the species name + String binomial = individual.getGenome().getPrimary().getBinomial(); + if (group != null && group.getLevel() == EnumClassLevel.GENUS) + binomial = group.getScientific().substring(0, 1) + ". " + binomial.toLowerCase(Locale.ENGLISH); + + drawLine(binomial, x, 0xebae85); + drawLine("SPECIES", 130, 0xebae85); + + newLine(); + newLine(); + drawLine(StringUtil.localize("gui.alyzer.authority") + ": " + individual.getGenome().getPrimary().getAuthority(), 12); + if (AlleleManager.alleleRegistry.isBlacklisted(individual.getIdent())) { + String extinct = ">> " + StringUtil.localize("gui.alyzer.extinct").toUpperCase() + " <<"; + fontRendererObj.drawStringWithShadow(extinct, adjustToFactor(guiLeft + 160) - fontRendererObj.getStringWidth(extinct), + adjustToFactor(guiTop + getLineY()), fontColor.get("gui.beealyzer.dominant")); + } + + newLine(); + String description = individual.getGenome().getPrimary().getDescription(); + if (description == null || description.isEmpty()) + drawSplitLine(StringUtil.localize("gui.alyzer.nodescription"), 12, 156, 0x666666); + else { + String tokens[] = description.split("\\|"); + drawSplitLine(tokens[0], 12, 152, 0x666666); + if (tokens.length > 1) + fontRendererObj.drawStringWithShadow("- " + tokens[1], adjustToFactor(guiLeft + 160) - fontRendererObj.getStringWidth("- " + tokens[1]), + adjustToFactor(guiTop + 145 - 14), 0x99cc32); + } + + endPage(); + + } + + protected void drawAnalyticsPage4(IIndividual individual) { + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + drawLine(StringUtil.localize("gui.beealyzer.mutations") + ":", COLUMN_0); + newLine(); + newLine(); + + RenderHelper.enableGUIStandardItemLighting(); + + HashMap combinations = new HashMap(); + + for (IMutation mutation : speciesRoot.getCombinations(individual.getGenome().getPrimary())) + combinations.put(mutation, individual.getGenome().getPrimary()); + + for (IMutation mutation : speciesRoot.getCombinations(individual.getGenome().getSecondary())) + combinations.put(mutation, individual.getGenome().getSecondary()); + + int columnWidth = 50; + int x = 0; + + for (Map.Entry mutation : combinations.entrySet()) { + + if (breedingTracker.isDiscovered(mutation.getKey())) + drawMutationInfo(mutation.getKey(), mutation.getValue(), COLUMN_0 + x); + else { + // Do not display secret undiscovered mutations. + if (mutation.getKey().isSecret()) + continue; + + drawUnknownMutation(mutation.getKey(), mutation.getValue(), COLUMN_0 + x); + } + + x += columnWidth; + if (x > 150) { + x = 0; + newLine(); + newLine(); + } + } + + endPage(); + } + + protected void drawMutationInfo(IMutation combination, IAllele species, int x) { + + drawItemStack(iconStacks.get(combination.getPartner(species).getUID()), + adjustToFactor(guiLeft) + x, adjustToFactor(guiTop) + getLineY()); + /* + itemRenderer.renderItemIntoGUI(fontRendererObj, mc.renderEngine, iconStacks.get(combination.getPartner(species).getUID()), adjustToFactor(guiLeft) + x, + adjustToFactor(guiTop) + getLineY()); + itemRenderer.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, iconStacks.get(combination.getPartner(species).getUID()), adjustToFactor(guiLeft) + + x, adjustToFactor(guiTop) + getLineY()); + */ + + IAllele result = combination.getTemplate()[EnumBeeChromosome.SPECIES.ordinal()]; + + drawItemStack(iconStacks.get(result.getUID()), + adjustToFactor(guiLeft) + x + 33, adjustToFactor(guiTop) + getLineY()); + /* + itemRenderer.renderItemIntoGUI(fontRendererObj, mc.renderEngine, iconStacks.get(result.getUID()), adjustToFactor(guiLeft) + x + 33, adjustToFactor(guiTop) + + getLineY()); + itemRenderer.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, iconStacks.get(result.getUID()), adjustToFactor(guiLeft) + x + 33, + adjustToFactor(guiTop) + getLineY()); + */ + + int line = 0; + int column = 196; + + switch (EnumMutateChance.rateChance(combination.getBaseChance())) { + case HIGHEST: + column = 226; + line = 9; + break; + case HIGHER: + column = 211; + line = 9; + break; + case HIGH: + line = 9; + break; + case NORMAL: + column = 226; + break; + case LOW: + column = 211; + break; + case LOWEST: + default: + break; + } + + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect(adjustToFactor(guiLeft) + x + 18, adjustToFactor(guiTop) + getLineY() + 4, column, line, 15, 9); + + } + + protected void drawUnknownMutation(IMutation combination, IAllele species, int x) { + + // Question marks + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect(adjustToFactor(guiLeft) + x, adjustToFactor(guiTop) + getLineY(), 196, 18, 16, 16); + + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect(adjustToFactor(guiLeft) + x + 32, adjustToFactor(guiTop) + getLineY(), 196, 18, 16, 16); + + int line = 0; + int column = 196; + + switch (EnumMutateChance.rateChance(combination.getBaseChance())) { + case HIGHEST: + column = 226; + line = 9; + break; + case HIGHER: + column = 211; + line = 9; + break; + case HIGH: + line = 9; + break; + case NORMAL: + column = 226; + break; + case LOW: + column = 211; + break; + case LOWEST: + default: + break; + } + + // Probability arrow + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect(adjustToFactor(guiLeft) + x + 18, adjustToFactor(guiTop) + getLineY() + 4, column, line, 15, 9); + + } + + protected void drawToleranceInfo(EnumTolerance tolerance, int x, int textColor) { + int length = tolerance.toString().length(); + String text = "(" + tolerance.toString().substring(length - 1) + ")"; + + // Enable correct lighting. + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + switch (tolerance) { + case BOTH_1: + case BOTH_2: + case BOTH_3: + case BOTH_4: + case BOTH_5: + drawBothSymbol(x, getLineY() - 1); + drawLine(text, x + (int) (20 * factor), textColor); + break; + case DOWN_1: + case DOWN_2: + case DOWN_3: + case DOWN_4: + case DOWN_5: + drawDownSymbol(x, getLineY() - 1); + drawLine(text, x + (int) (20 * factor), textColor); + break; + case UP_1: + case UP_2: + case UP_3: + case UP_4: + case UP_5: + drawUpSymbol(x, getLineY() - 1); + drawLine(text, x + (int) (20 * factor), textColor); + break; + default: + drawNoneSymbol(x, getLineY() - 1); + drawLine("(0)", x + (int) (20 * factor), textColor); + break; + } + } + + private void drawDownSymbol(int x, int y) { + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect((int) ((guiLeft + x) * (1 / factor)), (int) ((guiTop + getLineY()) * (1 / factor)), 196, 34, 15, 9); + } + + private void drawUpSymbol(int x, int y) { + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect((int) ((guiLeft + x) * (1 / factor)), (int) ((guiTop + getLineY()) * (1 / factor)), 211, 34, 15, 9); + } + + private void drawBothSymbol(int x, int y) { + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect((int) ((guiLeft + x) * (1 / factor)), (int) ((guiTop + getLineY()) * (1 / factor)), 226, 34, 15, 9); + } + + private void drawNoneSymbol(int x, int y) { + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect((int) ((guiLeft + x) * (1 / factor)), (int) ((guiTop + getLineY()) * (1 / factor)), 241, 34, 15, 9); + } + + protected void drawFertilityInfo(int fertility, int x, int textColor, int texOffset) { + // Enable correct lighting. + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect((int) ((guiLeft + x + 19) * (1 / factor)), (int) ((guiTop + getLineY()) * (1 / factor)), 196, 43 + texOffset, 12, 9); + + drawLine(Integer.toString(fertility) + " x", x, textColor); + } + +} diff --git a/forestry_common/core/forestry/core/gui/GuiAnalyzer.java b/forestry_common/core/forestry/core/gui/GuiAnalyzer.java new file mode 100755 index 000000000..a2f6fabab --- /dev/null +++ b/forestry_common/core/forestry/core/gui/GuiAnalyzer.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileAnalyzer; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Utils; + +public class GuiAnalyzer extends GuiForestry { + + public GuiAnalyzer(InventoryPlayer inventory, TileAnalyzer tile) { + super(Defaults.TEXTURE_PATH_GUI + "/alyzer.png", new ContainerAnalyzer(inventory, tile), tile); + ySize = 176; + widgetManager.add(new TankWidget(this.widgetManager, 95, 24, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String title = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(title, getCenteredOffset(title), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + TileAnalyzer machine = tile; + drawAnalyzeMeter(guiLeft + 64, guiTop + 30, machine.getProgressScaled(46), Utils.rateTankLevel(machine.getProgressScaled(100))); + + } + + private void drawAnalyzeMeter(int x, int y, int height, EnumTankLevel rated) { + int i = 176; + int k = 60; + switch (rated) { + case EMPTY: + break; + case LOW: + i += 4; + break; + case MEDIUM: + i += 8; + break; + case HIGH: + i += 12; + break; + case MAXIMUM: + i += 16; + break; + } + + drawTexturedModalRect(x, y + 46 - height, i, k + 46 - height, 4, height); + } +} diff --git a/forestry_common/core/forestry/core/gui/GuiEscritoire.java b/forestry_common/core/forestry/core/gui/GuiEscritoire.java new file mode 100755 index 000000000..e629b1e78 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/GuiEscritoire.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.Defaults; +import forestry.core.gadgets.NaturalistGame; +import forestry.core.gadgets.NaturalistGame.GameToken; +import forestry.core.gadgets.TileEscritoire; +import forestry.core.gui.widgets.Widget; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class GuiEscritoire extends GuiForestry { + + private static String[][] researchNotes = new String[][] { + new String[] { "I have found a curious specimen on my travels.", "This strange fellow needs further investigation.", "Elated, I wanted to start at once with my research." }, + new String[] { "I was amazed at the wondrous nature of it.", "The specimen twitched, while I inspected it more closely.", "Strange markings on the underside made me curious.", "This will be the talk of the society when I am done investigating." }, + new String[] { "After some prodding I discovered an interesting new lead.", "I scratched my head at this discovery and questioned everything.", "I thought my eyes deceived me, but there it was.", "A previously unseen dot led me to question the specimen's classification." }, + new String[] { "My screams of frustration had the housekeeper look into my study in worry.", "In a frenzy and on the verge of despair, I ripped up all the notes!", "This... just doesn't make any sense!", "It just cannot be. It didn't do that before!", "The sledgehammer barely made a dent, so I sent for the chainsaw.", "I swear it was looking at me, with its beady, cruel, little eyes.", "Is that laughter? Do I hear laughter? Who is laughing here?" }, + new String[] { "EUREKA!", "Wondrous! My name will go down in history!", "My colleagues will be impressed!", "I will be the envy of everyone at the society!", "Woot!" }, + new String[] { "All is lost.", "I consign my notes to the fire.", "Why? I had made such great strides at first...", "Failed. Again.", "Oh my..." } + }; + + private class TokenSlot extends Widget { + + private final ItemStack HIDDEN_TOKEN; + private final int index; + + public TokenSlot(WidgetManager manager, int xPos, int yPos, int index) { + super(manager, xPos, yPos); + this.index = index; + + HIDDEN_TOKEN = new ItemStack(Items.book); + } + + private boolean hasToken() { + return tile.getGame().getToken(index) != null; + } + + private GameToken getToken() { + return tile.getGame().getToken(index); + } + + @Override + public void draw(int startX, int startY) { + + if (!hasToken()) + return; + + int tokenColour = getToken().getTokenColour(); + + float colorR = (tokenColour >> 16 & 255) / 255.0F; + float colorG = (tokenColour >> 8 & 255) / 255.0F; + float colorB = (tokenColour & 255) / 255.0F; + + manager.gui.bindTexture(manager.gui.textureFile); + GL11.glColor4f(colorR, colorG, colorB, 1.0F); + manager.gui.drawTexturedModalRect(startX + xPos, startY + yPos, 228, 0, 22, 22); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + + ItemStack tokenStack = HIDDEN_TOKEN; + if (getToken().isVisible()) + tokenStack = getToken().tokenStack; + + + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_DEPTH_TEST); + RenderHelper.enableGUIStandardItemLighting(); + manager.gui.drawItemStack(tokenStack, startX + xPos + 3, startY + yPos + 3); + RenderHelper.disableStandardItemLighting(); + GL11.glPopAttrib(); + + manager.gui.setZLevel(150f); + for (String ident : getToken().getOverlayIcons()) { + RenderHelper.enableGUIStandardItemLighting(); + Proxies.common.bindTexture(SpriteSheet.ITEMS); + manager.gui.drawTexturedModelRectFromIcon(startX + xPos + 3, startY + yPos + 3, TextureManager.getInstance().getDefault(ident), 16, 16); + RenderHelper.disableStandardItemLighting(); + } + manager.gui.setZLevel(0f); + } + + @Override + protected String getLegacyTooltip(EntityPlayer player) { + return hasToken() && getToken().isVisible() ? getToken().getTooltip() : null; + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + container.sendTokenClick(index); + } + } + + private class ProbeButton extends Widget { + + private boolean pressed; + + public ProbeButton(WidgetManager manager, int xPos, int yPos) { + super(manager, xPos, yPos); + width = 22; + height = 25; + } + + @Override + public void draw(int startX, int startY) { + manager.gui.bindTexture(manager.gui.textureFile); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + manager.gui.drawTexturedModalRect(startX + xPos, startY + yPos, 228, pressed ? 47 : 22, width, height); + } + + @Override + protected String getLegacyTooltip(EntityPlayer player) { + return StringUtil.localize("gui.escritoire.probe"); + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + pressed = true; + container.sendProbeClick(); + } + + @Override + public void handleMouseRelease(int mouseX, int mouseY, int eventType) { + if (pressed) + pressed = false; + } + + @Override + public void handleMouseMove(int mouseX, int mouseY, int mouseButton, long time) { + if (widgetManager.getAtPosition(mouseX - getGuiLeft(), mouseY - getGuiTop()) != this) + pressed = false; + } + } + private final ItemStack LEVEL_ITEM; + protected ContainerEscritoire container; + private final TileEscritoire tile; + private String researchNote = ""; + private long lastUpdate; + + public GuiEscritoire(EntityPlayer player, TileEscritoire tile) { + super(Defaults.TEXTURE_PATH_GUI + "/escritoire.png", new ContainerEscritoire(player, tile)); + + LEVEL_ITEM = new ItemStack(Items.paper); + + xSize = 228; + ySize = 235; + + this.container = (ContainerEscritoire) inventorySlots; + this.tile = tile; + + widgetManager.add(new ProbeButton(widgetManager, 14, 16)); + + // Inner ring + widgetManager.add(new TokenSlot(widgetManager, 115, 51, 0)); + widgetManager.add(new TokenSlot(widgetManager, 115, 77, 1)); + widgetManager.add(new TokenSlot(widgetManager, 94, 90, 2)); + widgetManager.add(new TokenSlot(widgetManager, 73, 77, 3)); + widgetManager.add(new TokenSlot(widgetManager, 73, 51, 4)); + widgetManager.add(new TokenSlot(widgetManager, 94, 38, 5)); + + // Outer ring + widgetManager.add(new TokenSlot(widgetManager, 115, 25, 6)); + widgetManager.add(new TokenSlot(widgetManager, 136, 38, 7)); + widgetManager.add(new TokenSlot(widgetManager, 136, 64, 8)); + + widgetManager.add(new TokenSlot(widgetManager, 136, 90, 9)); + widgetManager.add(new TokenSlot(widgetManager, 115, 103, 10)); + widgetManager.add(new TokenSlot(widgetManager, 94, 116, 11)); + + widgetManager.add(new TokenSlot(widgetManager, 73, 103, 12)); + widgetManager.add(new TokenSlot(widgetManager, 52, 90, 13)); + widgetManager.add(new TokenSlot(widgetManager, 52, 64, 14)); + + widgetManager.add(new TokenSlot(widgetManager, 52, 38, 15)); + widgetManager.add(new TokenSlot(widgetManager, 73, 25, 16)); + widgetManager.add(new TokenSlot(widgetManager, 94, 12, 17)); + + // Corners + widgetManager.add(new TokenSlot(widgetManager, 52, 12, 18)); + widgetManager.add(new TokenSlot(widgetManager, 136, 12, 19)); + widgetManager.add(new TokenSlot(widgetManager, 52, 116, 20)); + widgetManager.add(new TokenSlot(widgetManager, 136, 116, 21)); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + for (int i = 0; i <= tile.getGame().getBountyLevel() / 4; i++) { + RenderHelper.enableGUIStandardItemLighting(); + GuiForestry.itemRender.renderItemAndEffectIntoGUI(mc.fontRenderer, + mc.renderEngine, LEVEL_ITEM, guiLeft + 170 + i * 8, guiTop + 7); + RenderHelper.disableStandardItemLighting(); + } + + startPage(); + setFactor(0.5f); + + newLine(); + newLine(); + drawLine("\u00A7n\u00A7oAttempt No. " + (NaturalistGame.BOUNTY_MAX - tile.getGame().getBountyLevel()), 171, fontColor.get("gui.mail.lettertext")); + newLine(); + drawSplitLine(getResearchNote(), 171, 46, fontColor.get("gui.mail.lettertext")); + + endPage(); + } + + private String getResearchNote() { + if (lastUpdate == tile.getGame().getLastUpdate()) + return researchNote; + + if (!tile.getGame().isInited()) + researchNote = ""; + else { + if (tile.getGame().isWon()) { + researchNote = getRandomNote(researchNotes[4]); + } else if (tile.getGame().isEnded()) { + researchNote = getRandomNote(researchNotes[5]); + } else { + int bounty = tile.getGame().getBountyLevel(); + if (bounty >= NaturalistGame.BOUNTY_MAX) { + researchNote = getRandomNote(researchNotes[0]); + } else if (bounty > NaturalistGame.BOUNTY_MAX / 2) { + researchNote = getRandomNote(researchNotes[1]); + } else if (bounty > NaturalistGame.BOUNTY_MAX / 4) { + researchNote = getRandomNote(researchNotes[2]); + } else + researchNote = getRandomNote(researchNotes[3]); + } + } + + lastUpdate = tile.getGame().getLastUpdate(); + return researchNote; + } + + private String getRandomNote(String[] candidates) { + return candidates[mc.theWorld.rand.nextInt(candidates.length)]; + } +} diff --git a/forestry_common/core/forestry/core/gui/GuiForestry.java b/forestry_common/core/forestry/core/gui/GuiForestry.java new file mode 100755 index 000000000..6ac3fb086 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/GuiForestry.java @@ -0,0 +1,545 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.Collection; +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import forestry.core.config.Config; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.slots.SlotForestry; +import forestry.core.gui.tooltips.IToolTipProvider; +import forestry.core.gui.tooltips.ToolTip; +import forestry.core.gui.tooltips.ToolTipLine; +import forestry.core.interfaces.IClimatised; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.IHintSource; +import forestry.core.interfaces.IOwnable; +import forestry.core.interfaces.IPowerHandler; +import forestry.core.proxy.Proxies; +import forestry.core.utils.FontColour; + +public abstract class GuiForestry extends GuiContainer { + + /* WIDGETS */ + protected WidgetManager widgetManager; + /* LEDGERS */ + protected LedgerManager ledgerManager = new LedgerManager(this); + protected T tile; + public ResourceLocation textureFile; + protected FontColour fontColor; + + public GuiForestry(ContainerForestry container) { + this("", container); + } + + public GuiForestry(String texture, ContainerForestry container) { + this(new ResourceLocation("forestry", texture), container, null); + } + + public GuiForestry(String texture, ContainerForestry container, Object inventory) { + this(new ResourceLocation("forestry", texture), container, inventory); + } + + public GuiForestry(ResourceLocation texture, ContainerForestry container) { + this(texture, container, null); + } + + @SuppressWarnings("unchecked") + public GuiForestry(ResourceLocation texture, ContainerForestry container, Object inventory) { + super(container); + this.widgetManager = new WidgetManager(this); + this.ledgerManager = new LedgerManager(this); + + this.textureFile = texture; + this.inventorySlots = container; + + if (inventory instanceof TileForestry) + this.tile = (T) inventory; + + fontColor = new FontColour(Proxies.common.getSelectedTexturePack(Proxies.common.getClientInstance())); + initLedgers(inventory); + } + + /* LEDGERS */ + protected void initLedgers(Object inventory) { + + if (inventory instanceof IErrorSource && ((IErrorSource) inventory).throwsErrors()) + ledgerManager.add(new ErrorLedger(ledgerManager, (IErrorSource) inventory)); + + if (inventory instanceof IClimatised && ((IClimatised) inventory).isClimatized()) + ledgerManager.add(new ClimateLedger(ledgerManager, (IClimatised) inventory)); + + if (!Config.disableEnergyStat && inventory instanceof IPowerHandler) + ledgerManager.add(new PowerLedger(ledgerManager, (IPowerHandler) inventory)); + + if (!Config.disableHints && inventory instanceof IHintSource && ((IHintSource) inventory).hasHints()) + ledgerManager.add(new HintLedger(ledgerManager, (IHintSource) inventory)); + + if (inventory instanceof IOwnable && ((IOwnable) inventory).isOwnable()) + ledgerManager.add(new OwnerLedger(ledgerManager, (IOwnable) inventory)); + + } + + /* TEXT HELPER FUNCTIONS */ + protected int column0; + protected int column1; + protected int column2; + private int line; + protected float factor = 0.75f; + + protected final void setFactor(float factor) { + this.factor = factor; + } + + protected final void startPage() { + line = 12; + GL11.glPushMatrix(); + GL11.glScalef(factor, factor, factor); + } + + protected final void startPage(int column0, int column1, int column2) { + + this.column0 = column0; + this.column1 = column1; + this.column2 = column2; + + startPage(); + } + + protected final int adjustToFactor(int fixed) { + return (int) (fixed * (1 / factor)); + } + + protected final int getLineY() { + return line; + } + + protected final void newLine() { + line += 12 * factor; + } + + protected final void newLine(int lineHeight) { + line += lineHeight * factor; + } + + protected final void endPage() { + GL11.glPopMatrix(); + } + + protected final void drawRow(String text0, String text1, String text2, int colour0, int colour1, int colour2) { + drawLine(text0, column0, colour0); + drawLine(text1, column1, colour1); + drawLine(text2, column2, colour2); + newLine(); + } + + protected final void drawLine(String text, int x) { + drawLine(text, x, fontColor.get("gui.screen")); + } + + protected final void drawSplitLine(String text, int x, int maxWidth) { + drawSplitLine(text, x, maxWidth, fontColor.get("gui.screen")); + } + + protected final void drawCenteredLine(String text, int x, int width) { + drawCenteredLine(text, x, width, fontColor.get("gui.screen")); + } + + protected final void drawCenteredLine(String text, int x, int width, int color) { + fontRendererObj.drawString(text, (int) ((guiLeft + x) * (1 / factor)) + (adjustToFactor(width) - fontRendererObj.getStringWidth(text)) / 2, + (int) ((guiTop + line) * (1 / factor)), color); + } + + protected final void drawLine(String text, int x, int color) { + fontRendererObj.drawString(text, (int) ((guiLeft + x) * (1 / factor)), (int) ((guiTop + line) * (1 / factor)), color); + } + + protected final void drawSplitLine(String text, int x, int maxWidth, int color) { + fontRendererObj.drawSplitString(text, (int) ((guiLeft + x) * (1 / factor)), (int) ((guiTop + line) * (1 / factor)), (int) (maxWidth * (1 / factor)), color); + } + + public void spinTextureIcon(int par1, int par2, IIcon par3Icon, int par4, int par5, int rotation) { + par1 += width / 2 - xSize / 2; + par2 += height / 2 - ySize / 2; + + float x = par1 + par4 / 2; + float y = par2 + par5 / 2; + GL11.glPushMatrix(); + GL11.glTranslatef(x, y, 0); + GL11.glRotatef(rotation, 0, 0, 1); + GL11.glTranslatef(-x, -y, 0); + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(par1 + 0, par2 + par5, this.zLevel, par3Icon.getMinU(), par3Icon.getMaxV()); + tessellator.addVertexWithUV(par1 + par4, par2 + par5, this.zLevel, par3Icon.getMaxU(), par3Icon.getMaxV()); + tessellator.addVertexWithUV(par1 + par4, par2 + 0, this.zLevel, par3Icon.getMaxU(), par3Icon.getMinV()); + tessellator.addVertexWithUV(par1 + 0, par2 + 0, this.zLevel, par3Icon.getMinU(), par3Icon.getMinV()); + tessellator.draw(); + GL11.glPopMatrix(); + } + + /* CORE GUI HANDLING */ + protected int getCenteredOffset(String string) { + return getCenteredOffset(string, xSize); + } + + protected int getCenteredOffset(String string, int xWidth) { + return (xWidth - fontRendererObj.getStringWidth(string)) / 2; + } + + @Override + protected void mouseClicked(int xPos, int yPos, int mouseButton) { + super.mouseClicked(xPos, yPos, mouseButton); + + // / Handle ledger clicks + ledgerManager.handleMouseClicked(xPos, yPos, mouseButton); + widgetManager.handleMouseClicked(xPos, yPos, mouseButton); + } + + @Override + protected void mouseMovedOrUp(int mouseX, int mouseY, int eventType) { + super.mouseMovedOrUp(mouseX, mouseY, eventType); + + widgetManager.handleMouseRelease(mouseX, mouseY, eventType); + } + + @Override + protected void mouseClickMove(int mouseX, int mouseY, int mouseButton, long time) { + + widgetManager.handleMouseMove(mouseX, mouseY, mouseButton, time); + + Slot slot = getSlotAtPosition(mouseX, mouseY); + if (mouseButton == 1 && slot instanceof SlotForestry && ((SlotForestry) slot).isPhantom()) + return; + super.mouseClickMove(mouseX, mouseY, mouseButton, time); + } + + public Slot getSlotAtPosition(int par1, int par2) { + for (int k = 0; k < this.inventorySlots.inventorySlots.size(); ++k) { + Slot slot = (Slot) this.inventorySlots.inventorySlots.get(k); + + if (isMouseOverSlot(slot, par1, par2)) { + return slot; + } + } + + return null; + } + + public boolean isMouseOverSlot(Slot par1Slot, int par2, int par3) { + return this.func_146978_c(par1Slot.xDisplayPosition, par1Slot.yDisplayPosition, 16, 16, par2, par3); + } + + @SuppressWarnings("rawtypes") + protected void drawTooltip(int mouseX, int mouseY, float zLevel, List information, EnumRarity rarity) { + + if (information.size() > 0) { + this.zLevel = 0f; + itemRender.zLevel = 0f; + + int tooltipWidth = 0; + + for (int i = 0; i < information.size(); ++i) { + int textWidth = this.fontRendererObj.getStringWidth((String) information.get(i)); + + if (textWidth > tooltipWidth) + tooltipWidth = textWidth; + } + + int xPos = mouseX - this.guiLeft + 12; + int yPos = mouseY - this.guiTop - 12; + int var14 = 8; + + if (information.size() > 1) + var14 += 2 + (information.size() - 1) * 10; + + this.zLevel = zLevel; + itemRender.zLevel = zLevel; + int var15 = -267386864; + this.drawGradientRect(xPos - 3, yPos - 4, xPos + tooltipWidth + 3, yPos - 3, var15, var15); + this.drawGradientRect(xPos - 3, yPos + var14 + 3, xPos + tooltipWidth + 3, yPos + var14 + 4, var15, var15); + this.drawGradientRect(xPos - 3, yPos - 3, xPos + tooltipWidth + 3, yPos + var14 + 3, var15, var15); + this.drawGradientRect(xPos - 4, yPos - 3, xPos - 3, yPos + var14 + 3, var15, var15); + this.drawGradientRect(xPos + tooltipWidth + 3, yPos - 3, xPos + tooltipWidth + 4, yPos + var14 + 3, var15, var15); + int var16 = 1347420415; + int var17 = (var16 & 16711422) >> 1 | var16 & -16777216; + this.drawGradientRect(xPos - 3, yPos - 3 + 1, xPos - 3 + 1, yPos + var14 + 3 - 1, var16, var17); + this.drawGradientRect(xPos + tooltipWidth + 2, yPos - 3 + 1, xPos + tooltipWidth + 3, yPos + var14 + 3 - 1, var16, var17); + this.drawGradientRect(xPos - 3, yPos - 3, xPos + tooltipWidth + 3, yPos - 3 + 1, var16, var16); + this.drawGradientRect(xPos - 3, yPos + var14 + 2, xPos + tooltipWidth + 3, yPos + var14 + 3, var17, var17); + + for (int i = 0; i < information.size(); ++i) { + String line = (String) information.get(i); + + if (i == 0) + line = "\u00a7" + rarity.rarityColor.getFormattingCode() + line; + else + line = "\u00a77" + line; + + this.fontRendererObj.drawStringWithShadow(line, xPos, yPos, -1); + + if (i == 0) + yPos += 2; + + yPos += 10; + } + + this.zLevel = 0.0F; + itemRender.zLevel = 0.0F; + } + } + + public void drawToolTips(ToolTip toolTips, int mouseX, int mouseY) { + if (toolTips == null) + return; + if (toolTips.isEmpty()) + return; + + int left = this.guiLeft; + int top = this.guiTop; + int lenght = 0; + int x; + int y; + + for (ToolTipLine tip : toolTips) { + y = this.fontRendererObj.getStringWidth(tip.text); + + if (y > lenght) + lenght = y; + } + + x = mouseX - left + 12; + y = mouseY - top - 12; + int var14 = 8; + + if (toolTips.size() > 1) + var14 += 2 + (toolTips.size() - 1) * 10; + + this.zLevel = 300.0F; + itemRender.zLevel = 300.0F; + int var15 = -267386864; + this.drawGradientRect(x - 3, y - 4, x + lenght + 3, y - 3, var15, var15); + this.drawGradientRect(x - 3, y + var14 + 3, x + lenght + 3, y + var14 + 4, var15, var15); + this.drawGradientRect(x - 3, y - 3, x + lenght + 3, y + var14 + 3, var15, var15); + this.drawGradientRect(x - 4, y - 3, x - 3, y + var14 + 3, var15, var15); + this.drawGradientRect(x + lenght + 3, y - 3, x + lenght + 4, y + var14 + 3, var15, var15); + int var16 = 1347420415; + int var17 = (var16 & 16711422) >> 1 | var16 & -16777216; + this.drawGradientRect(x - 3, y - 3 + 1, x - 3 + 1, y + var14 + 3 - 1, var16, var17); + this.drawGradientRect(x + lenght + 2, y - 3 + 1, x + lenght + 3, y + var14 + 3 - 1, var16, var17); + this.drawGradientRect(x - 3, y - 3, x + lenght + 3, y - 3 + 1, var16, var16); + this.drawGradientRect(x - 3, y + var14 + 2, x + lenght + 3, y + var14 + 3, var17, var17); + + for (ToolTipLine tip : toolTips) { + String line = tip.text; + + if (tip.color == null) + line = "\u00a77" + line; + else + line = "\u00a7" + tip.color.getFormattingCode() + line; + + this.fontRendererObj.drawStringWithShadow(line, x, y, -1); + + y += 10 + tip.getSpacing(); + } + + this.zLevel = 0.0F; + itemRender.zLevel = 0.0F; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + RenderHelper.enableGUIStandardItemLighting(); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glPushMatrix(); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240 / 1.0F, 240 / 1.0F); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + ledgerManager.drawTooltips(mouseX, mouseY); + + InventoryPlayer playerInv = mc.thePlayer.inventory; + + if (playerInv.getItemStack() == null) { + drawToolTips(widgetManager.widgets, mouseX, mouseY); + drawToolTips(buttonList, mouseX, mouseY); + drawToolTips(inventorySlots.inventorySlots, mouseX, mouseY); + } + + GL11.glPopMatrix(); + GL11.glPopAttrib(); + } + + private void drawToolTips(Collection objects, int mouseX, int mouseY) { + for (Object obj : objects) { + if (!(obj instanceof IToolTipProvider)) + continue; + IToolTipProvider provider = (IToolTipProvider) obj; + if (!provider.isToolTipVisible()) + continue; + ToolTip tips = provider.getToolTip(); + if (tips == null) + continue; + boolean mouseOver = provider.isMouseOver(mouseX - guiLeft, mouseY - guiTop); + tips.onTick(mouseOver); + if (mouseOver && tips.isReady()) { + tips.refresh(); + drawToolTips(tips, mouseX, mouseY); + } + } + } + + @Override + protected void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + bindTexture(textureFile); + int x = (width - xSize) / 2; + int y = (height - ySize) / 2; + drawTexturedModalRect(x, y, 0, 0, xSize, ySize); + + int left = this.guiLeft; + int top = this.guiTop; + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + RenderHelper.enableGUIStandardItemLighting(); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glPushMatrix(); + GL11.glTranslatef(left, top, 0.0F); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240 / 1.0F, 240 / 1.0F); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + ledgerManager.drawLedgers(); + widgetManager.drawWidgets(); + + GL11.glPopMatrix(); + GL11.glPopAttrib(); + + bindTexture(textureFile); + } + + protected void bindTexture(ResourceLocation texturePath) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + Proxies.common.bindTexture(texturePath); + } + + public void setZLevel(float level) { + this.zLevel = level; + } + + public static RenderItem getItemRenderer() { + return itemRender; + } + + public int getSizeX() { + return xSize; + } + + public int getSizeY() { + return ySize; + } + + public int getGuiLeft() { + return guiLeft; + } + + public int getGuiTop() { + return guiTop; + } + + @Override + public void drawGradientRect(int par1, int par2, int par3, int par4, int par5, int par6) { + super.drawGradientRect(par1, par2, par3, par4, par5, par6); + } + // + // protected void drawGuiContainerForegroundLayer() { + // } + + /** + * Draws the basic background texture centered on the screen. + */ + // protected void drawBackground() { + // drawBackground((this.width - this.xSize) / 2, (this.height - this.ySize) / 2, this.xSize, this.ySize); + // } + // protected void drawBackground(int x, int y, int w, int h) { + // bindTexture(); + // this.drawTexturedModalRect(x, y, 0, 0, w, h); + // } + // protected void bindTexture() { + // bindTexture(textureFile); + // } + // + // protected void drawSlotInventory(Slot slot) { + // + // int xPos = slot.xDisplayPosition; + // int yPos = slot.yDisplayPosition; + // ItemStack slotStack = slot.getStack(); + // boolean backgroundDrawn = false; + // + // this.zLevel = 100.0F; + // itemRenderer.zLevel = 100.0F; + // + // if (slotStack == null) { + // IIcon icon = slot.getBackgroundIconIndex(); + // + // if (icon != null) { + // GL11.glDisable(GL11.GL_LIGHTING); + // GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + // Proxies.common.bindTexture(SpriteSheet.ITEMS); + // this.drawTexturedModelRectFromIcon(xPos, yPos, icon, 16, 16); + // GL11.glEnable(GL11.GL_LIGHTING); + // backgroundDrawn = true; + // } + // } + // + // if (!backgroundDrawn && slotStack != null) + // drawItemStack(slotStack, xPos, yPos); + // + // this.zLevel = 0.0F; + // itemRenderer.zLevel = 0.0F; + // } + public void drawItemStack(ItemStack stack, int xPos, int yPos) { + GL11.glTranslatef(0.0F, 0.0F, 32.0F); + this.zLevel = 100.0F; + itemRender.zLevel = 100.0F; + FontRenderer font = null; + if (stack != null) + font = stack.getItem().getFontRenderer(stack); + if (font == null) + font = fontRendererObj; + itemRender.renderItemAndEffectIntoGUI(font, this.mc.getTextureManager(), stack, xPos, yPos); + itemRender.renderItemOverlayIntoGUI(font, this.mc.getTextureManager(), stack, xPos, yPos); + this.zLevel = 0.0F; + itemRender.zLevel = 0.0F; + } +} diff --git a/forestry_common/core/forestry/core/gui/GuiNaturalistInventory.java b/forestry_common/core/forestry/core/gui/GuiNaturalistInventory.java new file mode 100755 index 000000000..5cf6393c1 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/GuiNaturalistInventory.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.HashMap; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileForestry; +import forestry.core.genetics.EnumMutateChance; +import forestry.core.gui.buttons.GuiBetterButton; +import forestry.core.gui.buttons.StandardButtonTextureSets; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StringUtil; + +public class GuiNaturalistInventory extends GuiForestry { + private final ISpeciesRoot speciesRoot; + private final IBreedingTracker breedingTracker; + private final HashMap iconStacks = new HashMap(); + private final int pageCurrent, pageMax; + + public GuiNaturalistInventory(ISpeciesRoot speciesRoot, EntityPlayer player, ContainerForestry container, IPagedInventory inventory, int page, int maxPages) { + super(Defaults.TEXTURE_PATH_GUI + "/apiaristinventory.png", container, inventory); + + this.speciesRoot = speciesRoot; + + this.pageCurrent = page; + this.pageMax = maxPages; + + xSize = 196; + ySize = 202; + + for (IIndividual individual : speciesRoot.getIndividualTemplates()) { + iconStacks.put(individual.getIdent(), speciesRoot.getMemberStack(individual, 0)); + } + + breedingTracker = speciesRoot.getBreedingTracker(player.worldObj, player.getGameProfile().getId()); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float f, int i, int j) { + super.drawGuiContainerBackgroundLayer(f, i, j); + String header = StringUtil.localize("gui.page") + " " + (pageCurrent + 1) + "/" + pageMax; + fontRendererObj.drawString(header, guiLeft + 95 + getCenteredOffset(header, 98), guiTop + 10, fontColor.get("gui.title")); + + IIndividual individual = getIndividualAtPosition(i, j); + if (individual == null) + displayBreedingStatistics(10); + + if (individual != null) { + RenderHelper.enableGUIStandardItemLighting(); + startPage(); + + displaySpeciesInformation(true, individual.getGenome().getPrimary(), iconStacks.get(individual.getIdent()), 10); + if (!individual.isPureBred(0)) + displaySpeciesInformation(individual.isAnalyzed(), individual.getGenome().getSecondary(), iconStacks.get(individual.getGenome().getSecondary().getUID()), + 10); + + endPage(); + } + } + + @SuppressWarnings("unchecked") + @Override + public void initGui() { + super.initGui(); + + buttonList.add(new GuiBetterButton(1, guiLeft + 99, guiTop + 7, StandardButtonTextureSets.LEFT_BUTTON_SMALL)); + buttonList.add(new GuiBetterButton(2, guiLeft + 180, guiTop + 7, StandardButtonTextureSets.RIGHT_BUTTON_SMALL)); + } + + private void flipPage(int page) { + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = page; + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + } + + @Override + protected void actionPerformed(GuiButton guibutton) { + super.actionPerformed(guibutton); + + if (guibutton.id == 1 && pageCurrent > 0) + flipPage(pageCurrent - 1); + else if (guibutton.id == 2 && pageCurrent < pageMax - 1) + flipPage(pageCurrent + 1); + } + + private IIndividual getIndividualAtPosition(int x, int y) { + Slot slot = getSlotAtPosition(x, y); + if (slot == null) + return null; + + if (!slot.getHasStack()) + return null; + + if (!slot.getStack().hasTagCompound()) + return null; + + if (!speciesRoot.isMember(slot.getStack())) + return null; + + return speciesRoot.getMember(slot.getStack()); + } + + private void displayBreedingStatistics(int x) { + + startPage(); + + drawLine(StringUtil.localize("gui.speciescount") + ": " + breedingTracker.getSpeciesBred() + "/" + speciesRoot.getSpeciesCount(), x); + newLine(); + newLine(); + + if (breedingTracker instanceof IApiaristTracker) { + IApiaristTracker tracker = (IApiaristTracker) breedingTracker; + drawLine(StringUtil.localize("gui.queens") + ": " + tracker.getQueenCount(), x); + newLine(); + + drawLine(StringUtil.localize("gui.princesses") + ": " + tracker.getPrincessCount(), x); + newLine(); + + drawLine(StringUtil.localize("gui.drones") + ": " + tracker.getDroneCount(), x); + newLine(); + } + + endPage(); + } + + private void displaySpeciesInformation(boolean analyzed, IAlleleSpecies species, ItemStack iconStack, int x) { + + if (!analyzed) { + drawLine(StringUtil.localize("gui.unknown"), x); + return; + } + + drawLine(species.getName(), x); + RenderHelper.enableGUIStandardItemLighting(); + drawItemStack(iconStack, adjustToFactor(guiLeft + x + 69), adjustToFactor(guiTop + getLineY() - 2)); + RenderHelper.disableStandardItemLighting(); + + newLine(); + + // Viable Combinations + int columnWidth = 16; + int column = 10; + + for (IMutation combination : speciesRoot.getCombinations(species)) { + if (combination.isSecret()) + continue; + + if (breedingTracker.isDiscovered(combination)) + drawMutationIcon(combination, species, column); + else + drawUnknownIcon(combination, column); + + column += columnWidth; + if (column > 75) { + column = 10; + newLine(18); + } + } + + newLine(); + newLine(); + } + + private void drawMutationIcon(IMutation combination, IAlleleSpecies species, int x) { + + RenderHelper.enableGUIStandardItemLighting(); + drawItemStack(iconStacks.get(combination.getPartner(species).getUID()), adjustToFactor(guiLeft + x), + adjustToFactor(guiTop + getLineY())); + RenderHelper.disableStandardItemLighting(); + + int line = 48; + int column = 0; + EnumMutateChance chance = EnumMutateChance.rateChance(combination.getBaseChance()); + if (chance == EnumMutateChance.HIGHEST) { + line += 16; + column = 228; + } else if (chance == EnumMutateChance.HIGHER) { + line += 16; + column = 212; + } else if (chance == EnumMutateChance.HIGH) { + line += 16; + column = 196; + } else if (chance == EnumMutateChance.NORMAL) { + line += 0; + column = 228; + } else if (chance == EnumMutateChance.LOW) { + line += 0; + column = 212; + } else { + line += 0; + column = 196; + } + + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect(adjustToFactor(guiLeft + x), adjustToFactor(guiTop + getLineY()), column, line, 16, 16); + + } + + private void drawUnknownIcon(IMutation mutation, int x) { + + float chance = mutation.getBaseChance(); + + int line = 0; + int column = 0; + if (chance >= 20) { + line = 16; + column = 228; + } else if (chance >= 15) { + line = 16; + column = 212; + } else if (chance >= 12) { + line = 16; + column = 196; + } else if (chance >= 10) { + line = 0; + column = 228; + } else if (chance >= 5) { + line = 0; + column = 212; + } else { + line = 0; + column = 196; + } + + Proxies.common.bindTexture(textureFile); + drawTexturedModalRect(adjustToFactor(guiLeft + x), adjustToFactor(guiTop + getLineY()), column, line, 16, 16); + } + + @Override + protected boolean checkHotbarKeys(int key) { + return false; + } +} diff --git a/forestry_common/core/forestry/core/gui/GuiTextBox.java b/forestry_common/core/forestry/core/gui/GuiTextBox.java new file mode 100755 index 000000000..da26bc4de --- /dev/null +++ b/forestry_common/core/forestry/core/gui/GuiTextBox.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.Iterator; +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiTextField; + +public class GuiTextBox extends GuiTextField { + + private final FontRenderer fontRendererObj; + + private final int startX, startY, width, height; + private final int enabledColor = 14737632; + private final int disabledColor = 7368816; + + private int lineScroll = 0; + private int maxLines = 0; + + public GuiTextBox(FontRenderer fontRendererObj, int startX, int startY, int width, int height) { + super(fontRendererObj, startX, startY, width, height); + this.fontRendererObj = fontRendererObj; + this.startX = startX; + this.startY = startY; + this.width = width; + this.height = height; + } + + private int getLineScrollOffset() { + return 0; + } + + public void advanceLine() { + if(lineScroll < maxLines - 1) + lineScroll++; + } + + public void regressLine() { + if(lineScroll > 0) + lineScroll--; + } + + public boolean moreLinesAllowed() { + return fontRendererObj.listFormattedStringToWidth(getCursoredText(), width).size() * fontRendererObj.FONT_HEIGHT < height; + } + + private String getCursoredText() { + if(!isFocused()) + return getText(); + + int cursorPos = getCursorPosition() - getLineScrollOffset(); + String text = getText(); + if(cursorPos < 0) + return text; + if(cursorPos >= text.length()) + return text + "_"; + return text.substring(0, cursorPos) + "_" + text.substring(cursorPos); + } + + @SuppressWarnings("unchecked") + private void drawScrolledSplitString(String text, int startX, int startY, int width, int textColour) { + List list = fontRendererObj.listFormattedStringToWidth(text, width); + maxLines = list.size(); + + int count = 0; + int lineY = startY; + + for (Iterator iterator = list.iterator(); iterator.hasNext();) { + if(count < lineScroll) { + count++; + continue; + } + else if(lineY + fontRendererObj.FONT_HEIGHT - startY > height) + break; + + String line = iterator.next(); + fontRendererObj.drawString(line, startX, lineY, textColour); + lineY += fontRendererObj.FONT_HEIGHT; + + count++; + } + + } + + @Override + public void drawTextBox() { + if(!getVisible()) + return; + + if(getEnableBackgroundDrawing()) { + drawRect(startX - 1, startY - 1, startX + this.width + 1, startY + this.height + 1, -6250336); + drawRect(startX, startY, startX + this.width, startY + this.height, -16777216); + } + + int textColour = isFocused() ? this.enabledColor : this.disabledColor; + + drawScrolledSplitString(getCursoredText(), startX + 2, startY + 2, width - 4, textColour); + } + +} diff --git a/forestry_common/core/forestry/core/gui/HintLedger.java b/forestry_common/core/forestry/core/gui/HintLedger.java new file mode 100755 index 000000000..c997858da --- /dev/null +++ b/forestry_common/core/forestry/core/gui/HintLedger.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.Random; + +import forestry.core.interfaces.IHintSource; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class HintLedger extends Ledger { + + int position; + String[] hints; + + public HintLedger(LedgerManager manager, IHintSource tile) { + super(manager); + this.hints = tile.getHints(); + maxHeight = 96; + position = new Random().nextInt(hints.length); + overlayColor = manager.gui.fontColor.get("ledger.hint.background"); + } + + @Override + public void draw(int x, int y) { + + // Draw background + drawBackground(x, y); + + // Draw icon + drawIcon(TextureManager.getInstance().getDefault("misc/hint"), x + 3, y + 4); + + if (!isFullyOpened()) + return; + + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.didyouknow") + "?", x + 22, y + 8, + manager.gui.fontColor.get("ledger.hint.header")); + manager.minecraft.fontRenderer.drawSplitString(StringUtil.localize("hints." + hints[position] + ".desc"), x + 22, y + 20, maxWidth - 28, + manager.gui.fontColor.get("ledger.hint.text")); + + } + + @Override + public String getTooltip() { + return StringUtil.localize("hints." + hints[position] + ".tag"); + } + +} diff --git a/forestry_common/core/forestry/core/gui/IGuiSelectable.java b/forestry_common/core/forestry/core/gui/IGuiSelectable.java new file mode 100755 index 000000000..a1d72f470 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/IGuiSelectable.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.core.network.PacketUpdate; + +public interface IGuiSelectable { + void handleSelectionChange(EntityPlayer player, PacketUpdate packet); + + void setSelection(PacketUpdate packet); +} diff --git a/forestry_common/core/forestry/core/gui/IPagedInventory.java b/forestry_common/core/forestry/core/gui/IPagedInventory.java new file mode 100755 index 000000000..ad7b0984e --- /dev/null +++ b/forestry_common/core/forestry/core/gui/IPagedInventory.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; + +/** + * + * @author CovertJaguar + */ +public interface IPagedInventory extends IInventory { + + void flipPage(EntityPlayer player, int page); +} diff --git a/forestry_common/core/forestry/core/gui/Ledger.java b/forestry_common/core/forestry/core/gui/Ledger.java new file mode 100755 index 000000000..360ac50f9 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/Ledger.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.Defaults; +import forestry.core.config.SessionVars; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.utils.ForestryResource; + +/** + * Side ledger for guis + */ +public abstract class Ledger { + + private static final int OPEN_SPEED = 8; + private static final ResourceLocation ledgerTexture = new ForestryResource(Defaults.TEXTURE_PATH_GUI + "/ledger.png"); + + protected LedgerManager manager; + + private boolean open; + + protected int overlayColor = 0xffffff; + + public int currentShiftX = 0; + public int currentShiftY = 0; + + protected int limitWidth = 128; + protected int maxWidth = 124; + protected int minWidth = 24; + protected int currentWidth = minWidth; + + protected int maxHeight = 24; + protected int minHeight = 24; + protected int currentHeight = minHeight; + + public Ledger(LedgerManager manager) { + this.manager = manager; + } + + public void update() { + // Width + if (open && currentWidth < maxWidth) + currentWidth += OPEN_SPEED; + else if (!open && currentWidth > minWidth) { + currentWidth -= OPEN_SPEED; + currentWidth = currentWidth > minWidth ? currentWidth : minWidth; + } + + // Height + if (open && currentHeight < maxHeight) + currentHeight += OPEN_SPEED; + else if (!open && currentHeight > minHeight) { + currentHeight -= OPEN_SPEED; + currentHeight = currentHeight > minHeight ? currentHeight : minHeight; + } + } + + public int getHeight() { + return currentHeight; + } + + public abstract void draw(int x, int y); + public abstract String getTooltip(); + + public boolean handleMouseClicked(int x, int y, int mouseButton) { + return false; + } + + public boolean intersectsWith(int mouseX, int mouseY, int shiftX, int shiftY) { + + if (mouseX >= shiftX && mouseX <= shiftX + currentWidth && mouseY >= shiftY && mouseY <= shiftY + getHeight()) + return true; + + return false; + } + + public void setFullyOpen() { + open = true; + currentWidth = maxWidth; + currentHeight = maxHeight; + } + + public void toggleOpen() { + if (open) { + open = false; + SessionVars.setOpenedLedger(null); + } else { + open = true; + SessionVars.setOpenedLedger(this.getClass()); + } + } + + public boolean isVisible() { + return true; + } + + public boolean isOpen() { + return this.open; + } + + protected boolean isFullyOpened() { + return currentWidth >= maxWidth; + } + + protected void drawBackground(int x, int y) { + + float colorR = (overlayColor >> 16 & 255) / 255.0F; + float colorG = (overlayColor >> 8 & 255) / 255.0F; + float colorB = (overlayColor & 255) / 255.0F; + + GL11.glColor4f(colorR, colorG, colorB, 1.0F); + + Proxies.common.bindTexture(ledgerTexture); + + manager.gui.drawTexturedModalRect(x, y, 0, 256 - currentHeight, 4, currentHeight); + manager.gui.drawTexturedModalRect(x + 4, y, 256 - currentWidth + 4, 0, currentWidth - 4, 4); + manager.gui.drawTexturedModalRect(x, y, 0, 0, 4, 4); + + manager.gui.drawTexturedModalRect(x + 4, y + 4, 256 - currentWidth + 4, 256 - currentHeight + 4, currentWidth - 4, currentHeight - 4); + + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + } + + protected void drawIcon(IIcon icon, int x, int y) { + + if (icon != null) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + Proxies.common.bindTexture(SpriteSheet.ITEMS); + manager.gui.drawTexturedModelRectFromIcon(x, y, icon, 16, 16); + GL11.glEnable(GL11.GL_LIGHTING); + } + + } +} diff --git a/forestry_common/core/forestry/core/gui/LedgerManager.java b/forestry_common/core/forestry/core/gui/LedgerManager.java new file mode 100755 index 000000000..6bf09138d --- /dev/null +++ b/forestry_common/core/forestry/core/gui/LedgerManager.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.ArrayList; + +import net.minecraft.client.Minecraft; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.SessionVars; +import forestry.core.gadgets.TileForestry; +import forestry.core.proxy.Proxies; + +public class LedgerManager { + + public GuiForestry gui; + public Minecraft minecraft; + + protected ArrayList ledgers = new ArrayList(); + + public LedgerManager(GuiForestry gui) { + this.gui = gui; + this.minecraft = Proxies.common.getClientInstance(); + } + + public void add(Ledger ledger) { + this.ledgers.add(ledger); + if (SessionVars.getOpenedLedger() != null && ledger.getClass().equals(SessionVars.getOpenedLedger())) + ledger.setFullyOpen(); + } + + /** + * Inserts a ledger into the next-to-last position. + * + * @param ledger + */ + public void insert(Ledger ledger) { + this.ledgers.add(ledgers.size() - 1, ledger); + } + + protected Ledger getAtPosition(int mX, int mY) { + + int xShift = ((gui.width - gui.getSizeX()) / 2) + gui.getSizeX(); + int yShift = ((gui.height - gui.getSizeY()) / 2) + 8; + + for (int i = 0; i < ledgers.size(); i++) { + Ledger ledger = ledgers.get(i); + if (!ledger.isVisible()) + continue; + + ledger.currentShiftX = xShift; + ledger.currentShiftY = yShift; + if (ledger.intersectsWith(mX, mY, xShift, yShift)) + return ledger; + + yShift += ledger.getHeight(); + } + + return null; + } + + protected void drawLedgers() { + + int xPos = 8; + for (Ledger ledger : ledgers) { + + ledger.update(); + if (!ledger.isVisible()) + continue; + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + ledger.draw(gui.getSizeX(), xPos); + xPos += ledger.getHeight(); + } + } + + protected void drawTooltips(int mouseX, int mouseY) { + + Ledger ledger = getAtPosition(mouseX, mouseY); + if (ledger != null) { + int startX = mouseX - ((gui.width - gui.getSizeX()) / 2) + 12; + int startY = mouseY - ((gui.height - gui.getSizeY()) / 2) - 12; + + String tooltip = ledger.getTooltip(); + int textWidth = minecraft.fontRenderer.getStringWidth(tooltip); + gui.drawGradientRect(startX - 3, startY - 3, startX + textWidth + 3, startY + 8 + 3, 0xc0000000, 0xc0000000); + minecraft.fontRenderer.drawStringWithShadow(tooltip, startX, startY, -1); + } + + } + + public void handleMouseClicked(int x, int y, int mouseButton) { + + if (mouseButton == 0) { + + Ledger ledger = this.getAtPosition(x, y); + + // Default action only if the mouse click was not handled by the + // ledger itself. + if (ledger != null && !ledger.handleMouseClicked(x, y, mouseButton)) { + + for (Ledger other : ledgers) + if (other != ledger && other.isOpen()) + other.toggleOpen(); + ledger.toggleOpen(); + } + } + + } + +} diff --git a/forestry_common/core/forestry/core/gui/OwnerLedger.java b/forestry_common/core/forestry/core/gui/OwnerLedger.java new file mode 100755 index 000000000..cf9b78106 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/OwnerLedger.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.Locale; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; + +import forestry.core.interfaces.IOwnable; +import forestry.core.network.PacketCoordinates; +import forestry.core.network.PacketIds; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.EnumAccess; +import forestry.core.utils.StringUtil; + +/** + * Ledger displaying ownership information + */ +public class OwnerLedger extends Ledger { + + IOwnable tile; + + public OwnerLedger(LedgerManager manager, IOwnable tile) { + super(manager); + this.tile = tile; + } + + public boolean isAccessButton(int mouseX, int mouseY) { + + int shiftX = currentShiftX; + int shiftY = currentShiftY + 44; + + if (mouseX >= shiftX && mouseX <= currentShiftX + currentWidth && mouseY >= shiftY && mouseY <= shiftY + 12) + return true; + return false; + } + + public boolean isOwnerChangeButton(int mouseX, int mouseY) { + return false; + } + + @Override + public void draw(int x, int y) { + + // Update state + boolean playerIsOwner = tile.isOwner(manager.minecraft.thePlayer); + EnumAccess access = tile.getAccess(); + + if (playerIsOwner) + maxHeight = 60; + else + maxHeight = 36; + + // Draw background + drawBackground(x, y); + + // Draw icon + IIcon accessIcon = TextureManager.getInstance().getDefault("misc/access." + access.toString().toLowerCase(Locale.ENGLISH)); + drawIcon(accessIcon, x + 3, y + 4); + + // Draw description + if (!isFullyOpened()) + return; + + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.owner"), x + 22, y + 8, manager.gui.fontColor.get("ledger.owner.header")); + + String owner; + if ((owner = tile.getOwnerName()) == null) + owner = StringUtil.localize("gui.derelict"); + + manager.minecraft.fontRenderer.drawString(owner, x + 22, y + 20, manager.gui.fontColor.get("ledger.owner.text")); + + if (!playerIsOwner) + return; + + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.access") + ":", x + 22, y + 32, + manager.gui.fontColor.get("ledger.owner.subheader")); + // Access rules + drawIcon(accessIcon, x + 20, y + 40); + manager.minecraft.fontRenderer.drawString(StringUtil.localize(access.getName()), x + 38, y + 44, manager.gui.fontColor.get("ledger.owner.text")); + + } + + @Override + public String getTooltip() { + if (tile.getOwnerName() != null) + return StringUtil.localize("gui.owner") + ": " + tile.getOwnerName(); + else + return StringUtil.localize("gui.derelict"); + } + + @Override + public boolean handleMouseClicked(int x, int y, int mouseButton) { + + if (isAccessButton(x, y)) { + if (!Proxies.common.isSimulating(((TileEntity) tile).getWorldObj())) { + TileEntity te = (TileEntity) tile; + Proxies.net.sendToServer(new PacketCoordinates(PacketIds.ACCESS_SWITCH, te.xCoord, te.yCoord, te.zCoord)); + } + + tile.switchAccessRule(manager.minecraft.thePlayer); + return true; + } + + return false; + } + +} diff --git a/forestry_common/core/forestry/core/gui/PlainLedger.java b/forestry_common/core/forestry/core/gui/PlainLedger.java new file mode 100755 index 000000000..f8d28f9f7 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/PlainLedger.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import net.minecraft.util.IIcon; + +/** + * A simple ledger displaying an icon and one-line description. + */ +public class PlainLedger extends Ledger { + + private IIcon icon; + private String text; + + public PlainLedger(LedgerManager manager, IIcon icon, String text) { + super(manager); + this.icon = icon; + this.text = text; + } + + @Override + public void draw(int x, int y) { + + // Correct maximum width + int textWidth = manager.minecraft.fontRenderer.getStringWidth(getTooltip()); + this.maxWidth = textWidth + 24 + 4; + + // Draw background + drawBackground(x, y); + + // Draw icon + drawIcon(icon, x + 3, y + 4); + + // Draw description + if (isFullyOpened()) + manager.minecraft.fontRenderer.drawString(getTooltip(), x + 22, y + 8, 0x000000); + } + + @Override + public String getTooltip() { + return text; + } +} diff --git a/forestry_common/core/forestry/core/gui/PowerLedger.java b/forestry_common/core/forestry/core/gui/PowerLedger.java new file mode 100755 index 000000000..e9a237287 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/PowerLedger.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import buildcraft.api.power.PowerHandler; + +import forestry.core.interfaces.IPowerHandler; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class PowerLedger extends Ledger { + + IPowerHandler tile; + + public PowerLedger(LedgerManager manager, IPowerHandler tile) { + super(manager); + this.tile = tile; + maxHeight = 94; + overlayColor = manager.gui.fontColor.get("ledger.power.background"); + } + + @Override + public void draw(int x, int y) { + // Draw background + drawBackground(x, y); + + // Draw icon + drawIcon(TextureManager.getInstance().getDefault("misc/energy"), x + 3, y + 4); + + if (!isFullyOpened()) + return; + + PowerHandler handler = tile.getPowerHandler(); + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.energy"), x + 22, y + 8, manager.gui.fontColor.get("ledger.power.header")); + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.stored") + ":", x + 22, y + 20, + manager.gui.fontColor.get("ledger.power.subheader")); + manager.minecraft.fontRenderer.drawString(handler.getEnergyStored() + " MJ", x + 22, y + 32, manager.gui.fontColor.get("ledger.power.text")); + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.maxenergy") + ":", x + 22, y + 44, + manager.gui.fontColor.get("ledger.power.subheader")); + manager.minecraft.fontRenderer.drawString(handler.getMaxEnergyStored() + " MJ", x + 22, y + 56, manager.gui.fontColor.get("ledger.power.text")); + manager.minecraft.fontRenderer.drawStringWithShadow(StringUtil.localize("gui.maxenergyreceive") + ":", x + 22, y + 68, + manager.gui.fontColor.get("ledger.power.subheader")); + manager.minecraft.fontRenderer.drawString(handler.getMaxEnergyReceived() + " MJ", x + 22, y + 80, manager.gui.fontColor.get("ledger.power.text")); + + } + + @Override + public String getTooltip() { + return tile.getPowerHandler().getEnergyStored() + " MJ"; + } + +} diff --git a/forestry_common/core/forestry/core/gui/WidgetManager.java b/forestry_common/core/forestry/core/gui/WidgetManager.java new file mode 100755 index 000000000..6f2d0144b --- /dev/null +++ b/forestry_common/core/forestry/core/gui/WidgetManager.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui; + +import java.util.ArrayList; + +import net.minecraft.client.Minecraft; + +import org.lwjgl.opengl.GL11; + +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.widgets.Widget; +import forestry.core.proxy.Proxies; + +public class WidgetManager { + + public GuiForestry gui; + public Minecraft minecraft; + protected ArrayList widgets = new ArrayList(); + + public WidgetManager(GuiForestry gui) { + this.gui = gui; + this.minecraft = Proxies.common.getClientInstance(); + } + + public void add(Widget slot) { + this.widgets.add(slot); + } + + public void remove(Widget slot) { + this.widgets.remove(slot); + } + + public void clear() { + this.widgets.clear(); + } + + protected Widget getAtPosition(int mX, int mY) { + for (Widget slot : widgets) { + if (slot.isMouseOver(mX, mY)) + return slot; + } + + return null; + } + + public void drawWidgets() { + gui.setZLevel(100.0F); + GuiForestry.getItemRenderer().zLevel = 100.0F; + for (Widget slot : widgets) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + slot.draw(0, 0); + } + gui.setZLevel(0.0F); + GuiForestry.getItemRenderer().zLevel = 0.0F; + + } + + public void handleMouseClicked(int mouseX, int mouseY, int mouseButton) { + Widget slot = getAtPosition(mouseX - gui.getGuiLeft(), mouseY - gui.getGuiTop()); + if (slot != null) + slot.handleMouseClick(mouseX, mouseY, mouseButton); + } + + public void handleMouseRelease(int mouseX, int mouseY, int eventType) { + for (Widget slot : widgets) { + slot.handleMouseRelease(mouseX, mouseY, eventType); + } + } + + public void handleMouseMove(int mouseX, int mouseY, int mouseButton, long time) { + for (Widget slot : widgets) { + slot.handleMouseMove(mouseX, mouseY, mouseButton, time); + } + } +} diff --git a/forestry_common/core/forestry/core/gui/buttons/ButtonTextureSet.java b/forestry_common/core/forestry/core/gui/buttons/ButtonTextureSet.java new file mode 100755 index 000000000..485c12ea8 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/ButtonTextureSet.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +/** + * + * @author CovertJaguar + */ +public class ButtonTextureSet implements IButtonTextureSet { + + private final int x, y, height, width; + + public ButtonTextureSet(int x, int y, int height, int width) { + this.x = x; + this.y = y; + this.height = height; + this.width = width; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getWidth() { + return width; + } + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/GuiBetterButton.java b/forestry_common/core/forestry/core/gui/buttons/GuiBetterButton.java new file mode 100755 index 000000000..5788d34e9 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/GuiBetterButton.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.ResourceLocation; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.Defaults; +import forestry.core.gui.tooltips.IToolTipProvider; +import forestry.core.gui.tooltips.ToolTip; + +@SideOnly(Side.CLIENT) +public class GuiBetterButton extends GuiButton implements IToolTipProvider{ + + private static final ResourceLocation TEXTURE = new ResourceLocation("forestry", Defaults.TEXTURE_PATH_GUI + "/buttons.png"); + protected IButtonTextureSet texture; + private ToolTip toolTip; + private boolean useTexWidth = false; + + public GuiBetterButton(int id, int x, int y, String label) { + this(id, x, y, 200, StandardButtonTextureSets.LARGE_BUTTON, label); + } + + public GuiBetterButton(int id, int x, int y, int width, String label) { + this(id, x, y, width, StandardButtonTextureSets.LARGE_BUTTON, label); + } + + public GuiBetterButton(int id, int x, int y, int width, IButtonTextureSet texture, String label) { + super(id, x, y, width, texture.getHeight(), label); + this.texture = texture; + } + + public GuiBetterButton(int id, int x, int y, IButtonTextureSet texture) { + super(id, x, y, texture.getWidth(), texture.getHeight(), ""); + this.texture = texture; + useTexWidth = true; + } + + public GuiBetterButton setTexture(IButtonTextureSet texture) { + this.texture = texture; + width = texture.getWidth(); + height = texture.getHeight(); + return this; + } + + public GuiBetterButton setUseTextureWidth() { + useTexWidth = true; + return this; + } + + public GuiBetterButton setWidth(int width) { + this.width = width; + useTexWidth = false; + return this; + } + + public GuiBetterButton setLabel(String label) { + this.displayString = label; + return this; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return texture.getHeight(); + } + + public int getTextColor(boolean mouseOver) { + if (!enabled) + return 0xffa0a0a0; + else if (mouseOver) + return 0xffffa0; + else + return 0xe0e0e0; + } + + public boolean isMouseOverButton(int mouseX, int mouseY) { + return mouseX >= xPosition && mouseY >= yPosition && mouseX < xPosition + getWidth() && mouseY < yPosition + getHeight(); + } + + protected void bindButtonTextures(Minecraft minecraft) { + minecraft.renderEngine.bindTexture(TEXTURE); + } + + @Override + public void drawButton(Minecraft minecraft, int mouseX, int mouseY) { + if (!visible) + return; + FontRenderer fontrenderer = minecraft.fontRenderer; + bindButtonTextures(minecraft); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + int xOffset = texture.getX(); + int yOffset = texture.getY(); + int h = texture.getHeight(); + int w = texture.getWidth(); + boolean mouseOver = isMouseOverButton(mouseX, mouseY); + int hoverState = getHoverState(mouseOver); + if (useTexWidth) { + drawTexturedModalRect(xPosition, yPosition, xOffset, yOffset + hoverState * h, w, h); + } else { + drawTexturedModalRect(xPosition, yPosition, xOffset, yOffset + hoverState * h, width / 2, h); + drawTexturedModalRect(xPosition + width / 2, yPosition, xOffset + w - width / 2, yOffset + hoverState * h, width / 2, h); + } + mouseDragged(minecraft, mouseX, mouseY); + drawCenteredString(fontrenderer, displayString, xPosition + getWidth() / 2, yPosition + (h - 8) / 2, getTextColor(mouseOver)); + } + + @Override + public ToolTip getToolTip() { + return toolTip; + } + + public void setToolTip(ToolTip tips) { + this.toolTip = tips; + } + + @Override + public boolean isToolTipVisible() { + return visible; + } + + @Override + public boolean isMouseOver(int mouseX, int mouseY) { + return isMouseOverButton(mouseX, mouseY); + } +} diff --git a/forestry_common/core/forestry/core/gui/buttons/GuiButtonSmall.java b/forestry_common/core/forestry/core/gui/buttons/GuiButtonSmall.java new file mode 100755 index 000000000..479de8e43 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/GuiButtonSmall.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class GuiButtonSmall extends GuiBetterButton { + + public GuiButtonSmall(int i, int x, int y, String s) { + this(i, x, y, 200, s); + } + + public GuiButtonSmall(int i, int x, int y, int w, String s) { + super(i, x, y, w, StandardButtonTextureSets.SMALL_BUTTON, s); + } + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/GuiMultiButton.java b/forestry_common/core/forestry/core/gui/buttons/GuiMultiButton.java new file mode 100755 index 000000000..3e9813246 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/GuiMultiButton.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import forestry.core.gui.tooltips.ToolTip; + +/** + * + * @author CovertJaguar + */ +@SideOnly(Side.CLIENT) +public class GuiMultiButton extends GuiBetterButton { + + private final MultiButtonController control; + public boolean canChange = true; + + public GuiMultiButton(int id, int x, int y, int width, MultiButtonController control) { + super(id, x, y, width, StandardButtonTextureSets.LARGE_BUTTON, ""); + this.control = control; + } + + @Override + public int getHeight() { + return texture.getHeight(); + } + + @Override + public void drawButton(Minecraft minecraft, int x, int y) { + if (!visible) { + return; + } + FontRenderer fontrenderer = minecraft.fontRenderer; + bindButtonTextures(minecraft); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + IMultiButtonState state = control.getButtonState(); + IButtonTextureSet tex = state.getTextureSet(); + int xOffset = tex.getX(); + int yOffset = tex.getY(); + int h = tex.getHeight(); + int w = tex.getWidth(); + boolean flag = x >= xPosition && y >= yPosition && x < xPosition + width && y < yPosition + h; + int hoverState = getHoverState(flag); + drawTexturedModalRect(xPosition, yPosition, xOffset, yOffset + hoverState * h, width / 2, h); + drawTexturedModalRect(xPosition + width / 2, yPosition, xOffset + w - width / 2, yOffset + hoverState * h, width / 2, h); + mouseDragged(minecraft, x, y); + displayString = state.getLabel(); + if (!displayString.equals("")) { + if (!enabled) { + drawCenteredString(fontrenderer, displayString, xPosition + width / 2, yPosition + (h - 8) / 2, 0xffa0a0a0); + } else if (flag) { + drawCenteredString(fontrenderer, displayString, xPosition + width / 2, yPosition + (h - 8) / 2, 0xffffa0); + } else { + drawCenteredString(fontrenderer, displayString, xPosition + width / 2, yPosition + (h - 8) / 2, 0xe0e0e0); + } + } + } + + @Override + public boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY) { + boolean pressed = super.mousePressed(minecraft, mouseX, mouseY); + if (canChange && pressed && enabled) { + if (Mouse.getEventButton() == 0) { + control.incrementState(); + } else { + control.decrementState(); + } + } + return pressed; + } + + public MultiButtonController getController() { + return control; + } + + @Override + public ToolTip getToolTip() { + ToolTip tip = control.getButtonState().getToolTip(); + if (tip != null) { + return tip; + } + return super.getToolTip(); + } + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/GuiToggleButton.java b/forestry_common/core/forestry/core/gui/buttons/GuiToggleButton.java new file mode 100755 index 000000000..3a199ba06 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/GuiToggleButton.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +public class GuiToggleButton extends GuiBetterButton { + + public boolean active; + + public GuiToggleButton(int id, int x, int y, String label, boolean active) { + this(id, x, y, 200, StandardButtonTextureSets.LARGE_BUTTON, label, active); + } + + public GuiToggleButton(int id, int x, int y, int width, String s, boolean active) { + super(id, x, y, width, StandardButtonTextureSets.LARGE_BUTTON, s); + this.active = active; + } + + public GuiToggleButton(int id, int x, int y, int width, IButtonTextureSet texture, String s, boolean active) { + super(id, x, y, width, texture, s); + this.active = active; + } + + public void toggle() { + active = !active; + } + + @Override + protected int getHoverState(boolean mouseOver) { + int state = 1; + if (!enabled) { + state = 0; + } else if (mouseOver) { + state = 2; + } else if (!active) { + state = 3; + } + return state; + } + + @Override + public int getTextColor(boolean mouseOver) { + if (!enabled) { + return 0xffa0a0a0; + } else if (mouseOver) { + return 0xffffa0; + } else if (!active) { + return 0x777777; + } else { + return 0xe0e0e0; + } + } + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/GuiToggleButtonSmall.java b/forestry_common/core/forestry/core/gui/buttons/GuiToggleButtonSmall.java new file mode 100755 index 000000000..c9363e0f9 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/GuiToggleButtonSmall.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class GuiToggleButtonSmall extends GuiToggleButton { + + public GuiToggleButtonSmall(int i, int j, int k, String s, boolean active) { + this(i, j, k, 200, s, active); + } + + public GuiToggleButtonSmall(int i, int x, int y, int w, String s, boolean active) { + super(i, x, y, w, StandardButtonTextureSets.SMALL_BUTTON, s, active); + this.active = active; + } + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/IButtonTextureSet.java b/forestry_common/core/forestry/core/gui/buttons/IButtonTextureSet.java new file mode 100755 index 000000000..fd151bd11 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/IButtonTextureSet.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +/** + * + * @author CovertJaguar + */ +public interface IButtonTextureSet { + + public int getX(); + + public int getY(); + + public int getHeight(); + + public int getWidth(); + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/IMultiButtonState.java b/forestry_common/core/forestry/core/gui/buttons/IMultiButtonState.java new file mode 100755 index 000000000..00490f1b3 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/IMultiButtonState.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +import forestry.core.gui.tooltips.ToolTip; + + +/** + * + * @author CovertJaguar + */ +public interface IMultiButtonState { + + public String getLabel(); + + public String name(); + + public IButtonTextureSet getTextureSet(); + + public ToolTip getToolTip(); + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/LockButtonState.java b/forestry_common/core/forestry/core/gui/buttons/LockButtonState.java new file mode 100755 index 000000000..7c9b3648c --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/LockButtonState.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +import forestry.core.gui.tooltips.ToolTip; + +/** + * + * @author CovertJaguar + */ +public enum LockButtonState implements IMultiButtonState { + + UNLOCKED(new ButtonTextureSet(224, 0, 16, 16)), + LOCKED(new ButtonTextureSet(240, 0, 16, 16)); + public static final LockButtonState[] VALUES = values(); + private final IButtonTextureSet texture; + + private LockButtonState(IButtonTextureSet texture) { + this.texture = texture; + } + + @Override + public String getLabel() { + return ""; + } + + @Override + public IButtonTextureSet getTextureSet() { + return texture; + } + + @Override + public ToolTip getToolTip() { + return null; + } + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/MultiButtonController.java b/forestry_common/core/forestry/core/gui/buttons/MultiButtonController.java new file mode 100755 index 000000000..5c268674d --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/MultiButtonController.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +import net.minecraft.nbt.NBTTagByte; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagString; + +/** + * + * @author CovertJaguar + */ +public class MultiButtonController { + + private int currentState; + private final T[] validStates; + + public MultiButtonController(int startState, T... validStates) { + this.currentState = startState; + this.validStates = validStates; + } + + protected MultiButtonController(MultiButtonController controller) { + this.currentState = controller.currentState; + this.validStates = controller.validStates; + } + + public MultiButtonController copy() { + return new MultiButtonController(this); + } + + public T[] getValidStates() { + return validStates; + } + + public int incrementState() { + int newState = currentState + 1; + if (newState >= validStates.length) { + newState = 0; + } + currentState = newState; + return currentState; + } + + public int decrementState() { + int newState = currentState - 1; + if (newState < 0) { + newState = validStates.length - 1; + } + currentState = newState; + return currentState; + } + + public void setCurrentState(int state) { + currentState = state; + } + + public void setCurrentState(T state) { + for (int i = 0; i < validStates.length; i++) { + if (validStates[i] == state) { + currentState = i; + return; + } + } + } + + public int getCurrentState() { + return currentState; + } + + public T getButtonState() { + return validStates[currentState]; + } + + public void writeToNBT(NBTTagCompound nbt, String tag) { + nbt.setString(tag, getButtonState().name()); + } + + public void readFromNBT(NBTTagCompound nbt, String tag) { + if (nbt.getTag(tag) instanceof NBTTagString) { + String name = nbt.getString(tag); + for (int i = 0; i < validStates.length; i++) { + if (validStates[i].name().equals(name)) { + currentState = i; + break; + } + } + } else if (nbt.getTag(tag) instanceof NBTTagByte) { + currentState = nbt.getByte(tag); + } + } + +} diff --git a/forestry_common/core/forestry/core/gui/buttons/StandardButtonTextureSets.java b/forestry_common/core/forestry/core/gui/buttons/StandardButtonTextureSets.java new file mode 100755 index 000000000..d8158084e --- /dev/null +++ b/forestry_common/core/forestry/core/gui/buttons/StandardButtonTextureSets.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.buttons; + +/** + * + * @author CovertJaguar + */ +public enum StandardButtonTextureSets implements IButtonTextureSet{ + + LARGE_BUTTON(0, 0, 20, 200), + SMALL_BUTTON(0, 80, 15, 200), + LOCKED_BUTTON(224, 0, 16, 16), + UNLOCKED_BUTTON(240, 0, 16, 16), + LEFT_BUTTON(204, 0, 16, 10), + RIGHT_BUTTON(214, 0, 16, 10), + LEFT_BUTTON_SMALL(238, 220, 12, 9), + RIGHT_BUTTON_SMALL(247, 220, 12, 9); + private final int x, y, height, width; + + private StandardButtonTextureSets(int x, int y, int height, int width) { + this.x = x; + this.y = y; + this.height = height; + this.width = width; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getWidth() { + return width; + } + +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotClosed.java b/forestry_common/core/forestry/core/gui/slots/SlotClosed.java new file mode 100755 index 000000000..5f036049c --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotClosed.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +public class SlotClosed extends SlotForestry { + + public SlotClosed(IInventory par1iInventory, int par2, int par3, int par4) { + super(par1iInventory, par2, par3, par4); + } + + @Override + public boolean isItemValid(ItemStack par1ItemStack) { + return false; + } + +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotCraftAuto.java b/forestry_common/core/forestry/core/gui/slots/SlotCraftAuto.java new file mode 100755 index 000000000..6efca056c --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotCraftAuto.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +import forestry.core.interfaces.IContainerCrafting; + +/** + * Informs the passed container of slot changes. + */ +public class SlotCraftAuto extends Slot { + + private IContainerCrafting eventHandler; + private int slot; + + public SlotCraftAuto(IContainerCrafting container, IInventory iinventory, int slotNumber, int x, int y) { + super(iinventory, slotNumber, x, y); + this.eventHandler = container; + this.slot = slotNumber; + } + + @Override + public void onSlotChanged() { + super.onSlotChanged(); + eventHandler.onCraftMatrixChanged(inventory, slot); + } + +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotCrafter.java b/forestry_common/core/forestry/core/gui/slots/SlotCrafter.java new file mode 100755 index 000000000..ecc13d1ee --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotCrafter.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.core.interfaces.ICrafter; + +public class SlotCrafter extends Slot { + + ICrafter crafter; + + public SlotCrafter(IInventory inventory, ICrafter crafter, int slot, int xPos, int yPos) { + super(inventory, slot, xPos, yPos); + this.crafter = crafter; + } + + @Override + public boolean isItemValid(ItemStack par1ItemStack) { + return false; + } + + @Override + public ItemStack decrStackSize(int amount) { + if (!this.getHasStack()) + return null; + + return this.getStack(); + } + + @Override + public boolean canTakeStack(EntityPlayer player) { + return crafter.canTakeStack(getSlotIndex()); + } + + @Override + public ItemStack getStack() { + return this.crafter.getResult(); + } + + @Override + public boolean getHasStack() { + return this.getStack() != null && crafter.canTakeStack(getSlotIndex()); + } + + @Override + public void onPickupFromSlot(EntityPlayer player, ItemStack itemStack) { + crafter.takenFromSlot(getSlotIndex(), true, player); + } +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotCustom.java b/forestry_common/core/forestry/core/gui/slots/SlotCustom.java new file mode 100755 index 000000000..1e10c6708 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotCustom.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import java.util.Collection; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.ICrafter; +import forestry.core.render.TextureManager; +import forestry.core.utils.StackUtils; + +/** + * Slot which only specific items. (With permission by RichardG.) + * + * @author Richard + */ +public class SlotCustom extends SlotForestry { + + protected Object[] items; + private boolean exclusion; + private ICrafter crafter; + private String blockedTexture = "slots/blocked"; + + public SlotCustom(IInventory iinventory, int i, int j, int k, boolean exclusion) { + super(iinventory, i, j, k); + items = new Object[0]; + this.exclusion = exclusion; + } + + /*public SlotCustom(IInventory iinventory, ArrayList items, int i, int j, int k) { + this(iinventory, i, j, k, items.toArray()); + }*/ + + public SlotCustom(IInventory iinventory, Collection items, int i, int j, int k) { + this(iinventory, i, j, k, items.toArray()); + } + + public SlotCustom(IInventory iinventory, int i, int j, int k, boolean exclusion, Object... items) { + this(iinventory, i, j, k, items); + this.exclusion = exclusion; + } + + public SlotCustom(IInventory iinventory, int i, int j, int k, Object... items) { + super(iinventory, i, j, k); + this.items = items; + } + + public SlotCustom setCrafter(ICrafter crafter) { + this.crafter = crafter; + return this; + } + + @Override + public boolean isItemValid(ItemStack itemstack) { + if (itemstack == null) + return false; + if (!inventory.isItemValidForSlot(getSlotIndex(), itemstack)) + return false; + + if (exclusion) + return !determineValidity(itemstack); + else + return determineValidity(itemstack); + } + + @Override + public boolean getHasStack() { + if (crafter != null && !crafter.canTakeStack(getSlotIndex())) + return false; + else + return super.getHasStack(); + } + + @Override + public ItemStack decrStackSize(int i) { + if (crafter != null && !crafter.canTakeStack(getSlotIndex())) + return null; + else + return super.decrStackSize(i); + } + + @Override + public void onPickupFromSlot(EntityPlayer player, ItemStack itemStack) { + if (crafter != null) + crafter.takenFromSlot(getSlotIndex(), true, player); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private boolean determineValidity(ItemStack itemstack) { + for (Object filter : items) { + if (filter == null) + continue; + if (filter instanceof Class) { + Block block = StackUtils.getBlock(itemstack); + + if (block != null && ((Class) filter).isAssignableFrom(block.getClass())) return true; + if (((Class) filter).isAssignableFrom(itemstack.getItem().getClass())) return true; + } else if (filter instanceof ItemStack) { + if (((ItemStack) filter).getItemDamage() == Defaults.WILDCARD && itemstack.getItem() == ((ItemStack) filter).getItem()) + return true; + else if (itemstack.isItemEqual((ItemStack) filter)) + return true; + } else if (filter instanceof Block) { + if (StackUtils.equals((Block) filter, itemstack)) return true; + } else if (filter instanceof Item) { + if (itemstack.getItem() == (Item) filter) return true; + } else if (filter instanceof ForestryItem) { + if (((ForestryItem) filter).isItemEqual(itemstack)) return true; + } else if (filter instanceof ISpeciesRoot) { + if (((ISpeciesRoot) filter).isMember(itemstack)) return true; + } else { + throw new RuntimeException("invalid filter item specified: "+filter+" ("+filter.getClass()+")"); + } + } + + return false; + } + + public SlotCustom setBlockedTexture(String ident) { + blockedTexture = ident; + return this; + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getBackgroundIconIndex() { + if (!inventory.isItemValidForSlot(getSlotIndex(), null)) + return TextureManager.getInstance().getDefault(blockedTexture); + else + return null; + } +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotForestry.java b/forestry_common/core/forestry/core/gui/slots/SlotForestry.java new file mode 100755 index 000000000..83d17460a --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotForestry.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.core.gui.tooltips.IToolTipProvider; +import forestry.core.gui.tooltips.ToolTip; + +public class SlotForestry extends Slot implements IToolTipProvider{ + + protected boolean isPhantom; + protected boolean isInfinite; + protected boolean canAdjustPhantom = true; + protected boolean canShift = true; + protected int stackLimit; + private ToolTip toolTips; + + public SlotForestry(IInventory inventory, int slotIndex, int xPos, int yPos) { + this(inventory, slotIndex, xPos, yPos, -1); + } + + public SlotForestry(IInventory inventory, int slotIndex, int xPos, int yPos, int stackLimit) { + super(inventory, slotIndex, xPos, yPos); + this.stackLimit = stackLimit; + } + + public SlotForestry setInfinite() { + this.isInfinite = true; + return this; + } + + public SlotForestry setPhantom() { + isPhantom = true; + return this; + } + + public SlotForestry blockShift() { + canShift = false; + return this; + } + + public SlotForestry setCanAdjustPhantom(boolean canAdjust) { + this.canAdjustPhantom = canAdjust; + return this; + } + + public SlotForestry setCanShift(boolean canShift) { + this.canShift = canShift; + return this; + } + + public SlotForestry setStackLimit(int limit) { + this.stackLimit = limit; + return this; + } + + public boolean isPhantom() { + return this.isPhantom; + } + + public boolean canAdjustPhantom() { + return canAdjustPhantom; + } + + @Override + public boolean canTakeStack(EntityPlayer stack) { + return !isPhantom(); + } + + public boolean canShift() { + return canShift; + } + + @Override + public int getSlotStackLimit() { + if (stackLimit < 0) + return super.getSlotStackLimit(); + else + return stackLimit; + } + + @Override + public ItemStack decrStackSize(int i) { + if (!isInfinite) + return super.decrStackSize(i); + + ItemStack stack = inventory.getStackInSlot(getSlotIndex()); + if (stack == null) + return null; + + ItemStack result = stack.copy(); + result.stackSize = i; + return result; + } + + public void onSlotClick(int slotIndex, int button, int modifier, EntityPlayer player) { + } + + /** + * @param toolTips the tooltips to set + */ + public void setToolTips(ToolTip toolTips) { + this.toolTips = toolTips; + } + + /** + * @return the toolTips + */ + @Override + public ToolTip getToolTip() { + return toolTips; + } + + @Override + public boolean isToolTipVisible() { + return getStack() == null; + } + + @Override + public boolean isMouseOver(int mouseX, int mouseY) { + return mouseX >= xDisplayPosition && mouseX <= xDisplayPosition + 16 && mouseY >= yDisplayPosition && mouseY <= yDisplayPosition + 16; + } +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotItemInventory.java b/forestry_common/core/forestry/core/gui/slots/SlotItemInventory.java new file mode 100755 index 000000000..6a4afe5a7 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotItemInventory.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.core.gui.ContainerItemInventory; + +public class SlotItemInventory extends Slot { + + private final EntityPlayer player; + private ContainerItemInventory container; + + public SlotItemInventory(ContainerItemInventory container, IInventory inventory, EntityPlayer player, int par2, int par3, int par4) { + super(inventory, par2, par3, par4); + this.container = container; + this.player = player; + } + + @Override + public void onSlotChange(ItemStack par1ItemStack, ItemStack par2ItemStack) { + super.onSlotChange(par1ItemStack, par2ItemStack); + container.saveInventory(player); + } + +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotLiquidContainer.java b/forestry_common/core/forestry/core/gui/slots/SlotLiquidContainer.java new file mode 100755 index 000000000..eca98b2c8 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotLiquidContainer.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; + +import forestry.core.render.TextureManager; + +public class SlotLiquidContainer extends SlotCustom { + + private final boolean isEmpty; + + public SlotLiquidContainer(IInventory iinventory, int i, int j, int k) { + this(iinventory, i, j, k, false); + } + + public SlotLiquidContainer(IInventory iinventory, int i, int j, int k, boolean isEmpty) { + super(iinventory, i, j, k, false); + + this.isEmpty = isEmpty; + List container = new ArrayList(); + + for (FluidContainerData cont : FluidContainerRegistry.getRegisteredFluidContainerData()) + if (isEmpty) + container.add(cont.emptyContainer); + else + container.add(cont.filledContainer); + + this.items = container.toArray(); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getBackgroundIconIndex() { + if(isEmpty) + return TextureManager.getInstance().getDefault("slots/container"); + else + return TextureManager.getInstance().getDefault("slots/liquid"); + } + +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotLocked.java b/forestry_common/core/forestry/core/gui/slots/SlotLocked.java new file mode 100755 index 000000000..eb5068522 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotLocked.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +public class SlotLocked extends SlotForestry { + + public SlotLocked(IInventory par1iInventory, int par2, int par3, int par4) { + super(par1iInventory, par2, par3, par4); + setCanAdjustPhantom(false); + setCanShift(false); + } + + @Override + public void onPickupFromSlot(EntityPlayer player, ItemStack itemStack) { + } + + @Override + public boolean isItemValid(ItemStack par1ItemStack) { + return false; + } + + @Override + public boolean getHasStack() { + return false; + } + + @Override + public ItemStack decrStackSize(int i) { + return null; + } +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotOutput.java b/forestry_common/core/forestry/core/gui/slots/SlotOutput.java new file mode 100755 index 000000000..2a116a4dc --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotOutput.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +/** + * + * @author CovertJaguar + */ +public class SlotOutput extends SlotForestry { + + public SlotOutput(IInventory iinventory, int slotIndex, int posX, int posY) { + super(iinventory, slotIndex, posX, posY); + } + + @Override + public boolean isItemValid(ItemStack itemstack) { + return false; + } +} diff --git a/forestry_common/core/forestry/core/gui/slots/SlotWorking.java b/forestry_common/core/forestry/core/gui/slots/SlotWorking.java new file mode 100755 index 000000000..dacda5b02 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/slots/SlotWorking.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.slots; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +public class SlotWorking extends SlotForestry { + + public SlotWorking(IInventory iinventory, int i, int j, int k) { + super(iinventory, i, j, k); + setCanShift(false); + } + + @Override + public boolean isItemValid(ItemStack itemstack) { + return false; + } + + @Override + public void onPickupFromSlot(EntityPlayer player, ItemStack itemStack) { + } + + @Override + public boolean getHasStack() { + return false; + } + + @Override + public ItemStack decrStackSize(int i) { + return null; + } +} diff --git a/forestry_common/core/forestry/core/gui/tooltips/IToolTipProvider.java b/forestry_common/core/forestry/core/gui/tooltips/IToolTipProvider.java new file mode 100755 index 000000000..4c08b657b --- /dev/null +++ b/forestry_common/core/forestry/core/gui/tooltips/IToolTipProvider.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.tooltips; + +/** + * + * @author CovertJaguar + */ +public interface IToolTipProvider { + + ToolTip getToolTip(); + + boolean isToolTipVisible(); + + boolean isMouseOver(int mouseX, int mouseY); +} diff --git a/forestry_common/core/forestry/core/gui/tooltips/ToolTip.java b/forestry_common/core/forestry/core/gui/tooltips/ToolTip.java new file mode 100755 index 000000000..b665e6bac --- /dev/null +++ b/forestry_common/core/forestry/core/gui/tooltips/ToolTip.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.tooltips; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.ForwardingList; + +import forestry.core.utils.Localization; + +/** + * + * @author CovertJaguar + */ +public class ToolTip extends ForwardingList { + + private final List delegate = new ArrayList(); + private final long delay; + private long mouseOverStart; + + public ToolTip() { + this.delay = 0; + } + + public ToolTip(int delay) { + this.delay = delay; + } + + @Override + protected final List delegate() { + return delegate; + } + + public boolean add(String line) { + return add(new ToolTipLine(line)); + } + + public void onTick(boolean mouseOver) { + if (delay == 0) + return; + if (mouseOver) { + if (mouseOverStart == 0) + mouseOverStart = System.currentTimeMillis(); + } else + mouseOverStart = 0; + } + + public boolean isReady() { + if (delay == 0) + return true; + if (mouseOverStart == 0) + return false; + return System.currentTimeMillis() - mouseOverStart >= delay; + } + + public void refresh() { + } + + public List convertToStrings() { + List tips = new ArrayList(size()); + for (ToolTipLine line : this) { + tips.add(line.text); + } + return tips; + } + + public static ToolTip buildToolTip(String tipTag, String... vars) { + if (!Localization.instance.hasMapping(tipTag)) + return null; + ToolTip toolTip = new ToolTip(750); + String text = Localization.instance.get(tipTag); + for (String var : vars) { + String[] pair = var.split("="); + text = text.replace(pair[0], pair[1]); + } + String[] tips = text.split("\n"); + for (String tip : tips) { + tip = tip.trim(); + toolTip.add(new ToolTipLine(tip)); + } + return toolTip; + } + +} diff --git a/forestry_common/core/forestry/core/gui/tooltips/ToolTipLine.java b/forestry_common/core/forestry/core/gui/tooltips/ToolTipLine.java new file mode 100755 index 000000000..2ba4a5ea4 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/tooltips/ToolTipLine.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.tooltips; + +import net.minecraft.util.EnumChatFormatting; + +/** + * + * @author CovertJaguar + */ +public class ToolTipLine { + + public String text; + public final EnumChatFormatting color; + public int spacing; + + public ToolTipLine(String text, EnumChatFormatting color) { + this.text = text; + this.color = color; + } + + public ToolTipLine(String text) { + this(text, null); + } + + public ToolTipLine() { + this("", null); + } + + public void setSpacing(int spacing) { + this.spacing = spacing; + } + + public int getSpacing() { + return spacing; + } + +} diff --git a/forestry_common/core/forestry/core/gui/widgets/ReservoirWidget.java b/forestry_common/core/forestry/core/gui/widgets/ReservoirWidget.java new file mode 100755 index 000000000..e53ad00ff --- /dev/null +++ b/forestry_common/core/forestry/core/gui/widgets/ReservoirWidget.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.widgets; + +import net.minecraft.util.IIcon; + +import net.minecraftforge.fluids.FluidStack; + +import org.lwjgl.opengl.GL11; + +import forestry.core.gui.WidgetManager; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; + +public class ReservoirWidget extends TankWidget { + + public ReservoirWidget(WidgetManager manager, int xPos, int yPos, int slot) { + super(manager, xPos, yPos, slot); + this.height = 16; + } + + @Override + public void draw(int startX, int startY) { + + FluidStack contents = getTank().getFluid(); + if(contents == null || contents.amount <= 0) + return; + IIcon liquidIcon = contents.getFluid().getIcon(contents); + if(liquidIcon == null) + return; + + int squaled = (contents.amount * height) / getTank().getCapacity(); + if (squaled > height) + squaled = height; + + Proxies.common.bindTexture(SpriteSheet.BLOCKS); + int start = 0; + + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + while (true) { + int x = 0; + + if (squaled > 16) { + x = 16; + squaled -= 16; + } else { + x = squaled; + squaled = 0; + } + + manager.gui.drawTexturedModelRectFromIcon(startX + xPos, startY + yPos + height - x - start, liquidIcon, 16, 16 - (16 - x)); + start = start + 16; + + if (x == 0 || squaled == 0) + break; + } + + } +} diff --git a/forestry_common/core/forestry/core/gui/widgets/SocketWidget.java b/forestry_common/core/forestry/core/gui/widgets/SocketWidget.java new file mode 100755 index 000000000..e69caac70 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/widgets/SocketWidget.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.widgets; + +import java.util.List; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import forestry.core.circuits.ISolderingIron; +import forestry.core.circuits.ItemCircuitBoard; +import forestry.core.gui.ContainerSocketed; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.WidgetManager; +import forestry.core.gui.tooltips.ToolTip; +import forestry.core.interfaces.ISocketable; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StringUtil; + +public class SocketWidget extends Widget { + + ISocketable tile; + int slot = 0; + + public SocketWidget(WidgetManager manager, int xPos, int yPos, ISocketable tile, int slot) { + super(manager, xPos, yPos); + this.tile = tile; + this.slot = slot; + } + + @Override + public void draw(int startX, int startY) { + ItemStack socketStack = tile.getSocket(slot); + if (socketStack != null) + GuiForestry.getItemRenderer().renderItemIntoGUI(manager.minecraft.fontRenderer, manager.minecraft.renderEngine, socketStack, startX + xPos, startY + + yPos); + } + + @Override + public ToolTip getToolTip() { + return toolTip; + } + + protected final ToolTip toolTip = new ToolTip(500) { + @SuppressWarnings("unchecked") + @Override + public void refresh() { + toolTip.clear(); + ItemStack stack = tile.getSocket(slot); + if (stack != null) { + for (String line : (List) stack.getTooltip(Proxies.common.getClientInstance().thePlayer, false)) { + toolTip.add(line); + } + } else { + toolTip.add(StringUtil.localize("gui.emptysocket")); + } + } + }; + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + + ItemStack itemstack = manager.minecraft.thePlayer.inventory.getItemStack(); + if (itemstack == null) + return; + + Item held = itemstack.getItem(); + + // Insert chipsets + if (held instanceof ItemCircuitBoard) + ((ContainerSocketed) manager.gui.inventorySlots).handleChipsetClick(slot, manager.minecraft.thePlayer, itemstack); + else if (held instanceof ISolderingIron) + ((ContainerSocketed) manager.gui.inventorySlots).handleSolderingIronClick(slot, manager.minecraft.thePlayer, itemstack); + } +} diff --git a/forestry_common/core/forestry/core/gui/widgets/TankWidget.java b/forestry_common/core/forestry/core/gui/widgets/TankWidget.java new file mode 100755 index 000000000..d93c21d41 --- /dev/null +++ b/forestry_common/core/forestry/core/gui/widgets/TankWidget.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.widgets; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.tools.IToolPipette; +import org.lwjgl.opengl.GL11; + +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.WidgetManager; +import forestry.core.gui.tooltips.ToolTip; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.utils.ForestryTank; + +/** + * Slot for liquid tanks + */ +public class TankWidget extends Widget { + + protected int overlayTexX = 176; + protected int overlayTexY = 0; + protected int slot = 0; + + public TankWidget(WidgetManager manager, int xPos, int yPos, int slot) { + super(manager, xPos, yPos); + this.slot = slot; + this.height = 58; + } + + public TankWidget setOverlayOrigin(int x, int y) { + overlayTexX = x; + overlayTexY = y; + return this; + } + + public ForestryTank getTank() { + return ((ContainerForestry) manager.gui.inventorySlots).getTank(slot); + } + + @Override + public void draw(int startX, int startY) { + if (getTank() == null) + return; + + FluidStack contents = getTank().getFluid(); + if (contents == null || contents.amount <= 0) + return; + IIcon liquidIcon = contents.getFluid().getIcon(contents); + if (liquidIcon == null) + return; + int squaled = (contents.amount * height) / getTank().getCapacity(); + + Proxies.common.bindTexture(SpriteSheet.BLOCKS); + int start = 0; + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + while (true) { + int x = 0; + + if (squaled > 16) { + x = 16; + squaled -= 16; + } else { + x = squaled; + squaled = 0; + } + + manager.gui.drawTexturedModelRectFromIcon(startX + xPos, startY + yPos + height - x - start, liquidIcon, 16, 16 - (16 - x)); + start = start + 16; + + if (x == 0 || squaled == 0) + break; + } + + Proxies.common.bindTexture(manager.gui.textureFile); + manager.gui.drawTexturedModalRect(startX + xPos, startY + yPos, overlayTexX, overlayTexY, 16, 60); + GL11.glPopAttrib(); + } + + @Override + public ToolTip getToolTip() { + ForestryTank tank = getTank(); + if (tank == null) + return null; + return tank.getToolTip(); + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + ItemStack itemstack = manager.minecraft.thePlayer.inventory.getItemStack(); + if (itemstack == null) + return; + + Item held = itemstack.getItem(); + if (held instanceof IToolPipette && manager.gui.inventorySlots instanceof ContainerLiquidTanks) + ((ContainerLiquidTanks) manager.gui.inventorySlots).handlePipetteClick(slot, manager.minecraft.thePlayer); + + } +} diff --git a/forestry_common/core/forestry/core/gui/widgets/Widget.java b/forestry_common/core/forestry/core/gui/widgets/Widget.java new file mode 100755 index 000000000..acce4a26b --- /dev/null +++ b/forestry_common/core/forestry/core/gui/widgets/Widget.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.gui.widgets; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.core.gui.WidgetManager; +import forestry.core.gui.tooltips.IToolTipProvider; +import forestry.core.gui.tooltips.ToolTip; +import forestry.core.proxy.Proxies; + +/** + * Basic non-ItemStack slot + */ +public abstract class Widget implements IToolTipProvider { + + protected WidgetManager manager; + protected int xPos; + protected int yPos; + protected int width = 16; + protected int height = 16; + + public Widget(WidgetManager manager, int xPos, int yPos) { + this.manager = manager; + this.xPos = xPos; + this.yPos = yPos; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public abstract void draw(int startX, int startY); + + @Override + public ToolTip getToolTip() { + String line = getLegacyTooltip(Proxies.common.getClientInstance().thePlayer); + if (line != null && !line.isEmpty()) { + ToolTip tip = new ToolTip(); + tip.add(line); + return tip; + } + return null; + } + + protected String getLegacyTooltip(EntityPlayer player) { + return null; + } + + // Not fully implemented + @Override + public boolean isToolTipVisible() { + return true; + } + + @Override + public boolean isMouseOver(int mouseX, int mouseY) { + return mouseX >= xPos && mouseX <= xPos + this.width && mouseY >= yPos && mouseY <= yPos + this.height; + } + + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + } + + public void handleMouseRelease(int mouseX, int mouseY, int eventType) { + } + + public void handleMouseMove(int mouseX, int mouseY, int mouseButton, long time) { + } +} diff --git a/forestry_common/core/forestry/core/interfaces/IBlockRenderer.java b/forestry_common/core/forestry/core/interfaces/IBlockRenderer.java new file mode 100755 index 000000000..a14a5e254 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IBlockRenderer.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.tileentity.TileEntity; + +public interface IBlockRenderer { + public void renderTileEntityAt(TileEntity tileentity, double d, double d1, double d2, float f); + + public void inventoryRender(double x, double y, double z, float f, float f1); +} diff --git a/forestry_common/core/forestry/core/interfaces/IClimatised.java b/forestry_common/core/forestry/core/interfaces/IClimatised.java new file mode 100755 index 000000000..341832b79 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IClimatised.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public interface IClimatised { + boolean isClimatized(); + + EnumTemperature getTemperature(); + + EnumHumidity getHumidity(); + + float getExactTemperature(); + + float getExactHumidity(); +} diff --git a/forestry_common/core/forestry/core/interfaces/IContainerCrafting.java b/forestry_common/core/forestry/core/interfaces/IContainerCrafting.java new file mode 100755 index 000000000..08363027c --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IContainerCrafting.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.inventory.IInventory; + +public interface IContainerCrafting { + void onCraftMatrixChanged(IInventory iinventory, int slot); +} diff --git a/forestry_common/core/forestry/core/interfaces/ICrafter.java b/forestry_common/core/forestry/core/interfaces/ICrafter.java new file mode 100755 index 000000000..cf4acdefe --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/ICrafter.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public interface ICrafter { + + ItemStack takenFromSlot(int slotIndex, boolean consumeRecipe, EntityPlayer player); + + ItemStack getResult(); + + boolean canTakeStack(int slotIndex); + +} diff --git a/forestry_common/core/forestry/core/interfaces/ICraftingPlan.java b/forestry_common/core/forestry/core/interfaces/ICraftingPlan.java new file mode 100755 index 000000000..eea3ea6f8 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/ICraftingPlan.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.item.ItemStack; + +public interface ICraftingPlan { + ItemStack planUsed(ItemStack plan, ItemStack result); +} diff --git a/forestry_common/core/forestry/core/interfaces/IDescriptiveRecipe.java b/forestry_common/core/forestry/core/interfaces/IDescriptiveRecipe.java new file mode 100755 index 000000000..52b8f8646 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IDescriptiveRecipe.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.item.crafting.IRecipe; + +public interface IDescriptiveRecipe extends IRecipe { + + int getWidth(); + + int getHeight(); + + Object[] getIngredients(); +} diff --git a/forestry_common/core/forestry/core/interfaces/IErrorSource.java b/forestry_common/core/forestry/core/interfaces/IErrorSource.java new file mode 100755 index 000000000..dd8490968 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IErrorSource.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import forestry.core.EnumErrorCode; + +public interface IErrorSource { + + boolean throwsErrors(); + + EnumErrorCode getErrorState(); + +} diff --git a/forestry_common/core/forestry/core/interfaces/IHintSource.java b/forestry_common/core/forestry/core/interfaces/IHintSource.java new file mode 100755 index 000000000..1569740dd --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IHintSource.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +public interface IHintSource { + boolean hasHints(); + + String[] getHints(); +} diff --git a/forestry_common/core/forestry/core/interfaces/IInventoriedItem.java b/forestry_common/core/forestry/core/interfaces/IInventoriedItem.java new file mode 100755 index 000000000..b0ce2317c --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IInventoriedItem.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +public interface IInventoriedItem { + +} diff --git a/forestry_common/core/forestry/core/interfaces/ILiquidTankContainer.java b/forestry_common/core/forestry/core/interfaces/ILiquidTankContainer.java new file mode 100755 index 000000000..7c0262994 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/ILiquidTankContainer.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraftforge.fluids.IFluidHandler; + +import forestry.core.utils.ForestryTank; + +public interface ILiquidTankContainer extends IFluidHandler { + + ForestryTank[] getTanks(); + +} diff --git a/forestry_common/core/forestry/core/interfaces/IOreDictionaryHandler.java b/forestry_common/core/forestry/core/interfaces/IOreDictionaryHandler.java new file mode 100755 index 000000000..a68e48940 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IOreDictionaryHandler.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.item.ItemStack; + +public interface IOreDictionaryHandler { + void onOreRegistration(String name, ItemStack ore); +} diff --git a/forestry_common/core/forestry/core/interfaces/IOwnable.java b/forestry_common/core/forestry/core/interfaces/IOwnable.java new file mode 100755 index 000000000..73b5c1dbf --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IOwnable.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.core.utils.EnumAccess; + +public interface IOwnable { + + boolean isOwnable(); + + boolean isOwned(); + + String getOwnerName(); + + void setOwner(EntityPlayer player); + + boolean isOwner(EntityPlayer player); + + boolean switchAccessRule(EntityPlayer player); + + EnumAccess getAccess(); + + boolean allowsRemoval(EntityPlayer player); + + boolean allowsInteraction(EntityPlayer player); +} diff --git a/forestry_common/core/forestry/core/interfaces/IPacketHandler.java b/forestry_common/core/forestry/core/interfaces/IPacketHandler.java new file mode 100755 index 000000000..d2237d051 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IPacketHandler.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import java.io.DataInputStream; + +import net.minecraft.entity.player.EntityPlayer; + +public interface IPacketHandler { + + void onPacketData(int packetID, DataInputStream data, EntityPlayer player); + +} diff --git a/forestry_common/core/forestry/core/interfaces/IPickupHandler.java b/forestry_common/core/forestry/core/interfaces/IPickupHandler.java new file mode 100755 index 000000000..30b710a71 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IPickupHandler.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; + +public interface IPickupHandler { + + boolean onItemPickup(EntityPlayer entityPlayer, EntityItem item); + +} diff --git a/forestry_common/core/forestry/core/interfaces/IPowerHandler.java b/forestry_common/core/forestry/core/interfaces/IPowerHandler.java new file mode 100755 index 000000000..d540d9ecc --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IPowerHandler.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import buildcraft.api.power.IPowerReceptor; +import buildcraft.api.power.PowerHandler; + +public interface IPowerHandler extends IPowerReceptor { + PowerHandler getPowerHandler(); +} diff --git a/forestry_common/core/forestry/core/interfaces/IRenderableMachine.java b/forestry_common/core/forestry/core/interfaces/IRenderableMachine.java new file mode 100755 index 000000000..7ce9f9d8d --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IRenderableMachine.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.core.utils.EnumTankLevel; + +public interface IRenderableMachine { + + ForgeDirection getOrientation(); + + EnumTankLevel getPrimaryLevel(); + + EnumTankLevel getSecondaryLevel(); + +} diff --git a/forestry_common/core/forestry/core/interfaces/IResupplyHandler.java b/forestry_common/core/forestry/core/interfaces/IResupplyHandler.java new file mode 100755 index 000000000..82c72d15b --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/IResupplyHandler.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.entity.player.EntityPlayer; + +public interface IResupplyHandler { + + void resupply(EntityPlayer player); + +} diff --git a/forestry_common/core/forestry/core/interfaces/ISaveEventHandler.java b/forestry_common/core/forestry/core/interfaces/ISaveEventHandler.java new file mode 100755 index 000000000..58d4a8e22 --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/ISaveEventHandler.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.world.World; + +public interface ISaveEventHandler { + + void onWorldLoad(World world); + + void onWorldUnload(World world); + + void onWorldSave(World world); + +} diff --git a/forestry_common/core/forestry/core/interfaces/ISocketable.java b/forestry_common/core/forestry/core/interfaces/ISocketable.java new file mode 100755 index 000000000..f4e549c6c --- /dev/null +++ b/forestry_common/core/forestry/core/interfaces/ISocketable.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.interfaces; + +import net.minecraft.item.ItemStack; + +public interface ISocketable { + int getSocketCount(); + + ItemStack getSocket(int slot); + + void setSocket(int slot, ItemStack stack); +} diff --git a/forestry_common/core/forestry/core/inventory/ITileFilter.java b/forestry_common/core/forestry/core/inventory/ITileFilter.java new file mode 100755 index 000000000..5d53645b7 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/ITileFilter.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory; + +import net.minecraft.tileentity.TileEntity; + +/** + * + * @author CovertJaguar + */ +public interface ITileFilter { + + public boolean matches(TileEntity tile); + +} diff --git a/forestry_common/core/forestry/core/inventory/InvTools.java b/forestry_common/core/forestry/core/inventory/InvTools.java new file mode 100755 index 000000000..aa54d67f3 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/InvTools.java @@ -0,0 +1,796 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import net.minecraft.block.Block; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.oredict.OreDictionary; + +import buildcraft.api.inventory.ISpecialInventory; +import buildcraft.api.transport.PipeManager; + +import forestry.core.inventory.filters.ArrayStackFilter; +import forestry.core.inventory.filters.IStackFilter; +import forestry.core.inventory.filters.InvertedStackFilter; +import forestry.core.inventory.filters.StackFilter; +import forestry.core.inventory.manipulators.InventoryManipulator; +import forestry.core.inventory.wrappers.ChestWrapper; +import forestry.core.inventory.wrappers.IInvSlot; +import forestry.core.inventory.wrappers.InventoryIterator; +import forestry.core.inventory.wrappers.InventoryMapper; +import forestry.core.inventory.wrappers.SidedInventoryMapper; +import forestry.core.inventory.wrappers.SpecialInventoryMapper; +import forestry.core.utils.PlainInventory; + +public abstract class InvTools { + + /*private static final String TAG_ID = "id"; + private static final String TAG_SIZE = "stackSize"; + private static final String TAG_DAMAGE = "Damage"; + private static final String TAG_COUNT = "Count";*/ + private static final String TAG_SLOT = "Slot"; + + public static int getXOnSide(int x, ForgeDirection side) { + return x + side.offsetX; + } + + public static int getYOnSide(int y, ForgeDirection side) { + return y + side.offsetY; + } + + public static int getZOnSide(int z, ForgeDirection side) { + return z + side.offsetZ; + } + + public static boolean blockExistsOnSide(World world, int x, int y, int z, ForgeDirection side) { + return world.blockExists(getXOnSide(x, side), getYOnSide(y, side), getZOnSide(z, side)); + } + + public static int getBlockMetadataOnSide(IBlockAccess world, int i, int j, int k, ForgeDirection side) { + return world.getBlockMetadata(getXOnSide(i, side), getYOnSide(j, side), getZOnSide(k, side)); + } + + public static Block getBlockOnSide(IBlockAccess world, int x, int y, int z, ForgeDirection side) { + return world.getBlock(getXOnSide(x, side), getYOnSide(y, side), getZOnSide(z, side)); + } + + public static TileEntity getBlockTileEntityOnSide(World world, int x, int y, int z, ForgeDirection side) { + int sx = getXOnSide(x, side); + int sy = getYOnSide(y, side); + int sz = getZOnSide(z, side); + if (world.blockExists(sx, sy, sz)) + return world.getTileEntity(sx, sy, sz); + return null; + } + + public static TileEntity getBlockTileEntityOnSide(IBlockAccess world, int x, int y, int z, ForgeDirection side) { + int sx = getXOnSide(x, side); + int sy = getYOnSide(y, side); + int sz = getZOnSide(z, side); + return world.getTileEntity(sx, sy, sz); + } + + public static List getAdjacentInventories(World world, int i, int j, int k) { + return getAdjacentInventories(world, i, j, k, null); + } + + public static List getAdjacentInventories(World world, int i, int j, int k, Class type) { + List list = new ArrayList(5); + for (int side = 0; side < 6; side++) { + IInventory inv = getInventoryFromSide(world, i, j, k, ForgeDirection.getOrientation(side), type, null); + if (inv != null) + list.add(inv); + } + return list; + } + + public static Map getAdjacentInventoryMap(World world, int i, int j, int k) { + return getAdjacentInventoryMap(world, i, j, k, null); + } + + public static Map getAdjacentInventoryMap(World world, int i, int j, int k, Class type) { + Map map = new TreeMap(); + for (int side = 0; side < 6; side++) { + IInventory inv = getInventoryFromSide(world, i, j, k, ForgeDirection.getOrientation(side), type, null); + if (inv != null) + map.put(side, inv); + } + return map; + } + + public static IInventory getInventoryFromSide(World world, int x, int y, int z, ForgeDirection side, final Class type, final Class exclude) { + return getInventoryFromSide(world, x, y, z, side, new ITileFilter() { + @Override + public boolean matches(TileEntity tile) { + if (type != null && !type.isAssignableFrom(tile.getClass())) + return false; + if (exclude != null && exclude.isAssignableFrom(tile.getClass())) + return false; + return true; + } + }); + } + + public static IInventory getInventoryFromSide(World world, int x, int y, int z, ForgeDirection side, ITileFilter filter) { + TileEntity tile = getBlockTileEntityOnSide(world, x, y, z, side); + if (tile == null || !(tile instanceof IInventory) || !filter.matches(tile)) + return null; + return getInventoryFromTile(tile, side.getOpposite()); + } + + public static IInventory getInventoryFromTile(TileEntity tile, ForgeDirection side) { + if (tile == null || !(tile instanceof IInventory)) + return null; + + if (!PipeManager.canExtractItems(null, tile.getWorldObj(), tile.xCoord, tile.yCoord, tile.zCoord)) + return null; + + if (tile instanceof TileEntityChest) { + TileEntityChest chest = (TileEntityChest) tile; + return new ChestWrapper(chest); + } + return getInventory((IInventory) tile, side); + } + + public static IInventory getInventory(IInventory inv, ForgeDirection side) { + if (inv == null) + return null; + + if (inv instanceof ISpecialInventory) + inv = new SpecialInventoryMapper((ISpecialInventory) inv, side); + else if (inv instanceof ISidedInventory) + inv = new SidedInventoryMapper((ISidedInventory) inv, side); + return inv; + } + + public static int[] buildSlotArray(int start, int size) { + int[] slots = new int[size]; + for (int i = 0; i < size; i++) { + slots[i] = start + i; + } + return slots; + } + + /*public static void addItemToolTip(ItemStack stack, String tag, String msg) { + NBTTagCompound nbt = getItemData(stack); + NBTTagCompound display = nbt.getCompoundTag("display"); + nbt.setTag("display", display); + NBTTagList lore = display.getTagList("Lore", 8); // 8 = String + display.setTag("Lore", lore); + //lore.appendTag(new NBTTagString(tag, msg)); + lore.appendTag(new NBTTagString(msg)); + }*/ + + public static NBTTagCompound getItemData(ItemStack stack) { + NBTTagCompound nbt = stack.getTagCompound(); + if (nbt == null) { + nbt = new NBTTagCompound(); + stack.setTagCompound(nbt); + } + return nbt; + } + + public static ItemStack depleteItem(ItemStack stack) { + if (stack.stackSize == 1) + return stack.getItem().getContainerItem(stack); + else { + stack.splitStack(1); + return stack; + } + } + + public static ItemStack damageItem(ItemStack stack, int damage) { + if (!stack.isItemStackDamageable()) + return stack; + int curDamage = stack.getItemDamage(); + curDamage += damage; + stack.setItemDamage(curDamage); + if (stack.getItemDamage() > stack.getMaxDamage()) { + stack.stackSize--; + stack.setItemDamage(0); + } + if (stack.stackSize <= 0) + stack = null; + return stack; + } + + public static void dropItem(ItemStack stack, World world, double x, double y, double z) { + if (stack == null || stack.stackSize < 1) + return; + EntityItem entityItem = new EntityItem(world, x, y + 1.5, z, stack); + entityItem.delayBeforeCanPickup = 10; + world.spawnEntityInWorld(entityItem); + } + + public static boolean isInventoryEmpty(IInventory inv, ForgeDirection side) { + return isInventoryEmpty(getInventory(inv, side)); + } + + public static boolean isInventoryEmpty(IInventory inv) { + ItemStack stack = null; + for (IInvSlot slot : InventoryIterator.getIterable(inv)) { + stack = slot.getStackInSlot(); + if (stack != null) + break; + } + return stack == null; + } + + public static boolean isInventoryFull(IInventory inv, ForgeDirection side) { + return isInventoryFull(getInventory(inv, side)); + } + + public static boolean isInventoryFull(IInventory inv) { + ItemStack stack = null; + for (IInvSlot slot : InventoryIterator.getIterable(inv)) { + stack = slot.getStackInSlot(); + if (stack == null) + break; + } + return stack != null; + } + + /** + * Counts the number of items. + * + * @param inv + * @return + */ + public static int countItems(IInventory inv) { + int count = 0; + for (IInvSlot slot : InventoryIterator.getIterable(inv)) { + ItemStack stack = slot.getStackInSlot(); + if (stack != null) + count += stack.stackSize; + } + return count; + } + + public static int countItems(IInventory inv, IStackFilter filter) { + int count = 0; + for (IInvSlot slot : InventoryIterator.getIterable(inv)) { + ItemStack stack = slot.getStackInSlot(); + if (stack != null && filter.matches(stack)) + count += stack.stackSize; + } + return count; + } + + public static boolean numItemsMoreThan(IInventory inv, int amount) { + int count = 0; + for (IInvSlot slot : InventoryIterator.getIterable(inv)) { + ItemStack stack = slot.getStackInSlot(); + if (stack != null) + count += stack.stackSize; + if (count >= amount) + return true; + } + return false; + } + + /** + * Counts the number of items that match the filter. Ignores + * ISpecialInventory and ISidedInventory, and bypasses InventoryMapper to + * count from the base IInventory. + * + * @param inv + * @param filters + * @return + */ + public static int countItems(IInventory inv, ItemStack... filters) { + if (inv instanceof InventoryMapper) + inv = ((InventoryMapper) inv).getBaseInventory(); + boolean hasFilter = false; + for (ItemStack filter : filters) { + if (filter != null) { + hasFilter = true; + break; + } + } + + if (!hasFilter) + return countItems(inv); + + int count = 0; + ItemStack stack = null; + for (int slot = 0; slot < inv.getSizeInventory(); slot++) { + stack = inv.getStackInSlot(slot); + if (stack != null) + for (ItemStack filter : filters) { + if (filter != null && isItemEqual(stack, filter)) { + count += stack.stackSize; + break; + } + } + } + return count; + } + + public static int countItems(Collection inventories, ItemStack... filter) { + int count = 0; + for (IInventory inv : inventories) { + count += InvTools.countItems(inv, filter); + } + return count; + } + + /** + * Returns true if the inventory contains the specified item. + * + * @param inv The IIinventory to check + * @param item The ItemStack to look for + * @return true is exists + */ + public static boolean containsItem(IInventory inv, ItemStack item) { + return countItems(inv, item) > 0; + } + + /** + * Returns a map backed by an + * ItemStackMap that lists the total number of each type of + * item in the inventory. + * + * @param inv The IInventory to generate the manifest for + * @return A Map that lists how many of each item is in * * * + * the IInventory + * @see ItemStackMap + */ + public static Map getManifest(IInventory inv) { + Map manifest = new ItemStackMap(); + for (int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack slot = inv.getStackInSlot(i); + if (slot != null) { + Integer count = manifest.get(slot); + if (count == null) + count = 0; + count += slot.stackSize; + manifest.put(slot, count); + } + } + return manifest; + } + + /** + * Attempts to move a single item from one inventory to another. + * + * @param source + * @param dest + * @return null if nothing was moved, the stack moved otherwise + */ + public static ItemStack moveOneItem(IInventory source, IInventory dest) { + return moveOneItem(source, dest, StackFilter.ALL); + } + + /** + * Attempts to move a single item from one inventory to another. + * + * @param source + * @param dest + * @param filer an ItemStack[] to match against + * @return null if nothing was moved, the stack moved otherwise + */ + public static ItemStack moveOneItem(IInventory source, IInventory dest, ItemStack... filters) { + return moveOneItem(source, dest, new ArrayStackFilter(filters)); + } + + /** + * Attempts to move a single item from one inventory to another. + * + * @param source + * @param dest + * @param filer an IItemType to match against + * @return null if nothing was moved, the stack moved otherwise + */ + public static ItemStack moveOneItem(IInventory source, IInventory dest, IStackFilter filter) { + InventoryManipulator imSource = InventoryManipulator.get(source); + return imSource.moveItem(dest, filter); + } + + /** + * Attempts to move one item from a collection of inventories. + * + * @param sources + * @param dest + * @param filters + * @return + */ + public static ItemStack moveOneItem(Collection sources, IInventory dest, ItemStack... filters) { + for (IInventory inv : sources) { + ItemStack moved = InvTools.moveOneItem(inv, dest, filters); + if (moved != null) + return moved; + } + return null; + } + + /** + * Attempts to move one item from a collection of inventories. + * + * @param sources + * @param dest + * @param filters + * @return + */ + public static ItemStack moveOneItem(Collection sources, IInventory dest, IStackFilter filter) { + for (IInventory inv : sources) { + ItemStack moved = InvTools.moveOneItem(inv, dest, filter); + if (moved != null) + return moved; + } + return null; + } + + /** + * Attempts to move one item to a collection of inventories. + * + * @param sources + * @param dest + * @param filters + * @return + */ + public static ItemStack moveOneItem(IInventory source, Collection destinations, ItemStack... filters) { + for (IInventory dest : destinations) { + ItemStack moved = InvTools.moveOneItem(source, dest, filters); + if (moved != null) + return moved; + } + return null; + } + + /** + * Attempts to move a single item from one inventory to another. + * + * Will not move any items in the filter. + * + * @param source + * @param dest + * @param filer an ItemStack[] to exclude + * @return null if nothing was moved, the stack moved otherwise + */ + public static ItemStack moveOneItemExcept(IInventory source, IInventory dest, ItemStack... filters) { + return moveOneItem(source, dest, new InvertedStackFilter(new ArrayStackFilter(filters))); + } + + /** + * Attempts to move one item from a collection of inventories. + * + * @param sources + * @param dest + * @param filters + * @return + */ + public static ItemStack moveOneItemExcept(Collection sources, IInventory dest, ItemStack... filters) { + for (IInventory inv : sources) { + ItemStack moved = InvTools.moveOneItemExcept(inv, dest, filters); + if (moved != null) + return moved; + } + return null; + } + + /** + * Attempts to move one item to a collection of inventories. + * + * @param sources + * @param dest + * @param filters + * @return + */ + public static ItemStack moveOneItemExcept(IInventory source, Collection destinations, ItemStack... filters) { + for (IInventory dest : destinations) { + ItemStack moved = InvTools.moveOneItemExcept(source, dest, filters); + if (moved != null) + return moved; + } + return null; + } + + public static boolean isWildcard(ItemStack stack) { + return isWildcard(stack.getItemDamage()); + } + + public static boolean isWildcard(int damage) { + return damage == -1 || damage == OreDictionary.WILDCARD_VALUE; + } + + /** + * A more robust item comparison function. + * + * Compares stackSize as well. + * + * Two null stacks will return true, unlike the other functions. + * + * This function is primarily intended to be used to track changes to an + * ItemStack. + * + * @param a An ItemStack + * @param b An ItemStack + * @return True if equal + */ + public static boolean isItemEqualStrict(ItemStack a, ItemStack b) { + if (a == null && b == null) + return true; + if (a == null || b == null) + return false; + if (a.getItem() != b.getItem()) + return false; + if (a.stackSize != b.stackSize) + return false; + if (a.getItemDamage() != b.getItemDamage()) + return false; + if (a.stackTagCompound != null && !a.stackTagCompound.equals(b.stackTagCompound)) + return false; + return true; + } + + /** + * A more robust item comparison function. + * + * Compares stackSize as well. + * + * Two null stacks will return true, unlike the other functions. + * + * This function is primarily intended to be used to track changes to an + * ItemStack. + * + * @param a An ItemStack + * @param b An ItemStack + * @return True if equal + */ + public static boolean isItemEqualSemiStrict(ItemStack a, ItemStack b) { + if (a == null && b == null) + return true; + if (a == null || b == null) + return false; + if (a.getItem() != b.getItem()) + return false; + if (a.getItemDamage() != b.getItemDamage()) + return false; + if (a.stackTagCompound != null && !a.stackTagCompound.equals(b.stackTagCompound)) + return false; + return true; + } + + /** + * A more robust item comparison function. Supports items with damage = -1 + * matching any sub-type. + * + * @param a An ItemStack + * @param b An ItemStack + * @return True if equal + */ + public static boolean isItemEqual(ItemStack a, ItemStack b) { + return isItemEqual(a, b, true, true); + } + + /** + * A more robust item comparison function. Supports items with damage = -1 + * matching any sub-type. + * + * @param a An ItemStack + * @param b An ItemStack + * @return True if equal + */ + public static boolean isItemEqualIgnoreNBT(ItemStack a, ItemStack b) { + return isItemEqual(a, b, true, false); + } + + public static boolean isItemEqual(final ItemStack a, final ItemStack b, final boolean matchDamage, final boolean matchNBT) { + if (a == null || b == null) + return false; + if (a.getItem() != b.getItem()) + return false; + if (matchNBT && !ItemStack.areItemStackTagsEqual(a, b)) + return false; + if (matchDamage && a.getHasSubtypes()) { + if (isWildcard(a) || isWildcard(b)) + return true; + if (a.getItemDamage() != b.getItemDamage()) + return false; + } + return true; + } + + /** + * Returns true if the item is equal to any one of several possible matches. + * + * @param stack + * @param matches + * @return + */ + public static boolean isItemEqual(ItemStack stack, ItemStack... matches) { + for (ItemStack match : matches) { + if (isItemEqual(stack, match)) + return true; + } + return false; + } + + /** + * Returns true if the item is equal to any one of several possible matches. + * + * @param stack + * @param matches + * @return + */ + public static boolean isItemEqual(ItemStack stack, Collection matches) { + for (ItemStack match : matches) { + if (isItemEqual(stack, match)) + return true; + } + return false; + } + + /** + * Places an ItemStack in a destination IInventory. Will attempt to move as + * much of the stack as possible, returning any remainder. + * + * @param stack The ItemStack to put in the inventory. + * @param dest The destination IInventory. + * @return Null if itemStack was completely moved, a new itemStack with + * remaining stackSize if part or none of the stack was moved. + */ + public static ItemStack moveItemStack(ItemStack stack, IInventory dest) { + InventoryManipulator im = InventoryManipulator.get(dest); + return im.addStack(stack); + } + + /** + * Checks if there is room for the ItemStack in the inventory. + * + * @param stack The ItemStack + * @param dest The IInventory + * @return true if room for stack + */ + public static boolean isRoomForStack(ItemStack stack, IInventory dest) { + if (stack == null || dest == null) + return false; + InventoryManipulator im = InventoryManipulator.get(dest); + return im.canAddStack(stack); + } + + /** + * Removes a up to numItems worth of items from the inventory, not caring + * about what the items are. + * + * @param inv + * @param numItems + * @return + */ + public static ItemStack[] removeItems(IInventory inv, int numItems) { + if (inv instanceof ISpecialInventory) + return ((ISpecialInventory) inv).extractItem(true, ForgeDirection.UNKNOWN, numItems); + PlainInventory output = new PlainInventory(27, "temp"); + for (int i = 0; i < inv.getSizeInventory(); i++) { + if (numItems <= 0) + break; + ItemStack slot = inv.getStackInSlot(i); + if (slot == null) + continue; + ItemStack removed = inv.decrStackSize(i, numItems); + numItems -= removed.stackSize; + ItemStack remainder = moveItemStack(removed, output); + if (remainder != null) { + moveItemStack(remainder, inv); + numItems += remainder.stackSize; + break; + } + } + + List list = new LinkedList(); + for (ItemStack stack : output.getContents()) { + if (stack != null) + list.add(stack); + } + return list.toArray(new ItemStack[0]); + } + + /** + * Removes and returns a single item from the inventory. + * + * @param inv The inventory + * @return An ItemStack + */ + public static ItemStack removeOneItem(IInventory inv) { + return removeOneItem(inv, StackFilter.ALL); + } + + /** + * Removes and returns a single item from the inventory that matches the + * filter. + * + * @param inv The inventory + * @param filter ItemStack to match against + * @return An ItemStack + */ + public static ItemStack removeOneItem(IInventory inv, ItemStack... filter) { + return removeOneItem(inv, new ArrayStackFilter(filter)); + } + + /** + * Removes and returns a single item from the inventory that matches the + * filter. + * + * @param inv The inventory + * @param filter EnumItemType to match against + * @return An ItemStack + */ + public static ItemStack removeOneItem(IInventory inv, IStackFilter filter) { + InventoryManipulator im = InventoryManipulator.get(inv); + return im.removeItem(filter); + } + + /** + * Removes and returns a single item from the inventory that matches the + * filter. + * + * @param inv The inventory + * @param filter EnumItemType to match against + * @return An ItemStack + */ + public static ItemStack removeOneItem(Collection invs, IStackFilter filter) { + for (IInventory inv : invs) { + ItemStack stack = removeOneItem(inv, filter); + if (stack != null) + return stack; + } + return null; + } + + public static void writeInvToNBT(IInventory inv, String tag, NBTTagCompound data) { + NBTTagList list = new NBTTagList(); + for (byte slot = 0; slot < inv.getSizeInventory(); slot++) { + ItemStack stack = inv.getStackInSlot(slot); + if (stack != null) { + NBTTagCompound itemTag = new NBTTagCompound(); + itemTag.setByte(TAG_SLOT, slot); + writeItemToNBT(stack, itemTag); + list.appendTag(itemTag); + } + } + data.setTag(tag, list); + } + + public static void readInvFromNBT(IInventory inv, String tag, NBTTagCompound data) { + NBTTagList list = data.getTagList(tag, 10); + for (byte entry = 0; entry < list.tagCount(); entry++) { + NBTTagCompound itemTag = list.getCompoundTagAt(entry); + int slot = itemTag.getByte(TAG_SLOT); + if (slot >= 0 && slot < inv.getSizeInventory()) { + ItemStack stack = ItemStack.loadItemStackFromNBT(itemTag); + inv.setInventorySlotContents(slot, stack); + } + } + } + + public static void writeItemToNBT(ItemStack stack, NBTTagCompound data) { + if (stack == null || stack.stackSize <= 0) + return; + if (stack.stackSize > 127) + stack.stackSize = 127; + stack.writeToNBT(data); + } +} diff --git a/forestry_common/core/forestry/core/inventory/InventoryConcatenator.java b/forestry_common/core/forestry/core/inventory/InventoryConcatenator.java new file mode 100755 index 000000000..bec307dc0 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/InventoryConcatenator.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +/** + * Allows you to deal with multiple inventories through a single interface. + * + * @author CovertJaguar + */ +public class InventoryConcatenator implements IInventory { + + private final List slotMap = new ArrayList(); + private final List invMap = new ArrayList(); + + private InventoryConcatenator() { + } + + public static InventoryConcatenator make() { + return new InventoryConcatenator(); + } + + public InventoryConcatenator add(IInventory inv) { + for (int slot = 0; slot < inv.getSizeInventory(); slot++) { + slotMap.add(slot); + invMap.add(inv); + } + return this; + } + + @Override + public int getSizeInventory() { + return slotMap.size(); + } + + @Override + public ItemStack getStackInSlot(int slot) { + return invMap.get(slot).getStackInSlot(slotMap.get(slot)); + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + return invMap.get(slot).decrStackSize(slotMap.get(slot), amount); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return invMap.get(slot).getStackInSlotOnClosing(slotMap.get(slot)); + } + + @Override + public void setInventorySlotContents(int slot, ItemStack stack) { + invMap.get(slot).setInventorySlotContents(slotMap.get(slot), stack); + } + + @Override + public String getInventoryName() { + return ""; + } + + @Override + public boolean hasCustomInventoryName() { + return false; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public void markDirty() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack stack) { + return invMap.get(slot).isItemValidForSlot(slotMap.get(slot), stack); + } +} diff --git a/forestry_common/core/forestry/core/inventory/InventorySorter.java b/forestry_common/core/forestry/core/inventory/InventorySorter.java new file mode 100755 index 000000000..311735138 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/InventorySorter.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory; + +import java.util.Comparator; + +import net.minecraft.inventory.IInventory; + +/** + * + * @author CovertJaguar + */ +public enum InventorySorter implements Comparator { + + SIZE_DECENDING { + @Override + public int compare(IInventory inv1, IInventory inv2) { + return inv2.getSizeInventory() - inv1.getSizeInventory(); + } + + }; +} diff --git a/forestry_common/core/forestry/core/inventory/ItemStackMap.java b/forestry_common/core/forestry/core/inventory/ItemStackMap.java new file mode 100755 index 000000000..52ce0d192 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/ItemStackMap.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import net.minecraft.item.ItemStack; + +/** + * This is a custom data structure designed specifically + * for using ItemStacks as keys in a Map. + * + * The keys index on the itemID and damage of the ItemStacks, + * ignoring any other differences (NBT Tags, stackSize, etc...). + * + * @author CovertJaguar + * @see Map + * @param + */ +public class ItemStackMap implements Map +{ + + private class EntryWrapper implements Map.Entry + { + + private final Map.Entry entry; + + public EntryWrapper(Map.Entry e) + { + entry = e; + } + + @Override + public ItemStack getKey() + { + return entry.getKey().getStack(); + } + + @Override + public V getValue() + { + return entry.getValue(); + } + + @Override + public V setValue(V value) + { + return entry.setValue(value); + } + + @Override + public String toString() + { + return getKey().getItem().getUnlocalizedName() + "=" + getValue().toString(); + } + } + + private static class KeyWrapper + { + + private final ItemStack stack; + + public KeyWrapper(ItemStack stack) + { + this.stack = stack.copy(); + } + + @Override + public boolean equals(Object obj) + { + if(obj == null) { + return false; + } + if(getClass() != obj.getClass()) { + return false; + } + final KeyWrapper other = (KeyWrapper)obj; + if(stack.getItem() != other.stack.getItem()) { + return false; + } + if(stack.getItemDamage() != other.stack.getItemDamage()) { + return false; + } + return true; + } + + @Override + public int hashCode() + { + int hash = 5; + hash = 23 * hash + stack.getItem().hashCode(); + hash = 23 * hash + stack.getItemDamage(); + return hash; + } + + public ItemStack getStack() + { + return stack.copy(); + } + } + private final Map map = new HashMap(); + + @Override + public V put(ItemStack stack, V value) + { + return map.put(new KeyWrapper(stack), value); + } + + @Override + public Collection values() + { + return map.values(); + } + + @Override + public int size() + { + return map.size(); + } + + @Override + public V remove(Object key) + { + if(key instanceof ItemStack) { + return map.remove(new KeyWrapper((ItemStack)key)); + } + return null; + } + + @Override + public boolean isEmpty() + { + return map.isEmpty(); + } + + @Override + public int hashCode() + { + return map.hashCode(); + } + + @Override + public V get(Object key) + { + if(key instanceof ItemStack) { + return map.get(new KeyWrapper((ItemStack)key)); + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object o) + { + if(o instanceof ItemStackMap) { + return map.equals(((ItemStackMap)o).map); + } + return false; + } + + @Override + public boolean containsValue(Object value) + { + return map.containsValue(value); + } + + @Override + public boolean containsKey(Object key) + { + if(key instanceof ItemStack) { + return map.containsKey(new KeyWrapper((ItemStack)key)); + } + return false; + } + + @Override + public void clear() + { + map.clear(); + } + + @Override + public void putAll(Map m) + { + for(Map.Entry e : m.entrySet()) { + put(e.getKey(), e.getValue()); + } + } + + @Override + public Set keySet() + { + Set keySet = new HashSet(); + for(KeyWrapper w : map.keySet()) { + keySet.add(w.getStack()); + } + return keySet; + } + + @Override + public Set> entrySet() + { + Set> entrySet = new HashSet>(); + + for(Map.Entry entry : map.entrySet()) { + entrySet.add(new EntryWrapper(entry)); + } + return entrySet; + } +} diff --git a/forestry_common/core/forestry/core/inventory/ItemStackSet.java b/forestry_common/core/forestry/core/inventory/ItemStackSet.java new file mode 100755 index 000000000..e7de833fb --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/ItemStackSet.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import net.minecraft.item.ItemStack; + +/** + * This is a custom data structure designed specifically for using ItemStacks as + * elements of a Set. + * + * Its backed by an ArrayList, so as expected, most operations result in + * traversing the list one or more times. + * + * @author CovertJaguar + */ +public class ItemStackSet implements Set { + + private final List set = new ArrayList(); + + @Override + public int size() { + return set.size(); + } + + @Override + public boolean isEmpty() { + return set.isEmpty(); + } + + @Override + public boolean contains(Object obj) { + if (!(obj instanceof ItemStack)) { + return false; + } + ItemStack check = (ItemStack) obj; + for (ItemStack stack : set) { + if (InvTools.isItemEqual(stack, check)) { + return true; + } + } + return false; + } + + @Override + public Iterator iterator() { + return set.iterator(); + } + + @Override + public Object[] toArray() { + return set.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return set.toArray(a); + } + + @Override + public boolean add(ItemStack e) { + if (contains(e)) { + return false; + } + set.add(e); + return true; + } + + @Override + public boolean remove(Object obj) { + if (!(obj instanceof ItemStack)) { + return false; + } + boolean changed = false; + ItemStack check = (ItemStack) obj; + Iterator it = set.iterator(); + while (it.hasNext()) { + ItemStack stack = it.next(); + if (InvTools.isItemEqual(stack, check)) { + it.remove(); + changed = true; + } + } + return changed; + } + + @Override + public boolean containsAll(Collection c) { + for (Object obj : c) { + if (!(obj instanceof ItemStack)) { + return false; + } + if (!contains(obj)) { + return false; + } + } + return true; + } + + @Override + public boolean addAll(Collection c) { + boolean changed = false; + for (ItemStack stack : c) { + changed |= add(stack); + } + return changed; + } + + @Override + public boolean retainAll(Collection c) { + boolean changed = false; + Iterator it = set.iterator(); + while (it.hasNext()) { + ItemStack stack = it.next(); + if (!c.contains(stack)) { + it.remove(); + changed = true; + } + } + return changed; + } + + @Override + public boolean removeAll(Collection c) { + boolean changed = false; + Iterator it = set.iterator(); + while (it.hasNext()) { + ItemStack stack = it.next(); + if (c.contains(stack)) { + it.remove(); + changed = true; + } + } + return changed; + } + + @Override + public void clear() { + set.clear(); + } +} diff --git a/forestry_common/core/forestry/core/inventory/ItemStackSizeSorter.java b/forestry_common/core/forestry/core/inventory/ItemStackSizeSorter.java new file mode 100755 index 000000000..b82dec423 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/ItemStackSizeSorter.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import net.minecraft.item.ItemStack; + +public class ItemStackSizeSorter implements Comparator { + + private static ItemStackSizeSorter instance; + + private static ItemStackSizeSorter getInstance() { + if (instance == null) { + instance = new ItemStackSizeSorter(); + } + return instance; + } + + public static void sort(List list) { + Collections.sort(list, getInstance()); + } + + @Override + public int compare(ItemStack o1, ItemStack o2) { + return o1.stackSize - o2.stackSize; + } + +} diff --git a/forestry_common/core/forestry/core/inventory/filters/ArrayStackFilter.java b/forestry_common/core/forestry/core/inventory/filters/ArrayStackFilter.java new file mode 100755 index 000000000..d6c0ce7f7 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/filters/ArrayStackFilter.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.filters; + +import net.minecraft.item.ItemStack; + +import forestry.core.inventory.InvTools; + +/** + * + * @author CovertJaguar + */ +public class ArrayStackFilter implements IStackFilter { + + private final ItemStack[] stacks; + + public ArrayStackFilter(ItemStack... stacks) { + this.stacks = stacks; + } + + @Override + public boolean matches(ItemStack stack) { + if (stacks.length == 0 || !hasFilter()) { + return true; + } + return InvTools.isItemEqual(stack, stacks); + } + + public ItemStack[] getStacks() { + return stacks; + } + + public boolean hasFilter() { + for (ItemStack filter : stacks) { + if (filter != null) { + return true; + } + } + return false; + } +} diff --git a/forestry_common/core/forestry/core/inventory/filters/IStackFilter.java b/forestry_common/core/forestry/core/inventory/filters/IStackFilter.java new file mode 100755 index 000000000..36858c31a --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/filters/IStackFilter.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.filters; + +import net.minecraft.item.ItemStack; + +/** + * This interface is used with several of the functions in IItemTransfer to + * provide a convenient means of dealing with entire classes of items without + * having to specify each item individually. + * + * @author CovertJaguar + */ +public interface IStackFilter { + + public boolean matches(ItemStack stack); +} diff --git a/forestry_common/core/forestry/core/inventory/filters/InvertedStackFilter.java b/forestry_common/core/forestry/core/inventory/filters/InvertedStackFilter.java new file mode 100755 index 000000000..9c3214757 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/filters/InvertedStackFilter.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.filters; + +import net.minecraft.item.ItemStack; + +/** + * + * @author CovertJaguar + */ +public class InvertedStackFilter implements IStackFilter { + + private final IStackFilter filter; + + public InvertedStackFilter(IStackFilter filter) { + this.filter = filter; + } + + @Override + public boolean matches(ItemStack stack) { + if (stack == null) { + return false; + } + return !filter.matches(stack); + } +} diff --git a/forestry_common/core/forestry/core/inventory/filters/StackFilter.java b/forestry_common/core/forestry/core/inventory/filters/StackFilter.java new file mode 100755 index 000000000..020282e01 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/filters/StackFilter.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.filters; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemFood; +import net.minecraft.item.ItemSeeds; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntityFurnace; + +/** + * This interface is used with several of the functions in IItemTransfer to + * provide a convenient means of dealing with entire classes of items without + * having to specify each item individually. + * + * @author CovertJaguar + */ +public enum StackFilter implements IStackFilter { + + ALL { + @Override + public boolean matches(ItemStack stack) { + return true; + } + }, + FUEL { + @Override + public boolean matches(ItemStack stack) { + return TileEntityFurnace.getItemBurnTime(stack) > 0; + } + }, + FEED { + @Override + public boolean matches(ItemStack stack) { + return stack.getItem() instanceof ItemFood || stack.getItem() == Items.wheat || stack.getItem() instanceof ItemSeeds; + } + }; + + @Override + public abstract boolean matches(ItemStack stack); +} diff --git a/forestry_common/core/forestry/core/inventory/manipulators/InventoryManipulator.java b/forestry_common/core/forestry/core/inventory/manipulators/InventoryManipulator.java new file mode 100755 index 000000000..bf3df6c3e --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/manipulators/InventoryManipulator.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.manipulators; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.core.inventory.InvTools; +import forestry.core.inventory.filters.IStackFilter; +import forestry.core.inventory.wrappers.IInvSlot; +import forestry.core.inventory.wrappers.InventoryIterator; + +/** + * + * @author CovertJaguar + */ +public class InventoryManipulator { + + private final IInventory inv; + + public static InventoryManipulator get(IInventory inv) { + if (inv instanceof ISpecialInventory) { + return new SpecialManipulator((ISpecialInventory) inv); + } + return new InventoryManipulator(inv); + } + + protected InventoryManipulator(IInventory inv) { + this.inv = inv; + } + + protected Iterable getSlots() { + return InventoryIterator.getIterable(inv); + } + + public boolean canAddStack(ItemStack stack) { + return tryAddStack(stack) == null; + } + + public ItemStack tryAddStack(ItemStack stack) { + return addStack(stack, false); + } + + /** + * Attempt to add the stack to the inventory. + * + * @param stack + * @return The remainder + */ + public ItemStack addStack(ItemStack stack) { + return addStack(stack, true); + } + + private ItemStack addStack(ItemStack stack, boolean doAdd) { + if (stack == null || stack.stackSize <= 0) { + return null; + } + stack = stack.copy(); + List filledSlots = new ArrayList(inv.getSizeInventory()); + List emptySlots = new ArrayList(inv.getSizeInventory()); + for (IInvSlot slot : InventoryIterator.getIterable(inv)) { + if (slot.canPutStackInSlot(stack)) { + if (slot.getStackInSlot() == null) { + emptySlots.add(slot); + } else { + filledSlots.add(slot); + } + } + } + + int injected = 0; + injected = tryPut(filledSlots, stack, injected, doAdd); + injected = tryPut(emptySlots, stack, injected, doAdd); + stack.stackSize -= injected; + if (stack.stackSize <= 0) { + return null; + } + return stack; + } + + private int tryPut(List slots, ItemStack stack, int injected, boolean doAdd) { + if (injected >= stack.stackSize) { + return injected; + } + for (IInvSlot slot : slots) { + ItemStack stackInSlot = slot.getStackInSlot(); + if (stackInSlot == null || InvTools.isItemEqual(stackInSlot, stack)) { + int used = addToSlot(slot, stack, stack.stackSize - injected, doAdd); + if (used > 0) { + injected += used; + if (injected >= stack.stackSize) { + return injected; + } + } + } + } + return injected; + } + + /** + * + * @param slot + * @param stack + * @param available Amount we can move + * @param doAdd + * @return Return the number of items moved. + */ + private int addToSlot(IInvSlot slot, ItemStack stack, int available, boolean doAdd) { + int max = Math.min(stack.getMaxStackSize(), inv.getInventoryStackLimit()); + + ItemStack stackInSlot = slot.getStackInSlot(); + if (stackInSlot == null) { + int wanted = Math.min(available, max); + if (doAdd) { + stackInSlot = stack.copy(); + stackInSlot.stackSize = wanted; + slot.setStackInSlot(stackInSlot); + } + return wanted; + } + + if (!InvTools.isItemEqual(stack, stackInSlot)) { + return 0; + } + + int wanted = max - stackInSlot.stackSize; + if (wanted <= 0) { + return 0; + } + + if (wanted > available) { + wanted = available; + } + + if (doAdd) { + stackInSlot.stackSize += wanted; + slot.setStackInSlot(stackInSlot); + } + return wanted; + } + + public boolean canRemoveItem(IStackFilter filter) { + return tryRemoveItem(filter) == null; + } + + public ItemStack tryRemoveItem(IStackFilter filter) { + for (IInvSlot slot : getSlots()) { + ItemStack stack = slot.getStackInSlot(); + if (stack != null && slot.canTakeStackFromSlot(stack) && filter.matches(stack)) { + ItemStack output = stack.copy(); + output.stackSize = 1; + return output; + } + } + return null; + } + + public ItemStack removeItem(IStackFilter filter) { + for (IInvSlot slot : getSlots()) { + ItemStack stack = slot.getStackInSlot(); + if (stack != null && slot.canTakeStackFromSlot(stack) && filter.matches(stack)) { + return slot.decreaseStackInSlot(); + } + } + return null; + } + + public ItemStack moveItem(IInventory dest, IStackFilter filter) { + InventoryManipulator imDest = InventoryManipulator.get(dest); + for (IInvSlot slot : getSlots()) { + ItemStack stack = slot.getStackInSlot(); + if (stack != null && slot.canTakeStackFromSlot(stack) && filter.matches(stack)) { + stack = stack.copy(); + stack.stackSize = 1; + stack = imDest.addStack(stack); + if (stack == null) { + return slot.decreaseStackInSlot(); + } + } + } + return null; + } + +} diff --git a/forestry_common/core/forestry/core/inventory/manipulators/SpecialManipulator.java b/forestry_common/core/forestry/core/inventory/manipulators/SpecialManipulator.java new file mode 100755 index 000000000..4d5565102 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/manipulators/SpecialManipulator.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.manipulators; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.core.inventory.filters.IStackFilter; + +/** + * + * @author CovertJaguar + */ +public class SpecialManipulator extends InventoryManipulator { + + private final ISpecialInventory inv; + protected ForgeDirection side = ForgeDirection.UNKNOWN; + + protected SpecialManipulator(ISpecialInventory inv) { + super(inv); + this.inv = inv; + } + + public void setSide(ForgeDirection side) { + this.side = side; + } + + @Override + public ItemStack tryAddStack(ItemStack stack) { + return addStackInternal(stack, false); + } + + @Override + public ItemStack addStack(ItemStack stack) { + return addStackInternal(stack, true); + } + + private ItemStack addStackInternal(ItemStack stack, boolean doAdd) { + if (stack == null) { + return null; + } + stack = stack.copy(); + int used = inv.addItem(stack.copy(), doAdd, side); + if (used >= stack.stackSize) { + return null; + } + stack.stackSize -= used; + return stack; + } + + @Override + public boolean canRemoveItem(IStackFilter filter) { + return tryRemoveItem(filter) == null; + } + + @Override + public ItemStack tryRemoveItem(IStackFilter filter) { + return removeStackInternal(filter, false); + } + + @Override + public ItemStack removeItem(IStackFilter filter) { + return removeStackInternal(filter, true); + } + + protected ItemStack removeStackInternal(IStackFilter filter, boolean doRemove) { + ItemStack[] extracted = inv.extractItem(false, side, 1); + if (extracted != null && extracted.length > 0 && filter.matches(extracted[0])) { + if (doRemove) { + inv.extractItem(true, side, 1); + } + return extracted[0]; + } + return null; + } + + @Override + public ItemStack moveItem(IInventory dest, IStackFilter filter) { + InventoryManipulator imDest = InventoryManipulator.get(dest); + ItemStack stack = tryRemoveItem(filter); + if (stack != null) { + ItemStack result = imDest.addStack(stack); + if (result == null) { + return removeItem(filter); + } + } + return null; + } + +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/ChestWrapper.java b/forestry_common/core/forestry/core/inventory/wrappers/ChestWrapper.java new file mode 100755 index 000000000..0e9ee049f --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/ChestWrapper.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntityChest; + +/** + * + * @author CovertJaguar + */ +public class ChestWrapper implements IInventory { + + /** + * Inventory object corresponding to double chest upper part + */ + private final TileEntityChest upperChest; + /** + * Inventory object corresponding to double chest lower part + */ + private TileEntityChest lowerChest; + + public ChestWrapper(TileEntityChest tile) { + this.upperChest = tile; + checkChest(); + } + + private void checkChest() { + if (lowerChest == null || lowerChest.isInvalid()) { + if (upperChest.adjacentChestXNeg != null) { + lowerChest = upperChest.adjacentChestXNeg; + } else if (upperChest.adjacentChestXPos != null) { + lowerChest = upperChest.adjacentChestXPos; + } else if (upperChest.adjacentChestZNeg != null) { + lowerChest = upperChest.adjacentChestZNeg; + } else if (upperChest.adjacentChestZPos != null) { + lowerChest = upperChest.adjacentChestZPos; + } else { + lowerChest = null; + } + } + } + + /** + * Returns the number of slots in the inventory. + */ + @Override + public int getSizeInventory() { + checkChest(); + int size = upperChest.getSizeInventory(); + if (lowerChest != null) { + size += lowerChest.getSizeInventory(); + } + return size; + } + + /** + * Return whether the given inventory is part of this large chest. + */ + public boolean isPartOfLargeChest(IInventory inv) { + return this.upperChest == inv || this.lowerChest == inv; + } + + /** + * Returns the name of the inventory. + */ + @Override + public String getInventoryName() { + return ""; + } + + /** + * If this returns false, the inventory name will be used as an unlocalized + * name, and translated into the player's language. Otherwise it will be + * used directly. + */ + @Override + public boolean hasCustomInventoryName() { + return false; + } + + /** + * Returns the stack in slot i + */ + @Override + public ItemStack getStackInSlot(int slot) { + checkChest(); + if (slot >= upperChest.getSizeInventory() && lowerChest != null) { + return lowerChest.getStackInSlot(slot - upperChest.getSizeInventory()); + } + return upperChest.getStackInSlot(slot); + } + + /** + * Removes from an inventory slot (first arg) up to a specified number + * (second arg) of items and returns them in a new stack. + */ + @Override + public ItemStack decrStackSize(int slot, int amout) { + checkChest(); + if (slot >= upperChest.getSizeInventory() && lowerChest != null) { + return lowerChest.decrStackSize(slot - upperChest.getSizeInventory(), amout); + } + return upperChest.decrStackSize(slot, amout); + } + + /** + * When some containers are closed they call this on each slot, then drop + * whatever it returns as an EntityItem - like when you close a workbench + * GUI. + */ + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + checkChest(); + if (slot >= upperChest.getSizeInventory() && lowerChest != null) { + return lowerChest.getStackInSlotOnClosing(slot - upperChest.getSizeInventory()); + } + return upperChest.getStackInSlotOnClosing(slot); + } + + /** + * Sets the given item stack to the specified slot in the inventory (can be + * crafting or armor sections). + */ + @Override + public void setInventorySlotContents(int slot, ItemStack stack) { + checkChest(); + if (slot >= this.upperChest.getSizeInventory() && lowerChest != null) { + lowerChest.setInventorySlotContents(slot - upperChest.getSizeInventory(), stack); + } else { + upperChest.setInventorySlotContents(slot, stack); + } + } + + /** + * Returns the maximum stack size for a inventory slot. Seems to always be + * 64, possibly will be extended. *Isn't this more of a set than a get?* + */ + @Override + public int getInventoryStackLimit() { + return this.upperChest.getInventoryStackLimit(); + } + + /** + * Called when an the contents of an Inventory change, usually + */ + @Override + public void markDirty() { + this.upperChest.markDirty(); + if (lowerChest != null) lowerChest.markDirty(); + } + + /** + * Do not make give this method the name canInteractWith because it clashes + * with Container + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return this.upperChest.isUseableByPlayer(player) && (lowerChest == null || lowerChest.isUseableByPlayer(player)); + } + + @Override + public void openInventory() { + this.upperChest.openInventory(); + if (lowerChest != null) lowerChest.openInventory(); + } + + @Override + public void closeInventory() { + this.upperChest.closeInventory(); + if (lowerChest != null) lowerChest.closeInventory(); + } + + /** + * Returns true if automation is allowed to insert the given stack (ignoring + * stack size) into the given slot. + */ + @Override + public boolean isItemValidForSlot(int slot, ItemStack stack) { + return true; + } + +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/IInvSlot.java b/forestry_common/core/forestry/core/inventory/wrappers/IInvSlot.java new file mode 100755 index 000000000..95f7eb1fe --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/IInvSlot.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import net.minecraft.item.ItemStack; + +/** + * + * @author CovertJaguar + */ +public interface IInvSlot { + + boolean canPutStackInSlot(ItemStack stack); + + boolean canTakeStackFromSlot(ItemStack stack); + + ItemStack decreaseStackInSlot(); + + ItemStack getStackInSlot(); + + void setStackInSlot(ItemStack stack); + + int getIndex(); + +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/InventoryCopy.java b/forestry_common/core/forestry/core/inventory/wrappers/InventoryCopy.java new file mode 100755 index 000000000..48010826f --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/InventoryCopy.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +/** + * Creates a deep copy of an existing IInventory. + * + * Useful for performing inventory manipulations and then examining the results + * without affecting the original inventory. + * + * @author CovertJaguar + */ +public class InventoryCopy implements IInventory { + + private final IInventory orignal; + private final ItemStack contents[]; + + public InventoryCopy(IInventory orignal) { + this.orignal = orignal; + contents = new ItemStack[orignal.getSizeInventory()]; + for (int i = 0; i < contents.length; i++) { + ItemStack stack = orignal.getStackInSlot(i); + if (stack != null) { + contents[i] = stack.copy(); + } + } + } + + @Override + public int getSizeInventory() { + return contents.length; + } + + @Override + public ItemStack getStackInSlot(int i) { + return contents[i]; + } + + @Override + public ItemStack decrStackSize(int i, int j) { + if (contents[i] != null) { + if (contents[i].stackSize <= j) { + ItemStack itemstack = contents[i]; + contents[i] = null; + markDirty(); + return itemstack; + } + ItemStack itemstack1 = contents[i].splitStack(j); + if (contents[i].stackSize <= 0) { + contents[i] = null; + } + markDirty(); + return itemstack1; + } else { + return null; + } + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + contents[i] = itemstack; + if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) { + itemstack.stackSize = getInventoryStackLimit(); + } + markDirty(); + } + + @Override + public String getInventoryName() { + return orignal.getInventoryName(); + } + + @Override + public int getInventoryStackLimit() { + return orignal.getInventoryStackLimit(); + } + + @Override + public void markDirty() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return orignal.getStackInSlotOnClosing(slot); + } + + @Override + public boolean hasCustomInventoryName() { + return orignal.hasCustomInventoryName(); + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack stack) { + return orignal.isItemValidForSlot(slot, stack); + } +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/InventoryIterator.java b/forestry_common/core/forestry/core/inventory/wrappers/InventoryIterator.java new file mode 100755 index 000000000..12ee251a9 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/InventoryIterator.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import java.util.Iterator; + +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; + +/** + * @author CovertJaguar + */ +public class InventoryIterator implements Iterable { + + public static Iterable getIterable(IInventory inv) { + if (inv instanceof ISidedInventory) + return new SidedInventoryIterator((ISidedInventory) inv); + return new InventoryIterator(inv); + } + + private final IInventory inv; + private final int invSize; + + private InventoryIterator(IInventory inv) { + this.inv = inv; + this.invSize = inv.getSizeInventory(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + int slot = 0; + + @Override + public boolean hasNext() { + return slot < invSize; + } + + @Override + public IInvSlot next() { + return new InvSlot(slot++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Remove not supported."); + } + + }; + } + + private class InvSlot implements IInvSlot { + + private int slot; + + public InvSlot(int slot) { + this.slot = slot; + } + + @Override + public ItemStack getStackInSlot() { + return inv.getStackInSlot(slot); + } + + @Override + public void setStackInSlot(ItemStack stack) { + inv.setInventorySlotContents(slot, stack); + } + + @Override + public boolean canPutStackInSlot(ItemStack stack) { + return inv.isItemValidForSlot(slot, stack); + } + + @Override + public boolean canTakeStackFromSlot(ItemStack stack) { + return true; + } + + @Override + public ItemStack decreaseStackInSlot() { + return inv.decrStackSize(slot, 1); + } + + @Override + public int getIndex() { + return slot; + } + + } +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/InventoryMapper.java b/forestry_common/core/forestry/core/inventory/wrappers/InventoryMapper.java new file mode 100755 index 000000000..0b0859e6b --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/InventoryMapper.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Wrapper class used to specify part of an existing inventory to be treated as + * a complete inventory. Used primarily to map a side of an ISidedInventory, but + * it is also helpful for complex inventories such as the Tunnel Bore. + * + * @author CovertJaguar + */ +public class InventoryMapper implements IInventory { + + private final IInventory inv; + private final int start; + private final int size; + private int stackSizeLimit = -1; + private boolean checkItems = true; + + public InventoryMapper(IInventory inv, ForgeDirection side) { + this(inv, getInventoryStart(inv, side), getInventorySize(inv, side)); + } + + public InventoryMapper(IInventory inv) { + this(inv, 0, inv.getSizeInventory(), true); + } + + public InventoryMapper(IInventory inv, boolean checkItems) { + this(inv, 0, inv.getSizeInventory(), checkItems); + } + + /** + * Creates a new InventoryMapper + * + * @param inv The backing inventory + * @param start The starting index + * @param size The size of the new inventory, take care not to exceed the + * end of the backing inventory + */ + public InventoryMapper(IInventory inv, int start, int size) { + this(inv, start, size, true); + } + + public InventoryMapper(IInventory inv, int start, int size, boolean checkItems) { + this.inv = inv; + this.start = start; + this.size = size; + this.checkItems = checkItems; + } + + protected static int getInventorySize(IInventory inv, ForgeDirection side) { + return inv.getSizeInventory(); + } + + protected static int getInventoryStart(IInventory inv, ForgeDirection side) { + return 0; + } + + public IInventory getBaseInventory() { + return inv; + } + + @Override + public int getSizeInventory() { + return size; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return inv.getStackInSlot(start + slot); + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + return inv.decrStackSize(start + slot, amount); + } + + @Override + public void setInventorySlotContents(int slot, ItemStack itemstack) { + inv.setInventorySlotContents(start + slot, itemstack); + } + + @Override + public String getInventoryName() { + return inv.getInventoryName(); + } + + public void setStackSizeLimit(int limit) { + stackSizeLimit = limit; + } + + @Override + public int getInventoryStackLimit() { + return stackSizeLimit > 0 ? stackSizeLimit : inv.getInventoryStackLimit(); + } + + @Override + public void markDirty() { + inv.markDirty(); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return inv.isUseableByPlayer(entityplayer); + } + + @Override + public void openInventory() { + inv.openInventory(); + } + + @Override + public void closeInventory() { + inv.closeInventory(); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inv.getStackInSlotOnClosing(start + slot); + } + + @Override + public boolean hasCustomInventoryName() { + return inv.hasCustomInventoryName(); + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack stack) { + if (checkItems) + return inv.isItemValidForSlot(start + slot, stack); + return true; + } + +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryIterator.java b/forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryIterator.java new file mode 100755 index 000000000..eb2a4c675 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryIterator.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import java.util.Iterator; + +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; + +/** + * @author CovertJaguar + */ +public class SidedInventoryIterator implements Iterable { + + private final ISidedInventory inv; + + SidedInventoryIterator(ISidedInventory inv) { + this.inv = inv; + } + + @Override + public Iterator iterator() { + return new Iterator() { + int[] slots = inv.getAccessibleSlotsFromSide(0); + int index = 0; + + @Override + public boolean hasNext() { + return slots != null && index < slots.length; + } + + @Override + public IInvSlot next() { + return new InvSlot(slots[index++]); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Remove not supported."); + } + + }; + } + + private class InvSlot implements IInvSlot { + + private int slot; + + public InvSlot(int slot) { + this.slot = slot; + } + + @Override + public ItemStack getStackInSlot() { + return inv.getStackInSlot(slot); + } + + @Override + public void setStackInSlot(ItemStack stack) { + inv.setInventorySlotContents(slot, stack); + } + + @Override + public boolean canPutStackInSlot(ItemStack stack) { + return inv.canInsertItem(slot, stack, 0); + } + + @Override + public boolean canTakeStackFromSlot(ItemStack stack) { + return inv.canExtractItem(slot, stack, 0); + } + + @Override + public ItemStack decreaseStackInSlot() { + return inv.decrStackSize(slot, 1); + } + + @Override + public int getIndex(){ + return slot; + } + + } +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryMapper.java b/forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryMapper.java new file mode 100755 index 000000000..73a982148 --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/SidedInventoryMapper.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Wrapper class used to bake the side variable into the object itself instead + * of passing it around to all the inventory tools. + * + * @author CovertJaguar + */ +public class SidedInventoryMapper implements ISidedInventory { + + private final ISidedInventory inv; + private final int side; + private boolean checkItems = true; + + public SidedInventoryMapper(ISidedInventory inv, ForgeDirection side) { + this(inv, side, true); + } + + public SidedInventoryMapper(ISidedInventory inv, ForgeDirection side, boolean checkItems) { + this.inv = inv; + this.side = side.ordinal(); + this.checkItems = checkItems; + } + + public IInventory getBaseInventory() { + return inv; + } + + @Override + public int getSizeInventory() { + return inv.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int slot) { + return inv.getStackInSlot(slot); + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + return inv.decrStackSize(slot, amount); + } + + @Override + public void setInventorySlotContents(int slot, ItemStack itemstack) { + inv.setInventorySlotContents(slot, itemstack); + } + + @Override + public String getInventoryName() { + return inv.getInventoryName(); + } + + @Override + public int getInventoryStackLimit() { + return inv.getInventoryStackLimit(); + } + + @Override + public void markDirty() { + inv.markDirty(); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return inv.isUseableByPlayer(entityplayer); + } + + @Override + public void openInventory() { + inv.openInventory(); + } + + @Override + public void closeInventory() { + inv.closeInventory(); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inv.getStackInSlotOnClosing(slot); + } + + @Override + public boolean hasCustomInventoryName() { + return inv.hasCustomInventoryName(); + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack stack) { + return !checkItems || inv.isItemValidForSlot(slot, stack); + } + + @Override + public int[] getAccessibleSlotsFromSide(int s) { + return inv.getAccessibleSlotsFromSide(side); + } + + @Override + public boolean canInsertItem(int slot, ItemStack stack, int s) { + return !checkItems || inv.canInsertItem(slot, stack, side); + } + + @Override + public boolean canExtractItem(int slot, ItemStack stack, int s) { + return !checkItems || inv.canExtractItem(slot, stack, side); + } + +} diff --git a/forestry_common/core/forestry/core/inventory/wrappers/SpecialInventoryMapper.java b/forestry_common/core/forestry/core/inventory/wrappers/SpecialInventoryMapper.java new file mode 100755 index 000000000..a44c0361d --- /dev/null +++ b/forestry_common/core/forestry/core/inventory/wrappers/SpecialInventoryMapper.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.inventory.wrappers; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.inventory.ISpecialInventory; + +/** + * + * @author CovertJaguar + */ +public class SpecialInventoryMapper extends InventoryMapper implements ISpecialInventory +{ + + private final ISpecialInventory inv; + protected final ForgeDirection side; + + public SpecialInventoryMapper(ISpecialInventory inv, ForgeDirection side) + { + super(inv, side); + this.inv = inv; + this.side = side; + } + + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) + { + return inv.addItem(stack, doAdd, side); + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) + { + return inv.extractItem(doRemove, side, maxItemCount); + } +} diff --git a/forestry_common/core/forestry/core/items/ItemArmorNaturalist.java b/forestry_common/core/forestry/core/items/ItemArmorNaturalist.java new file mode 100755 index 000000000..7a4939350 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemArmorNaturalist.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.IArmorNaturalist; +import forestry.core.CreativeTabForestry; +import forestry.core.config.Defaults; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemArmorNaturalist extends ItemArmor implements IArmorNaturalist { + + public ItemArmorNaturalist(int slot) { + super(ArmorMaterial.CLOTH, 0, slot); + this.setMaxDamage(100); + setCreativeTab(CreativeTabForestry.tabForestry); + } + + public String getArmorTexture(ItemStack stack, Entity entity, int slot, int layer) { + return Defaults.ID + ":" + Defaults.TEXTURE_NATURALIST_ARMOR_PRIMARY; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + itemIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "")); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int par1, int par2) { + return itemIcon; + } + + @Override + public boolean requiresMultipleRenderPasses() { + return false; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int renderPass) { + return 0xffffff; + } + + @Override + public boolean hasColor(ItemStack itemstack) { + return false; + } + + @Override + public boolean canSeePollination(EntityPlayer player, ItemStack armor, boolean doSee) { + return armorType == 0; + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemAssemblyKit.java b/forestry_common/core/forestry/core/items/ItemAssemblyKit.java new file mode 100755 index 000000000..2a7f68a53 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemAssemblyKit.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; + +import forestry.core.proxy.Proxies; + +public class ItemAssemblyKit extends ItemForestry { + private final ItemStack assembled; + private final boolean motionOnOpen; + + public ItemAssemblyKit(ItemStack assembled) { + this(assembled, false); + } + + public ItemAssemblyKit(ItemStack assembled, boolean motionOnOpen) { + super(); + maxStackSize = 24; + this.assembled = assembled; + this.motionOnOpen = motionOnOpen; + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) { + itemstack.stackSize--; + EntityItem entity = new EntityItem(world, entityplayer.posX, entityplayer.posY, entityplayer.posZ, assembled.copy()); + + if (motionOnOpen) { + float f1 = 0.3F; + entity.motionX = -MathHelper.sin((entityplayer.rotationYaw / 180F) * 3.141593F) + * MathHelper.cos((entityplayer.rotationPitch / 180F) * 3.141593F) * f1; + entity.motionZ = MathHelper.cos((entityplayer.rotationYaw / 180F) * 3.141593F) + * MathHelper.cos((entityplayer.rotationPitch / 180F) * 3.141593F) * f1; + entity.motionY = -MathHelper.sin((entityplayer.rotationPitch / 180F) * 3.141593F) * f1 + 0.1F; + f1 = 0.02F; + float f3 = world.rand.nextFloat() * 3.141593F * 2.0F; + f1 *= world.rand.nextFloat(); + entity.motionX += Math.cos(f3) * f1; + entity.motionY += (world.rand.nextFloat() - world.rand.nextFloat()) * 0.1F; + entity.motionZ += Math.sin(f3) * f1; + } + + world.spawnEntityInWorld(entity); + } + return itemstack; + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemCrated.java b/forestry_common/core/forestry/core/items/ItemCrated.java new file mode 100755 index 000000000..8ceae8c6a --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemCrated.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import java.util.Locale; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.recipes.IGenericCrate; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemCrated extends Item implements IGenericCrate { + + private ItemStack contained; + + public ItemCrated() { + this(null); + } + + public ItemCrated(ItemStack contained) { + super(); + this.contained = contained; + } + + @Override + public void setContained(ItemStack crated, ItemStack contained) { + this.contained = contained; + } + + @Override + public ItemStack getContained(ItemStack crate) { + return contained; + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + + if (Proxies.common.isSimulating(world)) { + if (contained == null) + return itemstack; + + itemstack.stackSize--; + EntityItem entity = new EntityItem(world, entityplayer.posX, entityplayer.posY, entityplayer.posZ, new ItemStack(contained.getItem(), 9, + contained.getItemDamage())); + entity.delayBeforeCanPickup = 40; + + float f1 = 0.3F; + entity.motionX = -MathHelper.sin((entityplayer.rotationYaw / 180F) * 3.141593F) * MathHelper.cos((entityplayer.rotationPitch / 180F) * 3.141593F) + * f1; + entity.motionZ = MathHelper.cos((entityplayer.rotationYaw / 180F) * 3.141593F) * MathHelper.cos((entityplayer.rotationPitch / 180F) * 3.141593F) + * f1; + entity.motionY = -MathHelper.sin((entityplayer.rotationPitch / 180F) * 3.141593F) * f1 + 0.1F; + f1 = 0.02F; + float f3 = world.rand.nextFloat() * 3.141593F * 2.0F; + f1 *= world.rand.nextFloat(); + entity.motionX += Math.cos(f3) * f1; + entity.motionY += (world.rand.nextFloat() - world.rand.nextFloat()) * 0.1F; + entity.motionZ += Math.sin(f3) * f1; + + world.spawnEntityInWorld(entity); + } + return itemstack; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (contained != null) + return StringUtil.localize("item.crated.adj") + " " + Proxies.common.getDisplayName(contained); + else + return StringUtil.localize("item.crated.unknown"); + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + itemIcon = TextureManager.getInstance().registerTex(register, "crates/" + getUnlocalizedName().replace("item.crated", "").toLowerCase(Locale.ENGLISH)); + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemForestry.java b/forestry_common/core/forestry/core/items/ItemForestry.java new file mode 100755 index 000000000..869bf0eee --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemForestry.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemDye; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.CreativeTabForestry; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemForestry extends Item { + + private boolean isBonemeal = false; + + public ItemForestry() { + super(); + maxStackSize = 64; + setCreativeTab(CreativeTabForestry.tabForestry); + } + + public ItemForestry setBonemeal(boolean isBonemeal) { + this.isBonemeal = isBonemeal; + return this; + } + + @Override + public boolean onItemUse(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int par7, float par8, float par9, float par10) { + if(isBonemeal) { + if(ItemDye.applyBonemeal(itemstack, world, x, y, z, player)) { + if(Proxies.common.isSimulating(world)) + world.playAuxSFX(2005, x, y, z, 0); + + return true; + } + } + return super.onItemUse(itemstack, player, world, x, y, z, par7, par8, par9, par10); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + itemIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "")); + } +} diff --git a/forestry_common/core/forestry/core/items/ItemForestryBlock.java b/forestry_common/core/forestry/core/items/ItemForestryBlock.java new file mode 100755 index 000000000..115b01fa4 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemForestryBlock.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +import forestry.core.utils.StringUtil; + +public class ItemForestryBlock extends ItemBlock { + + + public ItemForestryBlock(Block block) { + super(block); + setMaxDamage(0); + setHasSubtypes(true); + } + + @Override + public int getMetadata(int i) { + return i; + } + + protected Block getBlock() { + return field_150939_a; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + + @Override + public String getUnlocalizedName(ItemStack itemstack) { + return getBlock().getUnlocalizedName() + "." + itemstack.getItemDamage(); + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemForestryFood.java b/forestry_common/core/forestry/core/items/ItemForestryFood.java new file mode 100755 index 000000000..158da86ee --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemForestryFood.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.CreativeTabForestry; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemForestryFood extends Item { + + private boolean isAlwaysEdible = false; + private boolean isDrink = false; + + private int healAmount = 0; + private final float saturationModifier; + + private int potionId; + private int potionDuration; + private int potionAmplifier; + private float potionEffectProbability; + + public ItemForestryFood(int heal) { + this(heal, 0.6f); + } + + public ItemForestryFood(int heal, float saturation) { + super(); + healAmount = heal; + saturationModifier = saturation; + setCreativeTab(CreativeTabForestry.tabForestry); + } + + @Override + public ItemStack onEaten(ItemStack itemstack, World world, EntityPlayer entityplayer) { + itemstack.stackSize--; + entityplayer.getFoodStats().addStats(healAmount, saturationModifier); + world.playSoundAtEntity(entityplayer, "random.burp", 0.5F, world.rand.nextFloat() * 0.1F + 0.9F); + if (!world.isRemote && potionId > 0 && world.rand.nextFloat() < potionEffectProbability) + entityplayer.addPotionEffect(new PotionEffect(potionId, potionDuration * 20, potionAmplifier)); + + return itemstack; + } + + @Override + public int getMaxItemUseDuration(ItemStack itemstack) { + return 32; + } + + @Override + public EnumAction getItemUseAction(ItemStack itemstack) { + if (isDrink) + return EnumAction.drink; + else + return EnumAction.eat; + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (entityplayer.canEat(isAlwaysEdible)) + entityplayer.setItemInUse(itemstack, getMaxItemUseDuration(itemstack)); + return itemstack; + } + + public ItemForestryFood setIsDrink() { + isDrink = true; + return this; + } + + public ItemForestryFood setPotionEffect(int i, int j, int k, float f) { + potionId = i; + potionDuration = j; + potionAmplifier = k; + potionEffectProbability = f; + return this; + } + + public ItemForestryFood setAlwaysEdible() { + isAlwaysEdible = true; + return this; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + itemIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "")); + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemForestryPickaxe.java b/forestry_common/core/forestry/core/items/ItemForestryPickaxe.java new file mode 100755 index 000000000..d59d0c857 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemForestryPickaxe.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; + +import forestry.core.config.ForestryBlock; + +public class ItemForestryPickaxe extends ItemForestryTool { + + private static Block blocksEffectiveAgainst[]; + + static { + blocksEffectiveAgainst = (new Block[] { Blocks.cobblestone, Blocks.stone, Blocks.sandstone, Blocks.mossy_cobblestone, Blocks.iron_ore, Blocks.iron_block, + Blocks.coal_ore, Blocks.gold_block, Blocks.brick_block, Blocks.nether_brick, Blocks.netherrack, Blocks.gold_ore, Blocks.diamond_ore, Blocks.diamond_block, + Blocks.ice, Blocks.netherrack, Blocks.lapis_ore, Blocks.lapis_block, ForestryBlock.resources, ForestryBlock.beehives, ForestryBlock.engine, + ForestryBlock.factoryTESR, ForestryBlock.factoryPlain }); + } + + public ItemForestryPickaxe(ItemStack remnants) { + super(blocksEffectiveAgainst, remnants); + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemForestryShovel.java b/forestry_common/core/forestry/core/items/ItemForestryShovel.java new file mode 100755 index 000000000..925028b22 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemForestryShovel.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; + +import forestry.core.config.ForestryBlock; + +public class ItemForestryShovel extends ItemForestryTool { + + private static Block blocksEffectiveAgainst[]; + + static { + blocksEffectiveAgainst = (new Block[] { Blocks.grass, Blocks.dirt, Blocks.sand, Blocks.gravel, Blocks.snow_layer, Blocks.snow, Blocks.clay, + Blocks.farmland, ForestryBlock.soil }); + } + + public ItemForestryShovel( ItemStack remnants) { + super(blocksEffectiveAgainst, remnants); + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemForestryTool.java b/forestry_common/core/forestry/core/items/ItemForestryTool.java new file mode 100755 index 000000000..c5a8cf264 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemForestryTool.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent; + +import forestry.core.proxy.Proxies; + +public class ItemForestryTool extends ItemForestry { + + private final ItemStack remnants; + private final float efficiencyOnProperMaterial; + private final Block[] blocksEffectiveAgainst; + + public ItemForestryTool(Block[] blocksEffectiveAgainst, ItemStack remnants) { + super(); + this.blocksEffectiveAgainst = blocksEffectiveAgainst; + this.maxStackSize = 1; + efficiencyOnProperMaterial = 6F; + setMaxDamage(200); + this.remnants = remnants; + } + + @Override + public float func_150893_a(ItemStack itemstack, Block block) { + for (int i = 0; i < blocksEffectiveAgainst.length; i++) + if (blocksEffectiveAgainst[i] == block) + return efficiencyOnProperMaterial; + return 1.0F; + } + + @Override + public float getDigSpeed(ItemStack itemstack, Block block, int md) { + if (ForgeHooks.isToolEffective(itemstack, block, md)) + return efficiencyOnProperMaterial; + return func_150893_a(itemstack, block); + } + + @SubscribeEvent + public void onDestroyCurrentItem(PlayerDestroyItemEvent event) { + if (event.original == null || event.original.getItem() != this) + return; + + if (Proxies.common.isSimulating(event.entityPlayer.worldObj)) { + EntityItem entity = new EntityItem(event.entityPlayer.worldObj, event.entityPlayer.posX, event.entityPlayer.posY, event.entityPlayer.posZ, + remnants.copy()); + event.entityPlayer.worldObj.spawnEntityInWorld(entity); + } + } + + @Override + public boolean onBlockDestroyed(ItemStack itemstack, World world, Block block, int j, int k, int l, EntityLivingBase entityliving) { + itemstack.damageItem(1, entityliving); + return true; + } + + /*@Override + public float getDamageVsEntity(Entity entity, ItemStack itemstack) { + return 1; + }*/ + + @Override + public boolean isFull3D() { + return true; + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemFruit.java b/forestry_common/core/forestry/core/items/ItemFruit.java new file mode 100755 index 000000000..4a3c0460c --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemFruit.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import java.util.List; +import java.util.Locale; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.oredict.OreDictionary; + +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemFruit extends ItemForestryFood { + + public static enum EnumFruit { + CHERRY("cropCherry"), WALNUT("cropWalnut"), CHESTNUT("cropChestnut"), LEMON("cropLemon"), PLUM("cropPlum"), DATES("cropDate"), PAPAYA("cropPapaya");//, COCONUT("cropCoconut"); + + final String oreDict; + + private EnumFruit(String oreDict) { + this.oreDict = oreDict; + } + + private static IIcon[] icons; + + public static void registerIcons(IIconRegister register) { + icons = new IIcon[values().length]; + for (int i = 0; i < values().length; i++) + icons[i] = TextureManager.getInstance().registerTex(register, "fruits/" + values()[i].toString().toLowerCase(Locale.ENGLISH)); + } + + public IIcon getIcon() { + return icons[ordinal()]; + } + } + + public ItemFruit() { + super(1, 0.2f); + setMaxDamage(0); + setHasSubtypes(true); + registerOreDictionary(); + } + + private void registerOreDictionary() { + for (EnumFruit def : EnumFruit.values()) + OreDictionary.registerOre(def.oreDict, new ItemStack(this, 1, def.ordinal())); + } + + @Override + public boolean isDamageable() { + return false; + } + + @Override + public boolean isRepairable() { + return false; + } + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + EnumFruit.registerIcons(register); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamage(int meta) { + return EnumFruit.values()[meta].getIcon(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + for (int i = 0; i < EnumFruit.values().length; i++) + itemList.add(new ItemStack(this, 1, i)); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (itemstack.getItemDamage() < 0 || itemstack.getItemDamage() >= EnumFruit.values().length) + return null; + + return StringUtil.localize("item.fruit." + EnumFruit.values()[itemstack.getItemDamage()].toString().toLowerCase(Locale.ENGLISH)); + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemInventoried.java b/forestry_common/core/forestry/core/items/ItemInventoried.java new file mode 100755 index 000000000..3b92b0b7a --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemInventoried.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; + +import forestry.core.gui.ContainerItemInventory; +import forestry.core.interfaces.IInventoriedItem; + +public abstract class ItemInventoried extends ItemForestry implements IInventoriedItem { + + public ItemInventoried() { + super(); + } + + @Override + public boolean onDroppedByPlayer(ItemStack itemstack, EntityPlayer player) { + if (itemstack != null && + player instanceof EntityPlayerMP && + player.openContainer instanceof ContainerItemInventory) + ((EntityPlayerMP) player).closeScreen(); + + return super.onDroppedByPlayer(itemstack, player); + } +} diff --git a/forestry_common/core/forestry/core/items/ItemLiquidContainer.java b/forestry_common/core/forestry/core/items/ItemLiquidContainer.java new file mode 100755 index 000000000..5e4b725a2 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemLiquidContainer.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import java.util.Locale; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.MovingObjectPosition.MovingObjectType; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidBlock; + +import forestry.core.CreativeTabForestry; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StringUtil; + +public class ItemLiquidContainer extends Item { + + public static enum EnumContainerType { + GLASS, JAR, CAN, CAPSULE, REFRACTORY + } + + private boolean isDrink = false; + private boolean isAlwaysEdible = false; + + private int healAmount = 0; + private float saturationModifier = 0.0f; + + private final EnumContainerType type; + private final int colour; + + public ItemLiquidContainer(EnumContainerType type, int colour) { + super(); + this.type = type; + this.colour = colour; + setCreativeTab(CreativeTabForestry.tabForestry); + setMaxStackSize(16); + } + + private int getMatchingSlot(EntityPlayer player, ItemStack stack) { + + for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++) { + ItemStack slotStack = player.inventory.getStackInSlot(slot); + + if (slotStack == null) + return slot; + + if (!slotStack.isItemEqual(stack)) + continue; + + int space = slotStack.getMaxStackSize() - slotStack.stackSize; + if (space >= stack.stackSize) + return slot; + } + + return -1; + } + + @Override + public ItemStack onEaten(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (!isDrink) + return itemstack; + + itemstack.stackSize--; + entityplayer.getFoodStats().addStats(this.getHealAmount(), this.getSaturationModifier()); + world.playSoundAtEntity(entityplayer, "random.burp", 0.5F, world.rand.nextFloat() * 0.1F + 0.9F); + /* + * if (!world.isRemote && potionId > 0 && world.rand.nextFloat() < potionEffectProbability) entityplayer.addPotionEffect(new PotionEffect(potionId, + * potionDuration * 20, potionAmplifier)); + */ + + return itemstack; + } + + @Override + public int getMaxItemUseDuration(ItemStack itemstack) { + if (isDrink) + return 32; + else + return super.getMaxItemUseDuration(itemstack); + } + + @Override + public EnumAction getItemUseAction(ItemStack itemstack) { + if (isDrink) + return EnumAction.drink; + else + return EnumAction.none; + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(world)) + return itemstack; + + // / DRINKS can be drunk + if (isDrink) { + if (entityplayer.canEat(isAlwaysEdible)) + entityplayer.setItemInUse(itemstack, getMaxItemUseDuration(itemstack)); + return itemstack; + } + + // / Otherwise check empty container + MovingObjectPosition movingobjectposition = this.getMovingObjectPositionFromPlayer(world, entityplayer, true); + if (movingobjectposition != null && movingobjectposition.typeOfHit == MovingObjectType.BLOCK) { + + int i = movingobjectposition.blockX; + int j = movingobjectposition.blockY; + int k = movingobjectposition.blockZ; + Block targetedBlock = world.getBlock(i, j, k); + //int targetedMeta = world.getBlockMetadata(i, j, k); + + if(!(targetedBlock instanceof IFluidBlock)) + return itemstack; + IFluidBlock fluidBlock = (IFluidBlock) targetedBlock; + FluidStack drainable = fluidBlock.drain(world, i, j, k, false); + if(drainable == null || drainable.amount <= 0) + return itemstack; + + // Check whether there is valid container for the liquid. + FluidContainerData container = LiquidHelper.getEmptyContainer(itemstack, drainable); + if (container == null) + return itemstack; + + // Search for a slot to stow a filled container in player's + // inventory + int slot = getMatchingSlot(entityplayer, container.filledContainer); + if (slot < 0) + return itemstack; + + if (entityplayer.inventory.getStackInSlot(slot) == null) + entityplayer.inventory.setInventorySlotContents(slot, container.filledContainer.copy()); + else + entityplayer.inventory.getStackInSlot(slot).stackSize++; + + // Remove consumed liquid block in world + world.setBlockToAir(i, j, k); + // Remove consumed empty container + itemstack.stackSize--; + + // Notify player that his inventory has changed. + Proxies.net.inventoryChangeNotify(entityplayer); + + return itemstack; + } + + return itemstack; + + } + + public int getHealAmount() { + return healAmount; + } + + public float getSaturationModifier() { + return saturationModifier; + } + + public ItemLiquidContainer setDrink(int healAmount, float saturationModifier) { + isDrink = true; + this.healAmount = healAmount; + this.saturationModifier = saturationModifier; + return this; + } + + /* + * public ItemLiquidContainer setPotionEffect(int i, int j, int k, float f) { potionId = i; potionDuration = j; potionAmplifier = k; potionEffectProbability + * = f; return this; } + */ + + public ItemLiquidContainer setAlwaysEdible() { + isAlwaysEdible = true; + return this; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + icons = new IIcon[2]; + icons[0] = TextureManager.getInstance().registerTex(register, "liquids/" + type.toString().toLowerCase(Locale.ENGLISH) + ".bottle"); + icons[1] = TextureManager.getInstance().registerTex(register, "liquids/" + type.toString().toLowerCase(Locale.ENGLISH) + ".contents"); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int i, int j) { + if (j > 0 && colour >= 0) + return icons[1]; + else + return icons[0]; + } + + // Return true to enable color overlay + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int j) { + if (j > 0 && colour >= 0) + return colour; + else + return 0xffffff; + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemLiquids.java b/forestry_common/core/forestry/core/items/ItemLiquids.java new file mode 100755 index 000000000..6e7060639 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemLiquids.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +public class ItemLiquids extends ItemForestry { + + public ItemLiquids() { + super(); + setCreativeTab(null); + } + + @Override + public boolean isDamageable() { + return false; + } + + @Override + public boolean isRepairable() { + return false; + } + + /* + * //@Override Client side only public String getItemStackDisplayName(ItemStack itemstack) { switch(itemstack.getItemDamage()) { case 0: return "Liquid Honey"; + * case 1: return "Liquid Mead"; default: return "Unknown Item"; } } + * + * //@Override Client side only public int getIconFromDamage(int damage) { switch(damage) { case 0: return 76; case 1: return 77; default: return 0; } } + * + * @Override public void addCreativeItems(ArrayList itemList) { //for(int i = 0; i < 2; i++) // itemList.add(new ItemStack(this, 1, i)); } + */ +} diff --git a/forestry_common/core/forestry/core/items/ItemMisc.java b/forestry_common/core/forestry/core/items/ItemMisc.java new file mode 100755 index 000000000..31c0a8501 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemMisc.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemMisc extends ItemForestry { + + String[] definition = new String[] { "pulsatingDust", "pulsatingMesh", "silkWisp", "wovenSilk", "dissipationCharge", "iceShard", "scentedPaneling" }; + + public ItemMisc() { + super(); + setMaxDamage(0); + setHasSubtypes(true); + } + + @Override + public boolean isDamageable() { + return false; + } + + @Override + public boolean isRepairable() { + return false; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (itemstack.getItemDamage() >= definition.length || itemstack.getItemDamage() < 0) + return StringUtil.localize("item.unknown"); + else + return StringUtil.localize("item." + definition[itemstack.getItemDamage()]); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + + icons = new IIcon[definition.length]; + for (int i = 0; i < definition.length; i++) + icons[i] = TextureManager.getInstance().registerTex(register, definition[i]); + + } + + @Override + public IIcon getIconFromDamage(int damage) { + if (damage >= definition.length || damage < 0) + return icons[0]; + else + return icons[damage]; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + for (int i = 0; i < 7; i++) + itemList.add(new ItemStack(this, 1, i)); + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemNBTTile.java b/forestry_common/core/forestry/core/items/ItemNBTTile.java new file mode 100755 index 000000000..df64fb5fa --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemNBTTile.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public class ItemNBTTile extends ItemForestryBlock { + + public ItemNBTTile(Block block) { + super(block); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List info, boolean par4) { + if (!itemstack.hasTagCompound()) + return; + + info.add("There are still some scribbles on this."); + } +} diff --git a/forestry_common/core/forestry/core/items/ItemOverlay.java b/forestry_common/core/forestry/core/items/ItemOverlay.java new file mode 100755 index 000000000..dbfd29c78 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemOverlay.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.config.Config; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemOverlay extends ItemForestry { + + public static class OverlayInfo { + + public String name; + public int primaryColor = 0; + public int secondaryColor = 0; + public boolean isSecret = false; + + public OverlayInfo(String name, int primaryColor, int secondaryColor) { + this.name = name; + this.primaryColor = primaryColor; + this.secondaryColor = secondaryColor; + } + + public OverlayInfo(String name, int primaryColor) { + this(name, primaryColor, 0); + } + + public OverlayInfo setIsSecret() { + isSecret = true; + return this; + } + } + + private final OverlayInfo[] overlays; + + public ItemOverlay(CreativeTabs tab, OverlayInfo... overlays) { + super(); + setMaxDamage(0); + setHasSubtypes(true); + setCreativeTab(tab); + + this.overlays = overlays; + } + + @Override + public boolean isDamageable() { + return false; + } + + @Override + public boolean isRepairable() { + return false; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + for (int i = 0; i < overlays.length; i++) + if (Config.isDebug || !overlays[i].isSecret) + itemList.add(new ItemStack(this, 1, i)); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon primaryIcon; + @SideOnly(Side.CLIENT) + private IIcon secondaryIcon; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + primaryIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".0"); + if(overlays[0].secondaryColor != 0) + secondaryIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".1"); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIconFromDamageForRenderPass(int i, int j) { + if (j > 0 && overlays[i].secondaryColor != 0) + return secondaryIcon; + else + return primaryIcon; + } + + @Override + public int getRenderPasses(int metadata) { + return overlays[metadata].secondaryColor != 0 ? 2 : 1; + } + + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (itemstack.getItemDamage() < 0 || itemstack.getItemDamage() >= overlays.length) + return null; + + return StringUtil.localize(getUnlocalizedName() + "." + overlays[itemstack.getItemDamage()].name); + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int j) { + + if (j == 0 || overlays[itemstack.getItemDamage()].secondaryColor == 0) + return overlays[itemstack.getItemDamage()].primaryColor; + else + return overlays[itemstack.getItemDamage()].secondaryColor; + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemPipette.java b/forestry_common/core/forestry/core/items/ItemPipette.java new file mode 100755 index 000000000..705b5aea6 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemPipette.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.tools.IToolPipette; + +import forestry.api.core.INBTTagable; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.render.TextureManager; + +public class ItemPipette extends ItemForestry implements IToolPipette { + + class PipetteContents implements INBTTagable { + + FluidStack contents; + + public PipetteContents(NBTTagCompound nbttagcompound) { + if (nbttagcompound != null) + readFromNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + contents = FluidStack.loadFluidStackFromNBT(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + if (contents != null) + contents.writeToNBT(nbttagcompound); + } + + public boolean isFull(int limit) { + if (contents == null) + return false; + + return contents.fluidID > 0 && contents.amount >= limit; + } + + public void addTooltip(List list) { + if (contents == null) + return; + + String descr = contents.getFluid().getLocalizedName(); + if (Config.isDebug) + descr += " (" + contents.amount + ")"; + + list.add(descr); + } + } + + public ItemPipette() { + super(); + setMaxStackSize(1); + setFull3D(); + } + + /** + * @return true if the item's stackTagCompound needs to be synchronized over SMP. + */ + @Override + public boolean getShareTag() { + return true; + } + + @Override + public boolean canPipette(ItemStack itemstack) { + PipetteContents contained = new PipetteContents(itemstack.getTagCompound()); + return !contained.isFull(1000); + } + + @Override + public int fill(ItemStack itemstack, FluidStack liquid, boolean doFill) { + PipetteContents contained = new PipetteContents(itemstack.getTagCompound()); + + int limit = getCapacity(itemstack); + int filled = 0; + + if (contained.contents == null) { + + if (liquid.amount > limit) + filled = limit; + else + filled = liquid.amount; + + contained.contents = new FluidStack(liquid.fluidID, filled); + filled = liquid.amount; + + } else { + + if (contained.contents.amount >= limit) + return 0; + if (!contained.contents.isFluidEqual(liquid)) + return 0; + + int space = limit - contained.contents.amount; + + if (liquid.amount > space) + filled = space; + else + filled = liquid.amount; + + contained.contents.amount += filled; + } + + if (doFill) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + contained.writeToNBT(nbttagcompound); + itemstack.setTagCompound(nbttagcompound); + itemstack.setItemDamage(1); + } + + return filled; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + PipetteContents contained = new PipetteContents(itemstack.getTagCompound()); + contained.addTooltip(list); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon primaryIcon; + @SideOnly(Side.CLIENT) + private IIcon secondaryIcon; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + primaryIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".0"); + secondaryIcon = TextureManager.getInstance().registerTex(register, getUnlocalizedName().replace("item.", "") + ".1"); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamage(int damage) { + + if (damage <= 0) + return primaryIcon; + else + return secondaryIcon; + } + + @Override + public FluidStack drain(ItemStack pipette, int maxDrain, boolean doDrain) { + PipetteContents contained = new PipetteContents(pipette.getTagCompound()); + if (contained.contents == null || contained.contents.fluidID <= 0) + return null; + + int drained = maxDrain; + if (contained.contents.amount < drained) + drained = contained.contents.amount; + + if (doDrain) { + contained.contents.amount -= drained; + + if (contained.contents.amount <= 0) { + pipette.setTagCompound(null); + pipette.setItemDamage(0); + } else { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + contained.writeToNBT(nbttagcompound); + pipette.setTagCompound(nbttagcompound); + } + } + + return new FluidStack(contained.contents.fluidID, drained); + } + + @Override + public int getCapacity(ItemStack pipette) { + return Defaults.BUCKET_VOLUME; + } +} diff --git a/forestry_common/core/forestry/core/items/ItemScoop.java b/forestry_common/core/forestry/core/items/ItemScoop.java new file mode 100755 index 000000000..bdf01eea7 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemScoop.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.ForgeHooks; + +import forestry.api.core.IToolScoop; +import forestry.api.core.Tabs; + +public class ItemScoop extends ItemForestry implements IToolScoop { + + private final float efficiencyOnProperMaterial; + + public ItemScoop() { + super(); + this.maxStackSize = 1; + efficiencyOnProperMaterial = 4.0F; + setMaxDamage(10); + setCreativeTab(Tabs.tabApiculture); + setMaxStackSize(1); + } + + @Override + public float func_150893_a(ItemStack itemstack, Block block) { + return 1.0F; + } + + @Override + public float getDigSpeed(ItemStack itemstack, Block block, int md) { + if (ForgeHooks.isToolEffective(itemstack, block, md)) + return efficiencyOnProperMaterial; + + return func_150893_a(itemstack, block); + } + + @Override + public boolean onBlockDestroyed(ItemStack itemstack, World world, Block block, int j, int k, int l, EntityLivingBase entityliving) { + itemstack.damageItem(1, entityliving); + return true; + } + + /*@Override + public float getDamageVsEntity(Entity entity, ItemStack itemstack) { + return 1; + }*/ + + @Override + public boolean isFull3D() { + return true; + } + +} diff --git a/forestry_common/core/forestry/core/items/ItemWrench.java b/forestry_common/core/forestry/core/items/ItemWrench.java new file mode 100755 index 000000000..ee5838195 --- /dev/null +++ b/forestry_common/core/forestry/core/items/ItemWrench.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.items; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.tools.IToolWrench; + +public class ItemWrench extends ItemForestry implements IToolWrench { + + public ItemWrench() { + super(); + } + + @Override + public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { + Block block = world.getBlock(x, y, z); + if (block.rotateBlock(world, x, y, z, ForgeDirection.getOrientation(side))) { + player.swingItem(); + return !world.isRemote; + } + return false; + } + + @Override + public boolean canWrench(EntityPlayer player, int x, int y, int z) { + return true; + } + + @Override + public void wrenchUsed(EntityPlayer player, int x, int y, int z) { + } + +} diff --git a/forestry_common/core/forestry/core/network/ClassMap.java b/forestry_common/core/forestry/core/network/ClassMap.java new file mode 100755 index 000000000..e0cc057db --- /dev/null +++ b/forestry_common/core/forestry/core/network/ClassMap.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.LinkedList; + +import forestry.core.gadgets.TileForestry; + +public class ClassMap { + + @SuppressWarnings("rawtypes") + public static HashMap classMappers = new HashMap(); + + private LinkedList intMember = new LinkedList(); + private LinkedList floatMember = new LinkedList(); + private LinkedList booleanMember = new LinkedList(); + private LinkedList stringMember = new LinkedList(); + private LinkedList enumMember = new LinkedList(); + private LinkedList objectMember = new LinkedList(); + + public int intSize; + public int floatSize; + public int stringSize; + + private Field field; + + /** + * Writes the actual data to the packet payload + * + * @param obj + * {@link TileForestry} to write to packet + * @param intPayload + * @param floatPayload + * @param stringPayload + * @param index + */ + @SuppressWarnings("rawtypes") + public void setData(Object obj, int[] intPayload, float[] floatPayload, String[] stringPayload, IndexInPayload index) throws IllegalAccessException { + for (Field member : intMember) { + intPayload[index.intIndex] = member.getInt(obj); + index.intIndex++; + } + for (Field member : floatMember) { + floatPayload[index.floatIndex] = member.getFloat(obj); + index.floatIndex++; + } + for (Field member : booleanMember) { + if (member.getBoolean(obj)) + floatPayload[index.intIndex] = 1; + else + floatPayload[index.intIndex] = 0; + index.intIndex++; + } + for (Field member : stringMember) { + stringPayload[index.stringIndex] = (String) member.get(obj); + index.stringIndex++; + } + for (Field member : enumMember) { + intPayload[index.intIndex] = ((Enum) member.get(obj)).ordinal(); + index.intIndex++; + } + + // Handle subobjects + for (ClassMap submap : objectMember) { + Object source = submap.field.get(obj); + + if (source == null) { + intPayload[index.intIndex] = 0; + index.intIndex++; + + index.intIndex += submap.intSize; + index.floatIndex += submap.floatSize; + index.stringIndex += submap.stringSize; + } else { + intPayload[index.intIndex] = 1; + index.intIndex++; + submap.setData(source, intPayload, floatPayload, stringPayload, index); + } + } + } + + /** + * Updates the given object with the data from the passed payload arrays + * + * @param obj + * @param intPayload + * @param floatPayload + * @param stringPayload + * @param index + * @throws IllegalAccessException + */ + @SuppressWarnings("rawtypes") + public void fromData(Object obj, int[] intPayload, float[] floatPayload, String[] stringPayload, IndexInPayload index) throws IllegalAccessException { + + for (Field member : intMember) { + member.setInt(obj, intPayload[index.intIndex]); + index.intIndex++; + } + + for (Field member : booleanMember) { + member.setBoolean(obj, intPayload[index.intIndex] == 1); + index.intIndex++; + } + + for (Field member : enumMember) { + member.set(obj, ((Class) member.getGenericType()).getEnumConstants()[intPayload[index.intIndex]]); + index.intIndex++; + } + + for (Field member : floatMember) { + member.setFloat(obj, floatPayload[index.floatIndex]); + index.floatIndex++; + } + for (Field member : stringMember) { + member.set(obj, stringPayload[index.stringIndex]); + index.stringIndex++; + } + + for (ClassMap map : objectMember) { + boolean isNull = intPayload[index.intIndex] == 0; + index.intIndex++; + + if (isNull) { + index.intIndex += map.intSize; + index.floatIndex += map.floatSize; + index.stringIndex += map.stringSize; + } else { + map.field.get(obj); + map.fromData(map.field.get(obj), intPayload, floatPayload, stringPayload, index); + } + } + } + + @SuppressWarnings("rawtypes") + public ClassMap(final Class targetClass) { + Field[] fields = targetClass.getFields(); + + try { + for (Field field : fields) { + // We only handle fields marked with EntityNetData + if (!isNetworkedMember(field)) + continue; + + Type type = field.getGenericType(); + + if (type instanceof Class && !((Class) type).isArray()) { + Class memberClass = (Class) type; + if (memberClass.equals(int.class)) { + intSize++; + intMember.add(field); + } else if (memberClass.equals(float.class)) { + floatSize++; + floatMember.add(field); + } else if (memberClass.equals(boolean.class)) { + intSize++; + booleanMember.add(field); + } else if (memberClass.equals(String.class)) { + stringSize++; + stringMember.add(field); + } else if (Enum.class.isAssignableFrom(memberClass)) { + intSize++; + enumMember.add(field); + } else { + // If we are none of the above we assume to be another + // mapable object + // Might not be true and fail! + ClassMap mapper = new ClassMap(memberClass); + mapper.field = field; + + objectMember.add(mapper); + intSize++; + + intSize += mapper.intSize; + floatSize += mapper.floatSize; + stringSize += mapper.stringSize; + } + } else if (type instanceof Class && ((Class) type).isArray()) + // We don't handle arrays currently. Throw exception + throw new RuntimeException("Tried to map class " + targetClass.toString() + " but it requested mapping of an array. Not handled!"); + } + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + private boolean isNetworkedMember(Field member) { + return member.getAnnotation(EntityNetData.class) != null; + } + +} diff --git a/forestry_common/core/forestry/core/network/EntityNetData.java b/forestry_common/core/forestry/core/network/EntityNetData.java new file mode 100755 index 000000000..0bc48e769 --- /dev/null +++ b/forestry_common/core/forestry/core/network/EntityNetData.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Simple annotation to mark a field for synchronization in SMP. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface EntityNetData { + // Needs to be set for arrays + int staticSize() default -1; +} diff --git a/forestry_common/core/forestry/core/network/ForestryPacket.java b/forestry_common/core/forestry/core/network/ForestryPacket.java new file mode 100755 index 000000000..1a5a9f0db --- /dev/null +++ b/forestry_common/core/forestry/core/network/ForestryPacket.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; + +import cpw.mods.fml.common.network.internal.FMLProxyPacket; +import cpw.mods.fml.common.registry.GameData; + +import io.netty.buffer.Unpooled; + +import forestry.core.proxy.Proxies; + +public class ForestryPacket { + + protected int id; + protected static String channel = "FOR"; + + public ForestryPacket() { + } + + public ForestryPacket(int id) { + this.id = id; + } + + public FMLProxyPacket getPacket() { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + + try { + data.writeByte(getID()); + writeData(data); + } catch (IOException e) { + e.printStackTrace(); + } + + return new FMLProxyPacket(Unpooled.wrappedBuffer(bytes.toByteArray()), channel); + } + + public int getID() { + return id; + } + + protected ItemStack readItemStack(DataInputStream data) throws IOException { + ItemStack itemstack = null; + String itemName = data.readUTF(); + + if (!itemName.isEmpty()) { + Item item = GameData.itemRegistry.getObject(itemName); + byte stackSize = data.readByte(); + short meta = data.readShort(); + itemstack = new ItemStack(item, stackSize, meta); + + if (item.isDamageable() || Proxies.common.needsTagCompoundSynched(item)) + itemstack.stackTagCompound = this.readNBTTagCompound(data); + } + + return itemstack; + } + + protected void writeItemStack(ItemStack itemstack, DataOutputStream data) throws IOException { + + if (itemstack == null) + data.writeUTF(""); + else { + data.writeUTF(GameData.itemRegistry.getNameForObject(itemstack.getItem())); + data.writeByte(itemstack.stackSize); + data.writeShort(itemstack.getItemDamage()); + + if (itemstack.getItem().isDamageable() || Proxies.common.needsTagCompoundSynched(itemstack.getItem())) + this.writeNBTTagCompound(itemstack.stackTagCompound, data); + } + } + + protected NBTTagCompound readNBTTagCompound(DataInputStream data) throws IOException { + + short length = data.readShort(); + + if (length < 0) + return null; + else { + byte[] compressed = new byte[length]; + data.readFully(compressed); + return CompressedStreamTools.decompress(compressed); + } + + } + + protected void writeNBTTagCompound(NBTTagCompound nbttagcompound, DataOutputStream data) throws IOException { + + if (nbttagcompound == null) + data.writeShort(-1); + else { + byte[] compressed = CompressedStreamTools.compress(nbttagcompound); + data.writeShort((short) compressed.length); + data.write(compressed); + } + + } + + public void writeData(DataOutputStream data) throws IOException { + } + + public void readData(DataInputStream data) throws IOException { + } + +} diff --git a/forestry_common/core/forestry/core/network/GuiId.java b/forestry_common/core/forestry/core/network/GuiId.java new file mode 100755 index 000000000..d3ce75b09 --- /dev/null +++ b/forestry_common/core/forestry/core/network/GuiId.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +public enum GuiId { + AlvearyGUI, + + AlvearySwarmerGUI, + + AlvearySieveGUI, + + AnalyzerGUI, + + ApiaristBackpackGUI, + + ApiaristChestGUI, + + ArboristChestGUI, + + ApiaryGUI, + + ArboretumGUI, + + BackpackGUI, + + BackpackT2GUI, + + BeealyzerGUI, + + BeehouseGUI, + + BottlerGUI, + + CatalogueGUI, + + CarpenterGUI, + + CentrifugeGUI, + + EngineBronzeGUI, + + EngineCopperGUI, + + EngineTinGUI, + + FabricatorGUI, + + FarmGUI, + + FermenterGUI, + + FlutterlyzerGUI, + + ForesterGUI, + + GeneratorGUI, + + HabitatLocatorGUI, + + HygroregulatorGUI, + + ImprinterGUI, + + InfuserGUI, + + LetterGUI, + + LepidopteristBackpackGUI, + + LepidopteristChestGUI, + + MailboxGUI, + + MoistenerGUI, + + MushroomFarmGUI, + + MultiFarmGUI, + + NaturalistBenchGUI, + + NetherFarmGUI, + + PeatBogGUI, + + PhilatelistGUI, + + PlantationGUI, + + PropolisPipeGUI, + + PumpkinFarmGUI, + + RaintankGUI, + + SolderingIronGUI, + + SqueezerGUI, + + StillGUI, + + TraderGUI, + + TraderNameGUI, + + TreealyzerGUI, + + WorktableGUI, + + Unknown +} diff --git a/forestry_common/core/forestry/core/network/ILocatedPacket.java b/forestry_common/core/forestry/core/network/ILocatedPacket.java new file mode 100755 index 000000000..234b8dda0 --- /dev/null +++ b/forestry_common/core/forestry/core/network/ILocatedPacket.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public interface ILocatedPacket { + TileEntity getTarget(World world); +} diff --git a/forestry_common/core/forestry/core/network/INetworkedEntity.java b/forestry_common/core/forestry/core/network/INetworkedEntity.java new file mode 100755 index 000000000..a9bc52d22 --- /dev/null +++ b/forestry_common/core/forestry/core/network/INetworkedEntity.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +public interface INetworkedEntity { + + public void sendNetworkUpdate(); + + public void fromPacket(ForestryPacket packet); + +} diff --git a/forestry_common/core/forestry/core/network/IndexInPayload.java b/forestry_common/core/forestry/core/network/IndexInPayload.java new file mode 100755 index 000000000..28d93de30 --- /dev/null +++ b/forestry_common/core/forestry/core/network/IndexInPayload.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +/** + * Keeps track of the indices to use when writing data to payload arrays. Internal use only. + */ +public class IndexInPayload { + public IndexInPayload(int intIndex, int floatIndex, int stringIndex) { + this.intIndex = intIndex; + this.floatIndex = floatIndex; + this.stringIndex = stringIndex; + } + + public int intIndex = 0; + public int floatIndex = 0; + public int stringIndex = 0; +} diff --git a/forestry_common/core/forestry/core/network/PacketCoordinates.java b/forestry_common/core/forestry/core/network/PacketCoordinates.java new file mode 100755 index 000000000..bf53f4466 --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketCoordinates.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; + +public class PacketCoordinates extends ForestryPacket implements ILocatedPacket { + + public int posX; + public int posY; + public int posZ; + + public PacketCoordinates() { + } + + public PacketCoordinates(int id, ChunkCoordinates coordinates) { + this(id, coordinates.posX, coordinates.posY, coordinates.posZ); + } + + public PacketCoordinates(int id, int posX, int posY, int posZ) { + super(id); + this.posX = posX; + this.posY = posY; + this.posZ = posZ; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + + data.writeInt(posX); + data.writeInt(posY); + data.writeInt(posZ); + + } + + @Override + public void readData(DataInputStream data) throws IOException { + + posX = data.readInt(); + posY = data.readInt(); + posZ = data.readInt(); + + } + + public ChunkCoordinates getCoordinates() { + return new ChunkCoordinates(posX, posY, posZ); + } + + @Override + public TileEntity getTarget(World world) { + return world.getTileEntity(posX, posY, posZ); + } + +} diff --git a/forestry_common/core/forestry/core/network/PacketFXSignal.java b/forestry_common/core/forestry/core/network/PacketFXSignal.java new file mode 100755 index 000000000..e9a4511bc --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketFXSignal.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.block.Block; + +import cpw.mods.fml.common.registry.GameData; + +import forestry.core.proxy.Proxies; + +public class PacketFXSignal extends ForestryPacket { + + public static enum VisualFXType { + NONE, BLOCK_DESTROY, SAPLING_PLACE + }; + + public static enum SoundFXType { + NONE(""), BLOCK_DESTROY(""), BLOCK_PLACE(""), LEAF("step.grass"), LOG("dig.wood"), DIRT("dig.gravel"); + + public final String soundFile; + public final float volume = 1.0f; + public final float pitch = 1.0f; + + private SoundFXType(String soundFile) { + this.soundFile = soundFile; + } + }; + + private VisualFXType visualFX; + private SoundFXType soundFX; + + private int xCoord; + private int yCoord; + private int zCoord; + private Block block; + private int meta; + + public PacketFXSignal() { + } + + public PacketFXSignal(VisualFXType type, int xCoord, int yCoord, int zCoord, Block block, int meta) { + this(type, SoundFXType.NONE, xCoord, yCoord, zCoord, block, meta); + } + + public PacketFXSignal(SoundFXType type, int xCoord, int yCoord, int zCoord, Block block, int meta) { + this(VisualFXType.NONE, type, xCoord, yCoord, zCoord, block, meta); + } + + public PacketFXSignal(VisualFXType visualFX, SoundFXType soundFX, int xCoord, int yCoord, int zCoord, Block block, int meta) { + super(PacketIds.FX_SIGNAL); + this.visualFX = visualFX; + this.soundFX = soundFX; + this.xCoord = xCoord; + this.yCoord = yCoord; + this.zCoord = zCoord; + this.block = block; + this.meta = meta; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + data.writeShort(visualFX.ordinal()); + data.writeShort(soundFX.ordinal()); + data.writeInt(xCoord); + data.writeInt(yCoord); + data.writeInt(zCoord); + data.writeUTF(GameData.blockRegistry.getNameForObject(block)); + data.writeInt(meta); + } + + @Override + public void readData(DataInputStream data) throws IOException { + this.visualFX = VisualFXType.values()[data.readShort()]; + this.soundFX = SoundFXType.values()[data.readShort()]; + this.xCoord = data.readInt(); + this.yCoord = data.readInt(); + this.zCoord = data.readInt(); + this.block = GameData.blockRegistry.getObject(data.readUTF()); + this.meta = data.readInt(); + } + + public void executeFX() { + if (visualFX != VisualFXType.NONE) + Proxies.common.addBlockDestroyEffects(Proxies.common.getRenderWorld(), xCoord, yCoord, zCoord, block, meta); + if (soundFX != SoundFXType.NONE) + if (soundFX == SoundFXType.BLOCK_DESTROY) + Proxies.common.playBlockBreakSoundFX(Proxies.common.getRenderWorld(), xCoord, yCoord, zCoord, block); + else if (soundFX == SoundFXType.BLOCK_PLACE) + Proxies.common.playBlockPlaceSoundFX(Proxies.common.getRenderWorld(), xCoord, yCoord, zCoord, block); + else + Proxies.common.playSoundFX(Proxies.common.getRenderWorld(), xCoord, yCoord, zCoord, soundFX.soundFile, soundFX.volume, soundFX.pitch); + } + +} diff --git a/forestry_common/core/forestry/core/network/PacketHandler.java b/forestry_common/core/forestry/core/network/PacketHandler.java new file mode 100755 index 000000000..9fbe1e9e7 --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketHandler.java @@ -0,0 +1,297 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.network.NetHandlerPlayServer; +import net.minecraft.tileentity.TileEntity; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.network.FMLEventChannel; +import cpw.mods.fml.common.network.FMLNetworkEvent.ClientCustomPacketEvent; +import cpw.mods.fml.common.network.FMLNetworkEvent.ServerCustomPacketEvent; +import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.network.internal.FMLProxyPacket; + +import net.minecraftforge.common.MinecraftForge; + +import forestry.api.core.ForestryEvent; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.circuits.ItemCircuitBoard; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.ContainerSocketed; +import forestry.core.gui.IGuiSelectable; +import forestry.core.interfaces.ISocketable; +import forestry.core.proxy.Proxies; +import forestry.plugins.PluginManager; + +public class PacketHandler { + public PacketHandler() { + channel = NetworkRegistry.INSTANCE.newEventDrivenChannel(ForestryPacket.channel); + channel.register(this); + } + + @SubscribeEvent + public void onPacket(ServerCustomPacketEvent event) { + byte[] data = new byte[event.packet.payload().readableBytes()]; + event.packet.payload().readBytes(data); + + onPacketData(data, ((NetHandlerPlayServer) event.handler).playerEntity); + } + + @SubscribeEvent + public void onPacket(ClientCustomPacketEvent event) { + byte[] data = new byte[event.packet.payload().readableBytes()]; + event.packet.payload().readBytes(data); + + onPacketData(data, null); + } + + public void onPacketData(byte[] bData, EntityPlayer player) { + DataInputStream data = new DataInputStream(new ByteArrayInputStream(bData)); + PacketUpdate packetU; + + try { + + int packetId = data.readByte(); + + switch (packetId) { + + case PacketIds.TILE_FORESTRY_UPDATE: + PacketTileUpdate packetT = new PacketTileUpdate(); + packetT.readData(data); + onTileUpdate(packetT); + break; + case PacketIds.TILE_UPDATE: + PacketUpdate packetUpdate = new PacketUpdate(); + packetUpdate.readData(data); + onTileUpdate(packetUpdate); + break; + case PacketIds.TILE_NBT: + PacketTileNBT packetN = new PacketTileNBT(); + packetN.readData(data); + onTileUpdate(packetN); + break; + case PacketIds.SOCKET_UPDATE: + PacketSocketUpdate packetS = new PacketSocketUpdate(); + packetS.readData(data); + onSocketUpdate(packetS); + break; + case PacketIds.IINVENTORY_STACK: + PacketInventoryStack packetQ = new PacketInventoryStack(); + packetQ.readData(data); + onInventoryStack(packetQ); + break; + case PacketIds.FX_SIGNAL: + PacketFXSignal packetF = new PacketFXSignal(); + packetF.readData(data); + packetF.executeFX(); + break; + + case PacketIds.PIPETTE_CLICK: + packetU = new PacketUpdate(); + packetU.readData(data); + onPipetteClick(packetU, player); + break; + case PacketIds.SOLDERING_IRON_CLICK: + packetU = new PacketUpdate(); + packetU.readData(data); + onSolderingIronClick(packetU, player); + break; + case PacketIds.CHIPSET_CLICK: + packetU = new PacketUpdate(); + packetU.readData(data); + onChipsetClick(packetU, player); + break; + case PacketIds.ACCESS_SWITCH: + PacketCoordinates packetC = new PacketCoordinates(); + packetC.readData(data); + onAccessSwitch(packetC, player); + break; + case PacketIds.GUI_SELECTION: + PacketUpdate packetI = new PacketUpdate(); + packetI.readData(data); + onGuiSelection(packetI); + break; + case PacketIds.GUI_SELECTION_CHANGE: + PacketUpdate packetZ = new PacketUpdate(); + packetZ.readData(data); + onGuiChange(player, packetZ); + break; + case PacketIds.GENOME_TRACKER_UPDATE: + PacketNBT packetTR = new PacketNBT(); + packetTR.readData(data); + onGenomeTrackerUpdate(packetTR); + break; + case PacketIds.TANK_UPDATE: + PacketTankUpdate packetAB = new PacketTankUpdate(); + packetAB.readData(data); + onTankUpdate(packetAB); + break; + default: + for (forestry.core.interfaces.IPacketHandler handler : PluginManager.packetHandlers) + handler.onPacketData(packetId, data, player); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + public void sendPacket(FMLProxyPacket packet) { + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { + channel.sendToServer(packet); + } else { + channel.sendToAll(packet); + } + } + + public void sendPacket(FMLProxyPacket packet, EntityPlayerMP player) { + channel.sendTo(packet, player); + } + + + private void onTankUpdate(PacketTankUpdate packetAB) { + assert FMLCommonHandler.instance().getEffectiveSide().isClient(); + + EntityPlayer player = Proxies.common.getPlayer(); + + if (player.openContainer instanceof ContainerForestry) { + ((ContainerForestry)player.openContainer).onTankUpdate(packetAB.nbttagcompound); + } + } + + private void onGenomeTrackerUpdate(PacketNBT packet) { + assert FMLCommonHandler.instance().getEffectiveSide().isClient(); + + EntityPlayer player = Proxies.common.getPlayer(); + IBreedingTracker tracker = null; + String type = packet.getTagCompound().getString("TYPE"); + + ISpeciesRoot root = AlleleManager.alleleRegistry.getSpeciesRoot(type); + if(root != null) + tracker = root.getBreedingTracker(Proxies.common.getRenderWorld(), player.getGameProfile().getId()); + if (tracker != null) { + tracker.decodeFromNBT(packet.getTagCompound()); + MinecraftForge.EVENT_BUS.post(new ForestryEvent.SyncedBreedingTracker(tracker, player)); + } + } + + private void onGuiChange(EntityPlayer player, PacketUpdate packet) { + assert FMLCommonHandler.instance().getEffectiveSide().isServer(); + + if (!(player.openContainer instanceof IGuiSelectable)) + return; + + ((IGuiSelectable) player.openContainer).handleSelectionChange(player, packet); + } + + private void onGuiSelection(PacketUpdate packet) { + assert FMLCommonHandler.instance().getEffectiveSide().isClient(); + + EntityPlayer player = Proxies.common.getPlayer(); + + Container container = player.openContainer; + if (!(container instanceof IGuiSelectable)) + return; + + ((IGuiSelectable) container).setSelection(packet); + + } + + private void onSocketUpdate(PacketSocketUpdate packet) { + assert FMLCommonHandler.instance().getEffectiveSide().isClient(); + + TileEntity tile = Proxies.common.getRenderWorld().getTileEntity(packet.posX, packet.posY, packet.posZ); + if (!(tile instanceof ISocketable)) + return; + + ISocketable socketable = (ISocketable) tile; + for (int i = 0; i < packet.itemstacks.length; i++) + socketable.setSocket(i, packet.itemstacks[i]); + } + + private void onTileUpdate(ForestryPacket packet) { + + TileEntity tile = ((ILocatedPacket) packet).getTarget(Proxies.common.getRenderWorld()); + if (tile instanceof INetworkedEntity) + ((INetworkedEntity) tile).fromPacket(packet); + + } + + private void onInventoryStack(PacketInventoryStack packet) { + + TileEntity tile = Proxies.common.getRenderWorld().getTileEntity(packet.posX, packet.posY, packet.posZ); + if (tile == null) + return; + + if (tile instanceof IInventory) { + ((IInventory) tile).setInventorySlotContents(packet.slotIndex, packet.itemstack); + } else if (tile instanceof TileForestry) { + IInventory inventory = ((TileForestry) tile).getInternalInventory(); + + if (inventory != null) inventory.setInventorySlotContents(packet.slotIndex, packet.itemstack); + } + } + + private void onChipsetClick(PacketUpdate packet, EntityPlayer player) { + assert FMLCommonHandler.instance().getEffectiveSide().isServer(); + + if (!(player.openContainer instanceof ContainerSocketed)) + return; + ItemStack itemstack = player.inventory.getItemStack(); + if (!(itemstack.getItem() instanceof ItemCircuitBoard)) + return; + + ((ContainerSocketed) player.openContainer).handleChipsetClick(packet.payload.intPayload[0], player, itemstack); + + } + + private void onSolderingIronClick(PacketUpdate packet, EntityPlayer player) { + assert FMLCommonHandler.instance().getEffectiveSide().isServer(); + + if (!(player.openContainer instanceof ContainerSocketed)) + return; + ItemStack itemstack = player.inventory.getItemStack(); + + ((ContainerSocketed) player.openContainer).handleSolderingIronClick(packet.payload.intPayload[0], player, itemstack); + } + + private void onAccessSwitch(PacketCoordinates packet, EntityPlayer playerEntity) { + assert FMLCommonHandler.instance().getEffectiveSide().isServer(); + + TileForestry tile = (TileForestry) playerEntity.worldObj.getTileEntity(packet.posX, packet.posY, packet.posZ); + if (tile == null) + return; + + tile.switchAccessRule(playerEntity); + } + + private void onPipetteClick(PacketUpdate packet, EntityPlayer player) { + assert FMLCommonHandler.instance().getEffectiveSide().isServer(); + + if (!(player.openContainer instanceof ContainerLiquidTanks)) + return; + + ((ContainerLiquidTanks) player.openContainer).handlePipetteClick(packet.payload.intPayload[0], player); + } + + private final FMLEventChannel channel; +} diff --git a/forestry_common/core/forestry/core/network/PacketIds.java b/forestry_common/core/forestry/core/network/PacketIds.java new file mode 100755 index 000000000..858ec0010 --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketIds.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +/** + * Valid ids: 0 - 127 + */ +public class PacketIds { + + public static final int TILE_FORESTRY_UPDATE = 0; + public static final int TILE_UPDATE = 1; + public static final int TILE_DESCRIPTION = 2; + public static final int IINVENTORY_STACK = 3; + public static final int FX_SIGNAL = 4; + public static final int TILE_NBT = 5; + + public static final int HABITAT_BIOME_POINTER = 20; + + public static final int GUI_SELECTION_CHANGE = 30; + public static final int IMPRINT_SELECTION_GET = 31; + public static final int GUI_SELECTION = 32; + + public static final int PIPETTE_CLICK = 40; + + public static final int ACCESS_SWITCH = 50; + + public static final int GENOME_TRACKER_UPDATE = 60; + public static final int GAME_TOKEN_SET = 61; + + public static final int CHIPSET_CLICK = 70; + public static final int SOLDERING_IRON_CLICK = 71; + public static final int SOCKET_UPDATE = 72; + + public static final int LETTER_RECIPIENT = 80; + public static final int LETTER_TEXT = 81; + public static final int TRADING_MONIKER_SET = 82; + public static final int TRADING_INFO = 83; + public static final int POBOX_INFO = 85; + public static final int POBOX_INFO_REQUEST = 86; + + public static final int LEAF_UPDATE = 90; + + public static final int TANK_UPDATE = 91; + + // Propolis pipe + public static final int PROP_SEND_FILTER_SET = 100; + public static final int PROP_REQUEST_FILTER_SET = 101; + public static final int PROP_SEND_FILTER_CHANGE_GENOME = 102; + public static final int PROP_SEND_FILTER_CHANGE_TYPE = 103; + + + + +} diff --git a/forestry_common/core/forestry/core/network/PacketInventoryStack.java b/forestry_common/core/forestry/core/network/PacketInventoryStack.java new file mode 100755 index 000000000..d52e78c56 --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketInventoryStack.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.item.ItemStack; + +public class PacketInventoryStack extends PacketCoordinates { + + public int slotIndex; + public ItemStack itemstack; + + public PacketInventoryStack() { + } + + public PacketInventoryStack(int id, int posX, int posY, int posZ, int slotIndex, ItemStack itemstack) { + super(id, posX, posY, posZ); + this.slotIndex = slotIndex; + this.itemstack = itemstack; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + super.writeData(data); + data.writeInt(slotIndex); + writeItemStack(itemstack, data); + } + + @Override + public void readData(DataInputStream data) throws IOException { + super.readData(data); + slotIndex = data.readInt(); + itemstack = readItemStack(data); + } + +} diff --git a/forestry_common/core/forestry/core/network/PacketNBT.java b/forestry_common/core/forestry/core/network/PacketNBT.java new file mode 100755 index 000000000..e25b59860 --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketNBT.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; + +public class PacketNBT extends ForestryPacket { + + protected NBTTagCompound nbttagcompound; + + public PacketNBT() { + } + + public PacketNBT(int id) { + super(id); + } + + public PacketNBT(int id, NBTTagCompound nbttagcompound) { + super(id); + this.nbttagcompound = nbttagcompound; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + byte[] compressed = CompressedStreamTools.compress(nbttagcompound); + data.writeShort(compressed.length); + data.write(compressed); + } + + @Override + public void readData(DataInputStream data) throws IOException { + short length = data.readShort(); + byte[] compressed = new byte[length]; + data.readFully(compressed); + this.nbttagcompound = CompressedStreamTools.decompress(compressed); + } + + public NBTTagCompound getTagCompound() { + return this.nbttagcompound; + } +} diff --git a/forestry_common/core/forestry/core/network/PacketPayload.java b/forestry_common/core/forestry/core/network/PacketPayload.java new file mode 100755 index 000000000..746c18f1d --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketPayload.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import forestry.core.utils.Utils; + +public class PacketPayload { + public int[] intPayload = new int[0]; + public short[] shortPayload = new short[0]; + public float[] floatPayload = new float[0]; + public String[] stringPayload = new String[0]; + + public PacketPayload() { + } + + public PacketPayload(int intSize, int floatSize, int stringSize) { + intPayload = new int[intSize]; + floatPayload = new float[floatSize]; + stringPayload = new String[stringSize]; + } + + public PacketPayload(int intSize, int shortSize) { + intPayload = new int[intSize]; + shortPayload = new short[shortSize]; + } + + public void append(PacketPayload other) { + if (other == null) + return; + + if (other.intPayload.length > 0) + this.intPayload = Utils.concat(this.intPayload, other.intPayload); + if (other.shortPayload.length > 0) + this.shortPayload = Utils.concat(this.shortPayload, other.shortPayload); + if (other.floatPayload.length > 0) + this.floatPayload = Utils.concat(this.floatPayload, other.floatPayload); + if (other.stringPayload.length > 0) + this.stringPayload = Utils.concat(this.stringPayload, other.stringPayload); + + } + + public void append(int[] other) { + if (other == null || other.length < 0) + return; + + this.intPayload = Utils.concat(this.intPayload, other); + } + + /* + * public void splitTail(IndexInPayload index) { PacketPayload payload = new PacketPayload(intPayload.length - index.intIndex, floatPayload.length - + * index.floatIndex, stringPayload.length - index.stringIndex); + * + * if (intPayload.length > 0) { System.arraycopy(intPayload, index.intIndex, payload.intPayload, 0, payload.intPayload.length); } if (floatPayload.length > + * 0) { System.arraycopy(floatPayload, index.floatIndex, payload.floatPayload, 0, payload.floatPayload.length); } if (stringPayload.length > 0) { + * System.arraycopy(stringPayload, index.stringIndex, payload.stringPayload, 0, payload.stringPayload.length); } } + */ + + public boolean isEmpty() { + return intPayload.length == 0 && shortPayload.length == 0 && floatPayload.length == 0 && stringPayload.length == 0; + } +} diff --git a/forestry_common/core/forestry/core/network/PacketSocketUpdate.java b/forestry_common/core/forestry/core/network/PacketSocketUpdate.java new file mode 100755 index 000000000..e2f3eeb8e --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketSocketUpdate.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.item.ItemStack; + +import forestry.core.interfaces.ISocketable; + +public class PacketSocketUpdate extends PacketCoordinates { + + public ItemStack[] itemstacks; + + public PacketSocketUpdate() { + } + + public PacketSocketUpdate(int id, int posX, int posY, int posZ, ISocketable tile) { + super(id, posX, posY, posZ); + + itemstacks = new ItemStack[tile.getSocketCount()]; + for (int i = 0; i < tile.getSocketCount(); i++) + itemstacks[i] = tile.getSocket(i); + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + super.writeData(data); + + data.writeShort(itemstacks.length); + for (int i = 0; i < itemstacks.length; i++) + writeItemStack(itemstacks[i], data); + } + + @Override + public void readData(DataInputStream data) throws IOException { + super.readData(data); + + int sockets = data.readShort(); + itemstacks = new ItemStack[sockets]; + for (int i = 0; i < sockets; i++) + itemstacks[i] = readItemStack(data); + } +} diff --git a/forestry_common/core/forestry/core/network/PacketTankUpdate.java b/forestry_common/core/forestry/core/network/PacketTankUpdate.java new file mode 100755 index 000000000..7a9809eaf --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketTankUpdate.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import net.minecraft.nbt.NBTTagCompound; + +import forestry.core.utils.ForestryTank; + +public class PacketTankUpdate extends PacketNBT { + + public PacketTankUpdate(int tankSlot, ForestryTank tank) { + super(PacketIds.TANK_UPDATE); + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setByte("tank", (byte) tankSlot); + nbt.setShort("capacity", (short) tank.getCapacity()); + tank.writeToNBT(nbt); + this.nbttagcompound = nbt; + } + + public PacketTankUpdate() { + } + +} diff --git a/forestry_common/core/forestry/core/network/PacketTileNBT.java b/forestry_common/core/forestry/core/network/PacketTileNBT.java new file mode 100755 index 000000000..3467c0abb --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketTileNBT.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class PacketTileNBT extends PacketNBT implements ILocatedPacket { + + private int posX; + private int posY; + private int posZ; + + public PacketTileNBT() { + } + + public PacketTileNBT(int id, TileEntity tile) { + super(id); + + posX = tile.xCoord; + posY = tile.yCoord; + posZ = tile.zCoord; + + this.nbttagcompound = new NBTTagCompound(); + tile.writeToNBT(nbttagcompound); + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + + data.writeInt(posX); + data.writeInt(posY); + data.writeInt(posZ); + + super.writeData(data); + } + + @Override + public void readData(DataInputStream data) throws IOException { + + posX = data.readInt(); + posY = data.readInt(); + posZ = data.readInt(); + + super.readData(data); + } + + @Override + public TileEntity getTarget(World world) { + return world.getTileEntity(posX, posY, posZ); + } + +} diff --git a/forestry_common/core/forestry/core/network/PacketTileUpdate.java b/forestry_common/core/forestry/core/network/PacketTileUpdate.java new file mode 100755 index 000000000..63795a6b5 --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketTileUpdate.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.core.EnumErrorCode; +import forestry.core.gadgets.TileForestry; +import forestry.core.utils.EnumAccess; + +public class PacketTileUpdate extends PacketUpdate { + + private ForgeDirection orientation = ForgeDirection.WEST; + private EnumErrorCode errorState = EnumErrorCode.OK; + + private boolean isOwnable = false; + private EnumAccess access = EnumAccess.SHARED; + private String owner = null; + + public PacketTileUpdate() { + } + + public PacketTileUpdate(TileForestry tile) { + super(PacketIds.TILE_FORESTRY_UPDATE, tile.getPacketPayload()); + + posX = tile.xCoord; + posY = tile.yCoord; + posZ = tile.zCoord; + + orientation = tile.getOrientation(); + errorState = tile.getErrorState(); + + isOwnable = tile.isOwnable(); + access = tile.getAccess(); + owner = tile.owner; + if (owner == null || owner.isEmpty()) + owner = ""; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + + data.writeInt(posX); + data.writeInt(posY); + data.writeInt(posZ); + + data.writeInt(this.orientation.ordinal()); + data.writeInt(this.errorState.ordinal()); + + if (isOwnable) { + data.writeInt(access.ordinal()); + data.writeUTF(owner); + } else + data.writeInt(-1); + + super.writeData(data); + } + + @Override + public void readData(DataInputStream data) throws IOException { + + posX = data.readInt(); + posY = data.readInt(); + posZ = data.readInt(); + + orientation = ForgeDirection.values()[data.readInt()]; + errorState = EnumErrorCode.values()[data.readInt()]; + + int ordinal = data.readInt(); + isOwnable = ordinal >= 0; + if (isOwnable) { + access = EnumAccess.values()[ordinal]; + owner = data.readUTF(); + } + + super.readData(data); + } + + public ForgeDirection getOrientation() { + return this.orientation; + } + + public EnumErrorCode getErrorState() { + return this.errorState; + } + + public EnumAccess getAccess() { + return this.access; + } + + public String getOwner() { + return this.owner; + } +} diff --git a/forestry_common/core/forestry/core/network/PacketUpdate.java b/forestry_common/core/forestry/core/network/PacketUpdate.java new file mode 100755 index 000000000..013efedf5 --- /dev/null +++ b/forestry_common/core/forestry/core/network/PacketUpdate.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class PacketUpdate extends PacketCoordinates { + + public PacketPayload payload; + + public PacketUpdate() { + } + + public PacketUpdate(int id) { + this(id, null); + } + + public PacketUpdate(int id, PacketPayload payload) { + this(id, 0, 0, 0, payload); + } + + public PacketUpdate(int id, int posX, int posY, int posZ, PacketPayload payload) { + super(id, posX, posY, posZ); + + this.payload = payload; + } + + public PacketUpdate(int id, int posX, int posY, int posZ, short val) { + super(id, posX, posY, posZ); + + this.payload = new PacketPayload(0, 1); + this.payload.shortPayload[0] = val; + } + + public PacketUpdate(int id, int posX, int posY, int posZ, int val) { + super(id, posX, posY, posZ); + + this.payload = new PacketPayload(1, 0); + this.payload.intPayload[0] = val; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + + super.writeData(data); + + // No payload means no data + if (payload == null) { + data.writeInt(0); + data.writeInt(0); + data.writeInt(0); + data.writeInt(0); + return; + } + + data.writeInt(payload.intPayload.length); + data.writeInt(payload.shortPayload.length); + data.writeInt(payload.floatPayload.length); + data.writeInt(payload.stringPayload.length); + + for (int intData : payload.intPayload) + data.writeInt(intData); + for (int shortData : payload.shortPayload) + data.writeShort(shortData); + for (float floatData : payload.floatPayload) + data.writeFloat(floatData); + for (String stringData : payload.stringPayload) + data.writeUTF(stringData); + + } + + @Override + public void readData(DataInputStream data) throws IOException { + + super.readData(data); + + payload = new PacketPayload(); + + payload.intPayload = new int[data.readInt()]; + payload.shortPayload = new short[data.readInt()]; + payload.floatPayload = new float[data.readInt()]; + payload.stringPayload = new String[data.readInt()]; + + for (int i = 0; i < payload.intPayload.length; i++) + payload.intPayload[i] = data.readInt(); + for (int i = 0; i < payload.shortPayload.length; i++) + payload.shortPayload[i] = data.readShort(); + for (int i = 0; i < payload.floatPayload.length; i++) + payload.floatPayload[i] = data.readFloat(); + for (int i = 0; i < payload.stringPayload.length; i++) + payload.stringPayload[i] = data.readUTF(); + + } + +} diff --git a/forestry_common/core/forestry/core/proxy/ClientProxyCommon.java b/forestry_common/core/forestry/core/proxy/ClientProxyCommon.java new file mode 100755 index 000000000..597bf3838 --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/ClientProxyCommon.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import java.io.File; + +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.particle.EntityExplodeFX; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +import org.lwjgl.input.Keyboard; + +import forestry.apiculture.render.TextureBiomefinder; +import forestry.core.ForestryClient; +import forestry.core.TickHandlerCoreClient; +import forestry.core.config.Config; +import forestry.core.render.SpriteSheet; + +public class ClientProxyCommon extends ProxyCommon { + + @Override + public void bindTexture(ResourceLocation location) { + getClientInstance().getTextureManager().bindTexture(location); + } + + @Override + public void bindTexture(SpriteSheet spriteSheet) { + bindTexture(spriteSheet.getLocation()); + } + + @Override + public void registerTickHandlers() { + super.registerTickHandlers(); + + new TickHandlerCoreClient(); + } + + @Override + public IResourceManager getSelectedTexturePack(Minecraft minecraft) { + return minecraft.getResourceManager(); + } + + @Override + public void setBiomefinderCoordinates(EntityPlayer player, ChunkCoordinates coordinates) { + if (isSimulating(player.worldObj)) + super.setBiomefinderCoordinates(player, coordinates); + else + TextureBiomefinder.getInstance().setTargetCoordinates(coordinates); + // TextureHabitatLocatorFX.instance.setTargetCoordinates(coordinates); + } + + @Override + public File getForestryRoot() { + return new File("."); + } + + @Override + public World getRenderWorld() { + return getClientInstance().theWorld; + } + + @Override + public int getBlockModelIdEngine() { + return ForestryClient.blockModelIdEngine; + } + + @Override + public int getByBlockModelId() { + return ForestryClient.byBlockModelId; + } + + @Override + public boolean isOp(EntityPlayer player) { + return true; + } + + @Override + public double getBlockReachDistance(EntityPlayer entityplayer) { + if (entityplayer instanceof EntityPlayerSP) + return getClientInstance().playerController.getBlockReachDistance(); + else + return 4f; + } + + @Override + public boolean isSimulating(World world) { + return !world.isRemote; + } + + @Override + public boolean isShiftDown() { + return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); + } + + @Override + public String getItemStackDisplayName(Item item) { + return item.getItemStackDisplayName(null); + } + + @Override + public String getItemStackDisplayName(ItemStack stack) { + return stack.getItem().getItemStackDisplayName(stack); + } + + @Override + public String getCurrentLanguage() { + return Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode(); + } + + @Override + public String getDisplayName(ItemStack itemstack) { + return itemstack.getItem().getItemStackDisplayName(itemstack); + } + + @Override + public void playSoundFX(World world, int x, int y, int z, Block block) { + if (Proxies.common.isSimulating(world)) + super.playSoundFX(world, x, y, z, block); + else + playSoundFX(world, x, y, z, block.stepSound.getStepResourcePath(), block.stepSound.getVolume(), block.stepSound.getPitch()); + } + + @Override + public void playBlockBreakSoundFX(World world, int x, int y, int z, Block block) { + if (Proxies.common.isSimulating(world)) + super.playSoundFX(world, x, y, z, block); + else + playSoundFX(world, x, y, z, block.stepSound.getBreakSound(), block.stepSound.getVolume() / 4, block.stepSound.getPitch()); + } + + @Override + public void playBlockPlaceSoundFX(World world, int x, int y, int z, Block block) { + if (Proxies.common.isSimulating(world)) + super.playSoundFX(world, x, y, z, block); + else + playSoundFX(world, x, y, z, block.stepSound.getStepResourcePath(), block.stepSound.getVolume() / 4, block.stepSound.getPitch()); + } + + @Override + public void playSoundFX(World world, int x, int y, int z, String sound, float volume, float pitch) { + world.playSound(x + 0.5, y + 0.5, z + 0.5, sound, volume, (1.0f + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.2f) * 0.7f, false); + } + + /** + * Renders a EntityBiodustFX on client. + * + * @param world + * @param d1 + * @param d2 + * @param d3 + * @param f1 + * @param f2 + * @param f3 + */ + // FIXME: This is causing crashes. + @Override + public void addEntityBiodustFX(World world, double d1, double d2, double d3, float f1, float f2, float f3) { + if (!Config.enableParticleFX) + return; + + // ModLoader.getMinecraftInstance().effectRenderer.addEffect(new EntityBiodustFX(world, d1, d2, d3, f1, f2, f3)); + } + + // FIXME: This is causing crashes. + @Override + public void addEntitySwarmFX(World world, double d1, double d2, double d3, float f1, float f2, float f3) { + if (!Config.enableParticleFX) + return; + + // ModLoader.getMinecraftInstance().effectRenderer.addEffect(new EntityHoneydustFX(world, d1, d2, d3, f1, f2, f3)); + } + + @Override + public void addEntityExplodeFX(World world, double d1, double d2, double d3, float f1, float f2, float f3) { + if (!Config.enableParticleFX) + return; + + getClientInstance().effectRenderer.addEffect(new EntityExplodeFX(world, d1, d2, d3, f1, f2, f3)); + } + + @Override + public void addBlockDestroyEffects(World world, int xCoord, int yCoord, int zCoord, Block block, int i) { + if (!isSimulating(world)) + getClientInstance().effectRenderer.addBlockDestroyEffects(xCoord, yCoord, zCoord, block, i); + else + super.addBlockDestroyEffects(world, xCoord, yCoord, zCoord, block, i); + } + + @Override + public void addBlockPlaceEffects(World world, int xCoord, int yCoord, int zCoord, Block block, int i) { + if (!isSimulating(world)) + playBlockPlaceSoundFX(world, xCoord, yCoord, zCoord, block); + else + super.addBlockPlaceEffects(world, xCoord, yCoord, zCoord, block, i); + } + + @Override + public EntityPlayer getPlayer() { + return Minecraft.getMinecraft().thePlayer; + } +} diff --git a/forestry_common/core/forestry/core/proxy/ClientProxyNetwork.java b/forestry_common/core/forestry/core/proxy/ClientProxyNetwork.java new file mode 100755 index 000000000..66d717f7c --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/ClientProxyNetwork.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import forestry.core.network.ForestryPacket; + +public class ClientProxyNetwork extends ProxyNetwork { + + @Override + public void sendToServer(ForestryPacket packet) { + Proxies.common.getClientInstance().getNetHandler().addToSendQueue(packet.getPacket()); + } +} diff --git a/forestry_common/core/forestry/core/proxy/ClientProxyRender.java b/forestry_common/core/forestry/core/proxy/ClientProxyRender.java new file mode 100755 index 000000000..a37e4bcd2 --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/ClientProxyRender.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.world.World; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.client.registry.RenderingRegistry; +import cpw.mods.fml.common.registry.VillagerRegistry; + +import forestry.core.config.Config; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.render.BlockRenderingHandler; +import forestry.core.render.EntitySnowFX; +import forestry.core.render.RenderEscritoire; +import forestry.core.render.RenderMachine; +import forestry.core.render.RenderMill; +import forestry.core.render.TextureManager; +import forestry.core.render.TileRendererIndex; +import forestry.core.utils.ForestryResource; + +public class ClientProxyRender extends ProxyRender { + + @Override + public int getNextAvailableRenderId() { + return RenderingRegistry.getNextAvailableRenderId(); + } + + @Override + public boolean fancyGraphicsEnabled() { + return Proxies.common.getClientInstance().gameSettings.fancyGraphics; + } + + @Override + public boolean hasRendering() { + return true; + } + + @Override + public void registerTESR(MachineDefinition definition) { + BlockRenderingHandler.byBlockRenderer.put(new TileRendererIndex(definition.block, definition.meta), definition.renderer); + ClientRegistry.bindTileEntitySpecialRenderer(definition.teClass, (TileEntitySpecialRenderer) definition.renderer); + } + + @Override + public IBlockRenderer getRenderDefaultMachine(String gfxBase) { + return new RenderMachine(gfxBase); + } + + @Override + public IBlockRenderer getRenderMill(String gfxBase) { + return new RenderMill(gfxBase); + } + + @Override + public IBlockRenderer getRenderMill(String gfxBase, byte charges) { + return new RenderMill(gfxBase, charges); + } + + @Override + public IBlockRenderer getRenderEscritoire() { + return new RenderEscritoire(); + } + + private boolean shouldSpawnParticle(World world, boolean canDisable) { + if (canDisable && !Config.enableParticleFX) + return false; + Minecraft mc = FMLClientHandler.instance().getClient(); + int particleSetting = mc.gameSettings.particleSetting; + if (!canDisable && particleSetting > 1) + particleSetting = 1; + if (particleSetting == 1 && world.rand.nextInt(3) == 0) + particleSetting = 2; + if (particleSetting > 1) + return false; + return true; + } + + @Override + public void addSnowFX(World world, double xCoord, double yCoord, double zCoord, int color, int areaX, int areaY, int areaZ) { + if (!shouldSpawnParticle(world, true)) + return; + + double spawnX = xCoord + world.rand.nextInt(areaX * 2) - areaX; + double spawnY = yCoord + world.rand.nextInt(areaY); + double spawnZ = zCoord + world.rand.nextInt(areaZ * 2) - areaZ; + + Proxies.common.getClientInstance().effectRenderer.addEffect(new EntitySnowFX(world, spawnX, spawnY, spawnZ, 0.0f, 0.0f, 0.0f)); + } + + @Override + public short registerItemTexUID(IIconRegister register, short uid, String ident) { + TextureManager.getInstance().registerTexUID(register, uid, ident); + return uid; + } + + @Override + public short registerTerrainTexUID(IIconRegister register, short uid, String ident) { + TextureManager.getInstance().registerTexUID(register, uid, ident); + return uid; + } + + @Override + public void registerVillagerSkin(int villagerId, String texturePath) { + VillagerRegistry.instance().registerVillagerSkin(villagerId, new ForestryResource(texturePath)); + } +} diff --git a/forestry_common/core/forestry/core/proxy/Proxies.java b/forestry_common/core/forestry/core/proxy/Proxies.java new file mode 100755 index 000000000..52e80d72b --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/Proxies.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import cpw.mods.fml.common.SidedProxy; + +public class Proxies { + @SidedProxy(clientSide = "forestry.core.proxy.ClientProxyCommon", serverSide = "forestry.core.proxy.ProxyCommon") + public static ProxyCommon common; + @SidedProxy(clientSide = "forestry.core.proxy.ClientProxyNetwork", serverSide = "forestry.core.proxy.ProxyNetwork") + public static ProxyNetwork net; + @SidedProxy(clientSide = "forestry.core.proxy.ClientProxyRender", serverSide = "forestry.core.proxy.ProxyRender") + public static ProxyRender render; + + public static ProxyLog log = new ProxyLog(); +} diff --git a/forestry_common/core/forestry/core/proxy/ProxyCommon.java b/forestry_common/core/forestry/core/proxy/ProxyCommon.java new file mode 100755 index 000000000..206bf506e --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/ProxyCommon.java @@ -0,0 +1,259 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import java.io.File; + +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.potion.Potion; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.registry.GameRegistry; + +import net.minecraftforge.oredict.ShapedOreRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; + +import forestry.Forestry; +import forestry.core.TickHandlerCoreServer; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.network.PacketCoordinates; +import forestry.core.network.PacketFXSignal; +import forestry.core.network.PacketIds; +import forestry.core.render.SpriteSheet; + +public class ProxyCommon { + + public String getMinecraftVersion() { + return Loader.instance().getMinecraftModContainer().getVersion(); + } + + public void registerTickHandlers() { + new TickHandlerCoreServer(); + } + + public void registerBlock(Block block, Class itemClass) { + GameRegistry.registerBlock(block, itemClass, block.getUnlocalizedName()); + } + + public void registerItem(Item item) { + GameRegistry.registerItem(item, item.getUnlocalizedName().replace("item.", "")); + } + + /** + * As addRecipe, except that the recipe is injected into the front of the + * crafting manager to avoid certain generic collisions. Notably, all + * Forestry wood crafting into oak stairs & slabs. + */ + @SuppressWarnings("unchecked") + public void addPriorityRecipe(ItemStack itemstack, Object... obj) { + cleanRecipe(obj); + CraftingManager.getInstance().getRecipeList().add(0, new ShapedOreRecipe(itemstack, obj)); + } + + /** + * As addShapelessRecipe, except that the recipe is injected into the front + * of the crafting manager to avoid certain generic collisions. Notably, all + * Forestry wood crafting into oak stairs & slabs. + */ + @SuppressWarnings("unchecked") + public void addPriorityShapelessRecipe(ItemStack itemstack, Object... obj) { + cleanRecipe(obj); + CraftingManager.getInstance().getRecipeList().add(0, new ShapelessOreRecipe(itemstack, obj)); + } + + @SuppressWarnings("unchecked") + public void addRecipe(ItemStack itemstack, Object... obj) { + cleanRecipe(obj); + CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(itemstack, obj)); + } + + @SuppressWarnings("unchecked") + public void addShapelessRecipe(ItemStack itemstack, Object... obj) { + cleanRecipe(obj); + CraftingManager.getInstance().getRecipeList().add(new ShapelessOreRecipe(itemstack, obj)); + } + + private void cleanRecipe(Object... obj) { + for (int i = 0; i < obj.length; i++) { + if (obj[i] instanceof ForestryItem) { + obj[i] = ((ForestryItem) obj[i]).item(); + } + } + } + + public void addSmelting(ItemStack res, ItemStack prod) { + GameRegistry.addSmelting(res.getItem(), prod, 0.0f); // TODO: use full stack as arg? + } + + public void dropItemPlayer(EntityPlayer player, ItemStack stack) { + player.dropPlayerItemWithRandomChoice(stack, true); + } + + public void setBiomefinderCoordinates(EntityPlayer player, ChunkCoordinates coordinates) { + if (coordinates != null) + Forestry.packetHandler.sendPacket(new PacketCoordinates(PacketIds.HABITAT_BIOME_POINTER, coordinates).getPacket(), (EntityPlayerMP) player); + } + + public void removePotionEffect(EntityPlayer player, Potion effect) { + player.clearActivePotions(); + } + + public String getCurrentLanguage() { + return null; + } + + public String getItemStackDisplayName(Item item) { + return null; + } + + public String getDisplayName(ItemStack itemstack) { + return null; + } + + public File getForestryRoot() { + return new File("./"); + } + + public int getByBlockModelId() { + return 0; + } + + public boolean isOp(EntityPlayer player) { + MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); + return server.getConfigurationManager().isPlayerOpped(player.getGameProfile().getId()); + } + + public double getBlockReachDistance(EntityPlayer entityplayer) { + return 4f; + } + + public boolean isSimulating(World world) { + return true; + } + + public boolean isShiftDown() { + return false; + } + + public boolean isItemStackTagEqual(ItemStack stack1, ItemStack stack2) { + return ItemStack.areItemStackTagsEqual(stack1, stack2); + } + + public String getItemStackDisplayName(ItemStack stack) { + return null; + } + + public boolean setBlockWithNotify(World world, int x, int y, int z, Block block) { + return world.setBlock(x, y, z, block, 0, Defaults.FLAG_BLOCK_SYNCH); + } + + public void playSoundFX(World world, int x, int y, int z, Block block) { + Proxies.net.sendNetworkPacket(new PacketFXSignal(PacketFXSignal.SoundFXType.LEAF, x, y, z, block, 0), x, y, z); + } + + public void playSoundFX(World world, int x, int y, int z, String sound, float volume, float pitch) { + } + + public void addEntityBiodustFX(World world, double d1, double d2, double d3, float f1, float f2, float f3) { + } + + public void addEntitySwarmFX(World world, double d1, double d2, double d3, float f1, float f2, float f3) { + } + + public void addEntityExplodeFX(World world, double d1, double d2, double d3, float f1, float f2, float f3) { + } + + public boolean needsTagCompoundSynched(Item item) { + return item.getShareTag(); + } + + public void addBlockDestroyEffects(World world, int xCoord, int yCoord, int zCoord, Block block, int i) { + sendFXSignal(PacketFXSignal.VisualFXType.BLOCK_DESTROY, PacketFXSignal.SoundFXType.BLOCK_DESTROY, world, xCoord, yCoord, zCoord, block, i); + } + + public void addBlockPlaceEffects(World world, int xCoord, int yCoord, int zCoord, Block block, int i) { + sendFXSignal(PacketFXSignal.VisualFXType.NONE, PacketFXSignal.SoundFXType.BLOCK_PLACE, world, xCoord, yCoord, zCoord, block, i); + } + + public void playBlockBreakSoundFX(World world, int x, int y, int z, Block block) { + } + + public void playBlockPlaceSoundFX(World world, int x, int y, int z, Block block) { + } + + public void sendFXSignal(PacketFXSignal.VisualFXType visualFX, PacketFXSignal.SoundFXType soundFX, World world, int xCoord, int yCoord, int zCoord, + Block block, int i) { + if (Proxies.common.isSimulating(world)) + Proxies.net.sendNetworkPacket(new PacketFXSignal(visualFX, soundFX, xCoord, yCoord, zCoord, block, i), xCoord, yCoord, zCoord); + } + + public IResourceManager getSelectedTexturePack(Minecraft minecraft) { + return null; + } + + public World getRenderWorld() { + return null; + } + + public Minecraft getClientInstance() { + return FMLClientHandler.instance().getClient(); + } + + public int getBlockModelIdEngine() { + return 0; + } + + public void closeGUI(EntityPlayer player) { + ((EntityPlayerMP) player).closeScreen(); + } + + /* DEPENDENCY HANDLING */ + public boolean isModLoaded(String modname) { + return Loader.isModLoaded(modname); + } + + public Object instantiateIfModLoaded(String modname, String className) { + + if (isModLoaded(modname)) + try { + Class clas = Class.forName(className, true, Loader.instance().getModClassLoader()); + return clas.newInstance(); + } catch (Exception ex) { + Proxies.log.severe("Failed to load " + className + " even though mod " + modname + " was available."); + return null; + } + else + return null; + + } + + public void bindTexture(ResourceLocation location) { + } + + public void bindTexture(SpriteSheet spriteSheet) { + } + + public EntityPlayer getPlayer() { + return null; + } +} diff --git a/forestry_common/core/forestry/core/proxy/ProxyLog.java b/forestry_common/core/forestry/core/proxy/ProxyLog.java new file mode 100755 index 000000000..509e5e960 --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/ProxyLog.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import forestry.core.config.Defaults; + +public class ProxyLog { + + /* LOGGING */ + private static Logger forestryLogger; + + private void initLogger() { + forestryLogger = LogManager.getLogger(Defaults.MOD); + } + + /* FINEST */ + public void finest(String message) { + log(Level.TRACE, message); + } + + public void finest(String message, Object param) { + log(Level.TRACE, message, param); + } + + public void finest(String message, Object... params) { + log(Level.TRACE, message, params); + } + + /* FINER */ + public void finer(String message) { + log(Level.TRACE, message); + } + + public void finer(String message, Object param) { + log(Level.TRACE, message, param); + } + + public void finer(String message, Object... params) { + log(Level.TRACE, message, params); + } + + /* FINE */ + public void fine(String message) { + log(Level.DEBUG, message); + } + + public void fine(String message, Object param) { + log(Level.DEBUG, message, param); + } + + public void fine(String message, Object... params) { + log(Level.DEBUG, message, params); + } + + /* INFO */ + public void info(String message) { + log(Level.INFO, message); + } + + public void info(String message, Object param) { + log(Level.INFO, message, param); + } + + public void info(String message, Object... params) { + log(Level.INFO, message, params); + } + + /* WARNING */ + public void warning(String message) { + log(Level.WARN, message); + } + + public void warning(String message, Object param) { + log(Level.WARN, message, param); + } + + public void warning(String message, Object... params) { + log(Level.WARN, message, params); + } + + /* SEVERE */ + public void severe(String message) { + log(Level.FATAL, message); + } + + public void severe(String message, Object param) { + log(Level.FATAL, message, param); + } + + public void severe(String message, Object... params) { + log(Level.FATAL, message, params); + } + + /* GENERIC */ + public void log(Level logLevel, String message) { + if (forestryLogger == null) + initLogger(); + + forestryLogger.log(logLevel, message); + } + + public void log(Level logLevel, String message, Object... params) { + log(logLevel, String.format(message, params)); + } + + public void log(Level logLevel, String message, Object param) { + log(logLevel, String.format(message, param)); + } + +} diff --git a/forestry_common/core/forestry/core/proxy/ProxyNetwork.java b/forestry_common/core/forestry/core/proxy/ProxyNetwork.java new file mode 100755 index 000000000..189914973 --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/ProxyNetwork.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.world.World; + +import net.minecraftforge.common.DimensionManager; + +import forestry.Forestry; +import forestry.core.config.Defaults; +import forestry.core.network.ForestryPacket; + +public class ProxyNetwork { + + public void sendNetworkPacket(ForestryPacket packet, int x, int y, int z) { + if (packet == null) + return; + + World[] worlds = DimensionManager.getWorlds(); + for (int i = 0; i < worlds.length; i++) + for (int j = 0; j < worlds[i].playerEntities.size(); j++) { + EntityPlayerMP player = (EntityPlayerMP) worlds[i].playerEntities.get(j); + + if (Math.abs(player.posX - x) <= Defaults.NET_MAX_UPDATE_DISTANCE && Math.abs(player.posY - y) <= Defaults.NET_MAX_UPDATE_DISTANCE + && Math.abs(player.posZ - z) <= Defaults.NET_MAX_UPDATE_DISTANCE) + Forestry.packetHandler.sendPacket(packet.getPacket(), player); + } + } + + public void sendToPlayer(ForestryPacket packet, EntityPlayer entityplayer) { + if (!(entityplayer instanceof EntityPlayerMP)) + return; + + EntityPlayerMP player = (EntityPlayerMP) entityplayer; + Forestry.packetHandler.sendPacket(packet.getPacket(), player); + } + + public void sendToServer(ForestryPacket packet) { + } + + public void inventoryChangeNotify(EntityPlayer player) { + if (player instanceof EntityPlayerMP) + ((EntityPlayerMP) player).sendContainerToPlayer(player.inventoryContainer); + } +} diff --git a/forestry_common/core/forestry/core/proxy/ProxyRender.java b/forestry_common/core/forestry/core/proxy/ProxyRender.java new file mode 100755 index 000000000..5abd13d8b --- /dev/null +++ b/forestry_common/core/forestry/core/proxy/ProxyRender.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.proxy; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.world.World; + +import forestry.core.gadgets.MachineDefinition; +import forestry.core.interfaces.IBlockRenderer; + +public class ProxyRender { + + public int getNextAvailableRenderId() { + return 0; + } + + public boolean fancyGraphicsEnabled() { + return false; + } + + public boolean hasRendering() { + return false; + } + + public void registerTESR(MachineDefinition definition) { + } + + public IBlockRenderer getRenderDefaultMachine(String gfxBase) { + return null; + } + + public IBlockRenderer getRenderMill(String gfxBase) { + return null; + } + + public IBlockRenderer getRenderMill(String gfxBase, byte charges) { + return null; + } + + public IBlockRenderer getRenderEscritoire() { + return null; + } + + public void addSnowFX(World world, double xCoord, double yCoord, double zCoord, int color, int areaX, int areaY, int areaZ) { + } + + public short registerItemTexUID(IIconRegister register, short uid, String ident) { + return uid; + } + + public short registerTerrainTexUID(IIconRegister register, short uid, String ident) { + return uid; + } + + public void registerVillagerSkin(int villagerId, String texturePath) { + } +} diff --git a/forestry_common/core/forestry/core/render/BlockRenderingHandler.java b/forestry_common/core/forestry/core/render/BlockRenderingHandler.java new file mode 100755 index 000000000..c78761ab6 --- /dev/null +++ b/forestry_common/core/forestry/core/render/BlockRenderingHandler.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import java.util.HashMap; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.world.IBlockAccess; + +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; + +import forestry.core.ForestryClient; +import forestry.core.interfaces.IBlockRenderer; + +public class BlockRenderingHandler implements ISimpleBlockRenderingHandler { + + public static HashMap byBlockRenderer = new HashMap(); + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + + if (block.getRenderType() == ForestryClient.byBlockModelId) { + TileRendererIndex index = new TileRendererIndex(block, metadata); + if (byBlockRenderer.containsKey(index)) + byBlockRenderer.get(index).inventoryRender(-0.5, -0.5, -0.5, 0, 0); + } + + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + return true; + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + return true; + } + + @Override + public int getRenderId() { + return ForestryClient.byBlockModelId; + } + +} diff --git a/forestry_common/core/forestry/core/render/EntityBiodustFX.java b/forestry_common/core/forestry/core/render/EntityBiodustFX.java new file mode 100755 index 000000000..032499f4a --- /dev/null +++ b/forestry_common/core/forestry/core/render/EntityBiodustFX.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.particle.EntityReddustFX; +import net.minecraft.world.World; + +public class EntityBiodustFX extends EntityReddustFX { + + public EntityBiodustFX(World world, double d, double d1, double d2, float f, float f1, float f2) { + this(world, d, d1, d2, 1.0F, f, f1, f2); + } + + public EntityBiodustFX(World world, double d, double d1, double d2, float f, float f1, float f2, float f3) { + super(world, d, d1, d2, f, f1, f2, f3); + // float f4 = (float)Math.random() * 0.4F + 0.6F; + // particleRed = ((float)(Math.random() * 0.20000000298023224D) + 0.8F) + // * f1 * f4; + // particleGreen = ((float)(Math.random() * 0.20000000298023224D) + + // 0.8F) * f2 * f4; + // particleBlue = ((float)(Math.random() * 0.20000000298023224D) + 0.8F) + // * f3 * f4; + particleRed = 0F; + particleGreen = 1.0F; + particleBlue = 0F; + } + +} diff --git a/forestry_common/core/forestry/core/render/EntityHoneydustFX.java b/forestry_common/core/forestry/core/render/EntityHoneydustFX.java new file mode 100755 index 000000000..510883d9a --- /dev/null +++ b/forestry_common/core/forestry/core/render/EntityHoneydustFX.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.particle.EntityReddustFX; +import net.minecraft.world.World; + +public class EntityHoneydustFX extends EntityReddustFX { + + public EntityHoneydustFX(World world, double d, double d1, double d2, float f, float f1, float f2) { + this(world, d, d1, d2, 1.0F, f, f1, f2); + } + + public EntityHoneydustFX(World world, double d, double d1, double d2, float f, float f1, float f2, float f3) { + super(world, d, d1, d2, f, f1, f2, f3); + // float f4 = (float)Math.random() * 0.4F + 0.6F; + // particleRed = ((float)(Math.random() * 0.20000000298023224D) + 0.95F) + // * f1 * f4; + // particleGreen = ((float)(Math.random() * 0.20000000298023224D) + + // 0.75F) * f2 * f4; + // particleBlue = ((float)(Math.random() * 0.20000000298023224D) + 0.1F) + // * f3 * f4; + particleRed = 0.9F; + particleGreen = 0.75F; + particleBlue = 0F; + } + +} diff --git a/forestry_common/core/forestry/core/render/EntitySnowFX.java b/forestry_common/core/forestry/core/render/EntitySnowFX.java new file mode 100755 index 000000000..1d7c21acf --- /dev/null +++ b/forestry_common/core/forestry/core/render/EntitySnowFX.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import java.util.Random; + +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +public class EntitySnowFX extends EntityFX { + + public static IIcon icons[]; + private Random spreadRand = new Random(); + + public EntitySnowFX(World world, double x, double y, double z, float motionScaleX, float motionScaleY, float motionScaleZ) { + super(world, x, y, z, 0.0D, 0.0D, 0.0D); + + this.setParticleIcon(icons[rand.nextInt(icons.length)]); + this.particleScale *= 0.5F; + this.particleMaxAge = (int) (40.0D / (Math.random() * 0.8D + 0.2D)); + this.noClip = true; + + this.motionX *= 0.01D; + this.motionY *= -0.4D; + this.motionZ *= 0.01D; + } + + @Override + public int getFXLayer() { + return 2; + } + + @Override + public void renderParticle(Tessellator tess, float timeStep, float rotationX, float rotationXZ, float rotationZ, float rotationYZ, float rotationXY) { + double x = (this.prevPosX + (this.posX - this.prevPosX) * timeStep - interpPosX); + double y = (this.prevPosY + (this.posY - this.prevPosY) * timeStep - interpPosY); + double z = (this.prevPosZ + (this.posZ - this.prevPosZ) * timeStep - interpPosZ); + + float minU = this.particleTextureIndexX / 16.0F; + float maxU = minU + 0.0624375F; + float minV = this.particleTextureIndexY / 16.0F; + float maxV = minV + 0.0624375F; + float scale = 0.1F * this.particleScale; + + if (this.particleIcon != null) { + minU = this.particleIcon.getMinU(); + maxU = this.particleIcon.getMaxU(); + minV = this.particleIcon.getMinV(); + maxV = this.particleIcon.getMaxV(); + } + + float brightness = 1.0F; + tess.setColorRGBA_F(this.particleRed * brightness, this.particleGreen * brightness, this.particleBlue * brightness, this.particleAlpha); + + spreadRand.setSeed(701); + + for (int i = 0; i < 5; i++) { + renderParticle(tess, x + spreadRand.nextGaussian() * 8, y, z + spreadRand.nextGaussian() * 8, rotationX, rotationXZ, rotationZ, rotationYZ, rotationXY, minU, maxU, minV, maxV, scale); + } + + } + + private void renderParticle(Tessellator tess, double x, double y, double z, float rotationX, float rotationXZ, float rotationZ, float rotationYZ, float rotationXY, + float minU, float maxU, float minV, float maxV, float scale) { + tess.addVertexWithUV((x - rotationX * scale - rotationYZ * scale), (y - rotationXZ * scale), (z - rotationZ * scale - rotationXY * scale), maxU, maxV); + tess.addVertexWithUV((x - rotationX * scale + rotationYZ * scale), (y + rotationXZ * scale), (z - rotationZ * scale + rotationXY * scale), maxU, minV); + tess.addVertexWithUV((x + rotationX * scale + rotationYZ * scale), (y + rotationXZ * scale), (z + rotationZ * scale + rotationXY * scale), minU, minV); + tess.addVertexWithUV((x + rotationX * scale - rotationYZ * scale), (y - rotationXZ * scale), (z + rotationZ * scale - rotationXY * scale), minU, maxV); + } +} diff --git a/forestry_common/core/forestry/core/render/ModelEscritoire.java b/forestry_common/core/forestry/core/render/ModelEscritoire.java new file mode 100755 index 000000000..72f586262 --- /dev/null +++ b/forestry_common/core/forestry/core/render/ModelEscritoire.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; + +public class ModelEscritoire extends ModelBase { + + //fields + ModelRenderer desk; + ModelRenderer standRB; + ModelRenderer standRF; + ModelRenderer standLB; + ModelRenderer standLF; + ModelRenderer drawers; + ModelRenderer standLowLF; + ModelRenderer standLowRB; + ModelRenderer standLowRF; + ModelRenderer standLowLB; + + public ModelEscritoire() { + textureWidth = 64; + textureHeight = 32; + + desk = new ModelRenderer(this, 0, 0); + desk.addBox(-8F, 3F, -7.8F, 16, 2, 15); + desk.setRotationPoint(0F, 0F, 0F); + desk.setTextureSize(64, 32); + desk.mirror = true; + setRotation(desk, 0.0872665f, 0f, 0f); + standRB = new ModelRenderer(this, 38, 18); + standRB.addBox(5F, 4F, 5F, 2, 6, 2); + standRB.setRotationPoint(0F, 0F, 0F); + standRB.setTextureSize(64, 32); + standRB.mirror = true; + setRotation(standRB, 0F, 0F, 0F); + standRF = new ModelRenderer(this, 38, 18); + standRF.addBox(5F, 4F, -7F, 2, 6, 2); + standRF.setRotationPoint(0F, 0F, 0F); + standRF.setTextureSize(64, 32); + standRF.mirror = true; + setRotation(standRF, 0F, 0F, 0F); + standLB = new ModelRenderer(this, 38, 18); + standLB.addBox(-7F, 4F, 5F, 2, 6, 2); + standLB.setRotationPoint(0F, 0F, 0F); + standLB.setTextureSize(64, 32); + standLB.mirror = true; + setRotation(standLB, 0F, 0F, 0F); + standLF = new ModelRenderer(this, 38, 18); + standLF.addBox(-7F, 4F, -7F, 2, 6, 2); + standLF.setRotationPoint(0F, 0F, 0F); + standLF.setTextureSize(64, 32); + standLF.mirror = true; + setRotation(standLF, 0F, 0F, 0F); + drawers = new ModelRenderer(this, 0, 18); + drawers.addBox(-7.5F, -2F, 4.5F, 15, 5, 3); + drawers.setRotationPoint(0F, 0F, 0F); + drawers.setTextureSize(64, 32); + drawers.mirror = true; + setRotation(drawers, 0F, 0F, 0F); + standLowLF = new ModelRenderer(this, 0, 26); + standLowLF.addBox(-6.5F, 10F, -6.5F, 1, 4, 1); + standLowLF.setRotationPoint(0F, 0F, 0F); + standLowLF.setTextureSize(64, 32); + standLowLF.mirror = true; + setRotation(standLowLF, 0F, 0F, 0F); + standLowRB = new ModelRenderer(this, 0, 26); + standLowRB.addBox(5.5F, 10F, 5.5F, 1, 4, 1); + standLowRB.setRotationPoint(0F, 0F, 0F); + standLowRB.setTextureSize(64, 32); + standLowRB.mirror = true; + setRotation(standLowRB, 0F, 0F, 0F); + standLowRF = new ModelRenderer(this, 0, 26); + standLowRF.addBox(5.5F, 10F, -6.5F, 1, 4, 1); + standLowRF.setRotationPoint(0F, 0F, 0F); + standLowRF.setTextureSize(64, 32); + standLowRF.mirror = true; + setRotation(standLowRF, 0F, 0F, 0F); + standLowLB = new ModelRenderer(this, 0, 26); + standLowLB.addBox(-6.5F, 10F, 5.5F, 1, 4, 1); + standLowLB.setRotationPoint(0F, 0F, 0F); + standLowLB.setTextureSize(64, 32); + standLowLB.mirror = true; + setRotation(standLowLB, 0F, 0F, 0F); + /* + desk = new ModelRenderer(this, 0, 0); + desk.addBox(0F, 0F, 0F, 16, 2, 15); + desk.setRotationPoint(-8F, 4F, -7.5F); + desk.setTextureSize(64, 32); + desk.mirror = true; + setRotation(desk, 0.0872665F, 0F, 0F); + standRB = new ModelRenderer(this, 38, 18); + standRB.addBox(0F, 0F, 0F, 2, 6, 2); + standRB.setRotationPoint(5F, 4F, 5F); + standRB.setTextureSize(64, 32); + standRB.mirror = true; + setRotation(standRB, 0F, 0F, 0F); + standRF = new ModelRenderer(this, 38, 18); + standRF.addBox(0F, 0F, 0F, 2, 6, 2); + standRF.setRotationPoint(5F, 4F, -7F); + standRF.setTextureSize(64, 32); + standRF.mirror = true; + setRotation(standRF, 0F, 0F, 0F); + standLB = new ModelRenderer(this, 38, 18); + standLB.addBox(0F, 0F, 0F, 2, 6, 2); + standLB.setRotationPoint(-7F, 4F, 5F); + standLB.setTextureSize(64, 32); + standLB.mirror = true; + setRotation(standLB, 0F, 0F, 0F); + standLF = new ModelRenderer(this, 38, 18); + standLF.addBox(0F, 0F, 0F, 2, 6, 2); + standLF.setRotationPoint(-7F, 4F, -7F); + standLF.setTextureSize(64, 32); + standLF.mirror = true; + setRotation(standLF, 0F, 0F, 0F); + drawers = new ModelRenderer(this, 0, 18); + drawers.addBox(0F, 0F, 0F, 16, 5, 3); + drawers.setRotationPoint(-8F, -2F, 4.5F); + drawers.setTextureSize(64, 32); + drawers.mirror = true; + setRotation(drawers, 0F, 0F, 0F); + standLowLF = new ModelRenderer(this, 0, 25); + standLowLF.addBox(0F, 0F, 0F, 1, 4, 1); + standLowLF.setRotationPoint(-6.5F, 10F, -6.5F); + standLowLF.setTextureSize(64, 32); + standLowLF.mirror = true; + setRotation(standLowLF, 0F, 0F, 0F); + standLowRB = new ModelRenderer(this, 0, 25); + standLowRB.addBox(0F, 0F, 0F, 1, 4, 1); + standLowRB.setRotationPoint(5.5F, 10F, 5.5F); + standLowRB.setTextureSize(64, 32); + standLowRB.mirror = true; + setRotation(standLowRB, 0F, 0F, 0F); + standLowRF = new ModelRenderer(this, 0, 25); + standLowRF.addBox(0F, 0F, 0F, 1, 4, 1); + standLowRF.setRotationPoint(5.5F, 10F, -6.5F); + standLowRF.setTextureSize(64, 32); + standLowRF.mirror = true; + setRotation(standLowRF, 0F, 0F, 0F); + standLowLB = new ModelRenderer(this, 0, 25); + standLowLB.addBox(0F, 0F, 0F, 1, 4, 1); + standLowLB.setRotationPoint(-6.5F, 10F, 5.5F); + standLowLB.setTextureSize(64, 32); + standLowLB.mirror = true; + setRotation(standLowLB, 0F, 0F, 0F); + */ + } + + @Override + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { + super.render(entity, f, f1, f2, f3, f4, f5); + setRotationAngles(f, f1, f2, f3, f4, f5, entity); + desk.render(f5); + standRB.render(f5); + standRF.render(f5); + standLB.render(f5); + standLF.render(f5); + drawers.render(f5); + standLowLF.render(f5); + standLowRB.render(f5); + standLowRF.render(f5); + standLowLB.render(f5); + } + + private void setRotation(ModelRenderer model, float x, float y, float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + + @Override + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) { + setRotation(desk, f + 0.0872665f, f1, f2); + setRotation(standRB, f, f1, f2); + setRotation(standRF, f, f1, f2); + setRotation(standLB, f, f1, f2); + setRotation(standLF, f, f1, f2); + setRotation(drawers, f, f1, f2); + setRotation(standLowLF, f, f1, f2); + setRotation(standLowRB, f, f1, f2); + setRotation(standLowRF, f, f1, f2); + setRotation(standLowLB, f, f1, f2); + super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } + +} diff --git a/forestry_common/core/forestry/core/render/OverlayRenderingHandler.java b/forestry_common/core/forestry/core/render/OverlayRenderingHandler.java new file mode 100755 index 000000000..1a6c82aa4 --- /dev/null +++ b/forestry_common/core/forestry/core/render/OverlayRenderingHandler.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; + +public abstract class OverlayRenderingHandler implements ISimpleBlockRenderingHandler { + + protected static final double OVERLAY_SHIFT = 0.001; + + protected int determineMixedBrightness(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, int mixedBrightness) { + return renderer.renderMinY > 0.0D ? mixedBrightness : block.getMixedBrightnessForBlock(world, x, y, z); + } + + protected void renderBottomFace(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, IIcon textureIndex, int mixedBrightness, + float r, float g, float b) { + + if (!renderer.renderAllFaces && !block.shouldSideBeRendered(world, x, y - 1, z, 0)) + return; + + Tessellator tesselator = Tessellator.instance; + + tesselator.setBrightness(determineMixedBrightness(world, block, x, y - 1, z, renderer, mixedBrightness)); + tesselator.setColorOpaque_F(r, g, b); + renderer.renderFaceYNeg(block, x, y - OVERLAY_SHIFT, z, textureIndex); + + } + + protected void renderTopFace(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, IIcon textureIndex, int mixedBrightness, float r, + float g, float b) { + + if (!renderer.renderAllFaces && !block.shouldSideBeRendered(world, x, y + 1, z, 1)) + return; + + Tessellator tesselator = Tessellator.instance; + + tesselator.setBrightness(determineMixedBrightness(world, block, x, y + 1, z, renderer, mixedBrightness)); + tesselator.setColorOpaque_F(r, g, b); + renderer.renderFaceYPos(block, x, y + OVERLAY_SHIFT, z, textureIndex); + + } + + protected void renderEastFace(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, IIcon textureIndex, int mixedBrightness, float r, + float g, float b) { + + if (!renderer.renderAllFaces && !block.shouldSideBeRendered(world, x, y, z - 1, 2)) + return; + + Tessellator tesselator = Tessellator.instance; + + tesselator.setBrightness(determineMixedBrightness(world, block, x, y, z - 1, renderer, mixedBrightness)); + tesselator.setColorOpaque_F(r, g, b); + renderer.renderFaceZNeg(block, x, y, z - OVERLAY_SHIFT, textureIndex); + + } + + protected void renderWestFace(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, IIcon textureIndex, int mixedBrightness, float r, + float g, float b) { + + if (!renderer.renderAllFaces && !block.shouldSideBeRendered(world, x, y, z + 1, 3)) + return; + + Tessellator tesselator = Tessellator.instance; + + tesselator.setBrightness(determineMixedBrightness(world, block, x, y, z + 1, renderer, mixedBrightness)); + tesselator.setColorOpaque_F(r, g, b); + renderer.renderFaceZPos(block, x, y, z + OVERLAY_SHIFT, textureIndex); + + } + + protected void renderNorthFace(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, IIcon textureIndex, int mixedBrightness, + float r, float g, float b) { + + if (!renderer.renderAllFaces && !block.shouldSideBeRendered(world, x - 1, y, z, 4)) + return; + + Tessellator tesselator = Tessellator.instance; + + tesselator.setBrightness(determineMixedBrightness(world, block, x - 1, y, z, renderer, mixedBrightness)); + tesselator.setColorOpaque_F(r, g, b); + renderer.renderFaceXNeg(block, x - OVERLAY_SHIFT, y, z, textureIndex); + + } + + protected void renderSouthFace(IBlockAccess world, Block block, int x, int y, int z, RenderBlocks renderer, IIcon textureIndex, int mixedBrightness, + float r, float g, float b) { + + if (!renderer.renderAllFaces && !block.shouldSideBeRendered(world, x + 1, y, z, 5)) + return; + + Tessellator tesselator = Tessellator.instance; + + tesselator.setBrightness(determineMixedBrightness(world, block, x + 1, y, z, renderer, mixedBrightness)); + tesselator.setColorOpaque_F(r, g, b); + renderer.renderFaceXPos(block, x + OVERLAY_SHIFT, y, z, textureIndex); + + } + +} diff --git a/forestry_common/core/forestry/core/render/RenderAnalyzer.java b/forestry_common/core/forestry/core/render/RenderAnalyzer.java new file mode 100755 index 000000000..8b6b228a8 --- /dev/null +++ b/forestry_common/core/forestry/core/render/RenderAnalyzer.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import forestry.apiculture.render.ModelAnalyzer; +import forestry.core.gadgets.TileAnalyzer; +import forestry.core.interfaces.IBlockRenderer; + +public class RenderAnalyzer extends TileEntitySpecialRenderer implements IBlockRenderer { + + private ModelAnalyzer model; + private final EntityItem dummyEntityItem = new EntityItem(null); + private final RenderItem customRenderItem; + private long lastTick; + + public RenderAnalyzer() { + customRenderItem = new RenderItem() { + @Override + public boolean shouldBob() { + return true; + } + + @Override + public boolean shouldSpreadItems() { + return false; + }; + }; + customRenderItem.setRenderManager(RenderManager.instance); + } + + public RenderAnalyzer(String baseTexture) { + this(); + this.model = new ModelAnalyzer(baseTexture); + } + + @Override + public void inventoryRender(double x, double y, double z, float f, float f1) { + render(null, null, ForgeDirection.WEST, x, y, z); + } + + @Override + public void renderTileEntityAt(TileEntity tile, double d, double d1, double d2, float f) { + + TileAnalyzer analyzer = (TileAnalyzer) tile; + render(analyzer.getIndividualOnDisplay(), tile.getWorldObj(), analyzer.getOrientation(), d, d1, d2); + } + + private void render(ItemStack itemstack, World world, ForgeDirection orientation, double x, double y, double z) { + + dummyEntityItem.worldObj = world; + + model.render(orientation, (float) x, (float) y, (float) z); + if (itemstack == null) + return; + float renderScale = 1.0f; + + GL11.glPushMatrix(); + GL11.glTranslatef((float) x, (float) y, (float) z); + GL11.glTranslatef(0.5f, 0.2f, 0.5f); + GL11.glScalef(renderScale, renderScale, renderScale); + dummyEntityItem.setEntityItemStack(itemstack); + + if (world.getTotalWorldTime() != lastTick) { + lastTick = world.getTotalWorldTime(); + dummyEntityItem.onUpdate(); + } + customRenderItem.doRender(dummyEntityItem, 0, 0, 0, 0, 0); + GL11.glPopMatrix(); + + } + +} diff --git a/forestry_common/core/forestry/core/render/RenderEscritoire.java b/forestry_common/core/forestry/core/render/RenderEscritoire.java new file mode 100755 index 000000000..905cecfd0 --- /dev/null +++ b/forestry_common/core/forestry/core/render/RenderEscritoire.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; + +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileEscritoire; +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryResource; + +public class RenderEscritoire extends TileEntitySpecialRenderer implements IBlockRenderer { + + ModelEscritoire modelEscritoire; + ResourceLocation texture = new ForestryResource(Defaults.TEXTURE_PATH_BLOCKS + "/escritoire.png"); + //private final EntityItem dummyEntityItem = new EntityItem(null); + private final RenderItem customRenderItem; + + public RenderEscritoire() { + modelEscritoire = new ModelEscritoire(); + + customRenderItem = new RenderItem() { + @Override + public boolean shouldBob() { + return false; + } + + @Override + public boolean shouldSpreadItems() { + return false; + }; + }; + customRenderItem.setRenderManager(RenderManager.instance); + + } + + @Override + public void inventoryRender(double x, double y, double z, float f, float f1) { + render(null, ForgeDirection.EAST, x, y, z); + } + + @Override + public void renderTileEntityAt(TileEntity tileentity, double x, double y, double z, float f) { + TileEscritoire tile = (TileEscritoire)tileentity; + render(tile.getStackInSlot(TileEscritoire.SLOT_ANALYZE), tile.getOrientation(), x, y, z); + } + + private void render(ItemStack itemstack, ForgeDirection orientation, double x, double y, double z) { + float factor = (float) (1.0 / 16.0); + + GL11.glPushMatrix(); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glTranslatef((float) x + 0.5f, (float) y + 0.875f, (float) z + 0.5f); + + float[] angle = { (float) Math.PI, 0, 0 }; + + if (orientation == null) + orientation = ForgeDirection.WEST; + switch (orientation) { + case EAST: + angle[1] = (float)Math.PI / 2; + break; + case SOUTH: + break; + case NORTH: + angle[1] = (float)Math.PI; + break; + case WEST: + default: + angle[1] = -(float)Math.PI / 2; + break; + } + + Proxies.common.bindTexture(texture); + modelEscritoire.render(null, angle[0], angle[1], angle[2], 0f, 0f, factor); + + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glPopMatrix(); + + /* + if(itemstack != null) { + float renderScale = 1.0f; + + GL11.glPushMatrix(); + GL11.glTranslatef((float) x, (float) y, (float) z); + GL11.glTranslatef(0.6f, 0.8f, 0.5f); + GL11.glRotatef(90.0f, 1.0F, 0.0F, 0.0F); + GL11.glScalef(renderScale, renderScale, renderScale); + + RenderItem.renderInFrame = true; + dummyEntityItem.setEntityItemStack(itemstack); + customRenderItem.doRenderItem(dummyEntityItem, 0, 0, 0, 0, 0); + RenderItem.renderInFrame = false; + GL11.glPopMatrix(); + } + */ + + } +} diff --git a/forestry_common/core/forestry/core/render/RenderMachine.java b/forestry_common/core/forestry/core/render/RenderMachine.java new file mode 100755 index 000000000..2893cb6b9 --- /dev/null +++ b/forestry_common/core/forestry/core/render/RenderMachine.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; + +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.interfaces.IRenderableMachine; +import forestry.core.proxy.Proxies; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryResource; + +public class RenderMachine extends TileEntitySpecialRenderer implements IBlockRenderer { + + private final ModelBase model = new ModelBase() { + }; + + private final ModelRenderer basefront; + private final ModelRenderer baseback; + private final ModelRenderer resourceTank; + private final ModelRenderer productTank; + + private static enum Textures { + BASE, + TANK_R_EMPTY, TANK_R_LOW, TANK_R_MEDIUM, TANK_R_HIGH, TANK_R_MAXIMUM, + TANK_P_EMPTY, TANK_P_LOW, TANK_P_MEDIUM, TANK_P_HIGH, TANK_P_MAXIMUM + }; + private ResourceLocation[] textures; + + public RenderMachine() { + + basefront = new ModelRenderer(model, 0, 0); + basefront.addBox(-8F, -8F, -8F, 16, 4, 16); + basefront.rotationPointX = 8; + basefront.rotationPointY = 8; + basefront.rotationPointZ = 8; + + baseback = new ModelRenderer(model, 0, 0); + baseback.addBox(-8F, 4F, -8F, 16, 4, 16); + baseback.rotationPointX = 8; + baseback.rotationPointY = 8; + baseback.rotationPointZ = 8; + + resourceTank = new ModelRenderer(model, 0, 0); + resourceTank.addBox(-6F, -8F, -6F, 12, 16, 6); + resourceTank.rotationPointX = 8; + resourceTank.rotationPointY = 8; + resourceTank.rotationPointZ = 8; + + productTank = new ModelRenderer(model, 0, 0); + productTank.addBox(-6F, -8F, 0F, 12, 16, 6); + productTank.rotationPointX = 8; + productTank.rotationPointY = 8; + productTank.rotationPointZ = 8; + + } + + public RenderMachine(String baseTexture) { + this(); + + textures = new ResourceLocation[] { + new ForestryResource(baseTexture + "base.png"), + + new ForestryResource(baseTexture + "tank_resource_empty.png"), + new ForestryResource(baseTexture + "tank_resource_low.png"), + new ForestryResource(baseTexture + "tank_resource_medium.png"), + new ForestryResource(baseTexture + "tank_resource_high.png"), + new ForestryResource(baseTexture + "tank_resource_maximum.png"), + + new ForestryResource(baseTexture + "tank_product_empty.png"), + new ForestryResource(baseTexture + "tank_product_low.png"), + new ForestryResource(baseTexture + "tank_product_medium.png"), + new ForestryResource(baseTexture + "tank_product_high.png"), + new ForestryResource(baseTexture + "tank_product_maximum.png"), + }; + + } + + @Override + public void inventoryRender(double x, double y, double z, float f, float f1) { + render(EnumTankLevel.EMPTY, EnumTankLevel.EMPTY, ForgeDirection.UP, x, y, z); + } + + @Override + public void renderTileEntityAt(TileEntity tileentity, double d, double d1, double d2, float f) { + IRenderableMachine generator = (IRenderableMachine) tileentity; + render(generator.getPrimaryLevel(), generator.getSecondaryLevel(), generator.getOrientation(), d, d1, d2); + + } + + private void render(EnumTankLevel waterLevel, EnumTankLevel melangeLevel, ForgeDirection orientation, double x, double y, double z) { + render(waterLevel.ordinal(), melangeLevel.ordinal(), orientation, x, y, z); + } + + public void render(int waterLevelInt, int melangeLevelInt, ForgeDirection orientation, double x, double y, double z) { + + EnumTankLevel waterLevel = EnumTankLevel.values()[waterLevelInt]; + EnumTankLevel melangeLevel = EnumTankLevel.values()[melangeLevelInt]; + + GL11.glPushMatrix(); + // GL11.glDisable(2896 /* GL_LIGHTING */); + GL11.glDisable(GL11.GL_LIGHTING); + + GL11.glTranslatef((float) x, (float) y, (float) z); + + float[] angle = { 0, 0, 0 }; + float[] translate = { 0, 0, 0 }; + + if (orientation == null) + orientation = ForgeDirection.WEST; + switch (orientation) { + case EAST: + // angle [2] = (float) Math.PI / 2; + angle[1] = (float) Math.PI; + angle[2] = (float) -Math.PI / 2; + translate[0] = 1; + break; + case WEST: + // 2, -PI/2 + angle[2] = (float) Math.PI / 2; + translate[0] = -1; + break; + case UP: + translate[1] = 1; + break; + case DOWN: + angle[2] = (float) Math.PI; + translate[1] = -1; + break; + case SOUTH: + angle[0] = (float) Math.PI / 2; + angle[2] = (float) Math.PI / 2; + translate[2] = 1; + break; + case NORTH: + default: + angle[0] = (float) -Math.PI / 2; + angle[2] = (float) Math.PI / 2; + translate[2] = -1; + break; + } + + basefront.rotateAngleX = angle[0]; + basefront.rotateAngleY = angle[1]; + basefront.rotateAngleZ = angle[2]; + + baseback.rotateAngleX = angle[0]; + baseback.rotateAngleY = angle[1]; + baseback.rotateAngleZ = angle[2]; + + resourceTank.rotateAngleX = angle[0]; + resourceTank.rotateAngleY = angle[1]; + resourceTank.rotateAngleZ = angle[2]; + + productTank.rotateAngleX = angle[0]; + productTank.rotateAngleY = angle[1]; + productTank.rotateAngleZ = angle[2]; + + float factor = (float) (1.0 / 16.0); + + Proxies.common.bindTexture(textures[Textures.BASE.ordinal()]); + basefront.render(factor); + + Proxies.common.bindTexture(textures[Textures.BASE.ordinal()]); + baseback.render(factor); + + ResourceLocation texture; + + switch (waterLevel) { + case LOW: + texture = textures[Textures.TANK_R_LOW.ordinal()]; + break; + case MEDIUM: + texture = textures[Textures.TANK_R_MEDIUM.ordinal()]; + break; + case HIGH: + texture = textures[Textures.TANK_R_HIGH.ordinal()]; + break; + case MAXIMUM: + texture = textures[Textures.TANK_R_MAXIMUM.ordinal()]; + break; + case EMPTY: + default: + texture = textures[Textures.TANK_R_EMPTY.ordinal()]; + break; + } + Proxies.common.bindTexture(texture); + resourceTank.render(factor); + + switch (melangeLevel) { + case LOW: + texture = textures[Textures.TANK_P_LOW.ordinal()]; + break; + case MEDIUM: + texture = textures[Textures.TANK_P_MEDIUM.ordinal()]; + break; + case HIGH: + texture = textures[Textures.TANK_P_HIGH.ordinal()]; + break; + case MAXIMUM: + texture = textures[Textures.TANK_P_MAXIMUM.ordinal()]; + break; + case EMPTY: + default: + texture = textures[Textures.TANK_P_EMPTY.ordinal()]; + break; + } + Proxies.common.bindTexture(texture); + productTank.render(factor); + + // GL11.glEnable(2896 /* GL_LIGHTING */); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glPopMatrix(); + } +} diff --git a/forestry_common/core/forestry/core/render/RenderMill.java b/forestry_common/core/forestry/core/render/RenderMill.java new file mode 100755 index 000000000..3cae846e9 --- /dev/null +++ b/forestry_common/core/forestry/core/render/RenderMill.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; + +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import forestry.core.gadgets.Mill; +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryResource; + +public class RenderMill extends TileEntitySpecialRenderer implements IBlockRenderer { + + private final ModelBase model = new ModelBase() { + }; + + private static enum Textures { PEDESTAL, EXTENSION, BLADE_1, BLADE_2, CHARGE }; + private ResourceLocation[] textures; + + private final ModelRenderer pedestal; + private final ModelRenderer column; + private final ModelRenderer extension; + private final ModelRenderer blade1; + private final ModelRenderer blade2; + + public RenderMill() { + pedestal = new ModelRenderer(model, 0, 0); + pedestal.addBox(-8F, -8F, -8F, 16, 1, 16); + pedestal.rotationPointX = 8; + pedestal.rotationPointY = 8; + pedestal.rotationPointZ = 8; + + column = new ModelRenderer(model, 0, 0); + column.addBox(-2, -7F, -2, 4, 15, 4); + column.rotationPointX = 8; + column.rotationPointY = 8; + column.rotationPointZ = 8; + + extension = new ModelRenderer(model, 0, 0); + extension.addBox(1F, 8F, 7F, 14, 2, 2); + extension.rotationPointX = 0; + extension.rotationPointY = 0; + extension.rotationPointZ = 0; + + blade1 = new ModelRenderer(model, 0, 0); + blade1.addBox(-4F, -5F, -3F, 8, 12, 1); + blade1.rotationPointX = 8; + blade1.rotationPointY = 8; + blade1.rotationPointZ = 8; + + blade2 = new ModelRenderer(model, 0, 0); + blade2.addBox(-4F, -5F, 2F, 8, 12, 1); + blade2.rotationPointX = 8; + blade2.rotationPointY = 8; + blade2.rotationPointZ = 8; + + } + + public RenderMill(String baseTexture) { + this(); + + textures = new ResourceLocation[12]; + + textures[Textures.PEDESTAL.ordinal()] = new ForestryResource(baseTexture + "pedestal.png"); + textures[Textures.EXTENSION.ordinal()] = new ForestryResource(baseTexture + "extension.png"); + textures[Textures.BLADE_1.ordinal()] = new ForestryResource(baseTexture + "blade1.png"); + textures[Textures.BLADE_2.ordinal()] = new ForestryResource(baseTexture + "blade2.png"); + + for(int i = 0; i < 8; i++) { + textures[Textures.CHARGE.ordinal() + i] = new ForestryResource(baseTexture + "column_"+ i +".png"); + } + } + + public RenderMill(String baseTexture, byte charges) { + this(baseTexture); + } + + @Override + public void inventoryRender(double x, double y, double z, float f, float f1) { + byte charge = 0; + render(0.0f, charge, ForgeDirection.WEST, x, y, z); + } + + @Override + public void renderTileEntityAt(TileEntity tileentity, double d, double d1, double d2, float f) { + Mill tile = (Mill) tileentity; + render(tile.progress, tile.charge, ForgeDirection.WEST, d, d1, d2); + } + + private void render(float progress, int charge, ForgeDirection orientation, double x, double y, double z) { + + GL11.glPushMatrix(); + GL11.glDisable(2896 /* GL_LIGHTING */); + + GL11.glTranslatef((float) x, (float) y, (float) z); + + float step; + + if (progress > 0.5) + step = 3.99F - (progress - 0.5F) * 2F * 3.99F; + else + step = progress * 2F * 3.99F; + + float[] angle = { 0, 0, 0 }; + float[] translate = { 0, 0, 0 }; + float tfactor = step / 16; + + if (orientation == null) + orientation = ForgeDirection.WEST; + switch (orientation) { + case EAST: + // angle [2] = (float) Math.PI / 2; + angle[1] = (float) Math.PI; + angle[2] = (float) -Math.PI / 2; + translate[0] = 1; + break; + case WEST: + // 2, -PI/2 + angle[2] = (float) Math.PI / 2; + translate[0] = -1; + break; + case UP: + translate[1] = 1; + break; + case DOWN: + angle[2] = (float) Math.PI; + translate[1] = -1; + break; + case SOUTH: + angle[0] = (float) Math.PI / 2; + angle[2] = (float) Math.PI / 2; + translate[2] = 1; + break; + case NORTH: + default: + angle[0] = (float) -Math.PI / 2; + angle[2] = (float) Math.PI / 2; + translate[2] = -1; + break; + } + + pedestal.rotateAngleX = angle[0]; + pedestal.rotateAngleY = angle[2]; + pedestal.rotateAngleZ = angle[1]; + + column.rotateAngleX = angle[0]; + column.rotateAngleY = angle[2]; + column.rotateAngleZ = angle[1]; + + blade1.rotateAngleX = angle[0]; + blade1.rotateAngleY = angle[2]; + blade1.rotateAngleZ = angle[1]; + + blade2.rotateAngleX = angle[0]; + blade2.rotateAngleY = angle[2]; + blade2.rotateAngleZ = angle[1]; + + float factor = (float) (1.0 / 16.0); + + Proxies.common.bindTexture(textures[Textures.PEDESTAL.ordinal()]); + pedestal.render(factor); + + Proxies.common.bindTexture(textures[Textures.CHARGE.ordinal() + charge]); + column.render(factor); + + Proxies.common.bindTexture(textures[Textures.EXTENSION.ordinal()]); + extension.render(factor); + + Proxies.common.bindTexture(textures[Textures.BLADE_1.ordinal()]); + GL11.glTranslatef(translate[0] * tfactor, translate[1] * tfactor, translate[2] * tfactor); + blade1.render(factor); + + // Reset + GL11.glTranslatef(-translate[0] * tfactor, -translate[1] * tfactor, -translate[2] * tfactor); + + Proxies.common.bindTexture(textures[Textures.BLADE_2.ordinal()]); + GL11.glTranslatef(-translate[0] * tfactor, translate[1] * tfactor, -translate[2] * tfactor); + blade2.render(factor); + + GL11.glEnable(2896 /* GL_LIGHTING */); + GL11.glPopMatrix(); + + } + +} diff --git a/forestry_common/core/forestry/core/render/SpriteSheet.java b/forestry_common/core/forestry/core/render/SpriteSheet.java new file mode 100755 index 000000000..10aa0fa57 --- /dev/null +++ b/forestry_common/core/forestry/core/render/SpriteSheet.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.ResourceLocation; + +public enum SpriteSheet { + BLOCKS, + ITEMS; + + public ResourceLocation getLocation() { + return ordinal() == 0 ? TextureMap.locationBlocksTexture : TextureMap.locationItemsTexture; + } + + public int getSheetOrdinal() { + return ordinal(); + } +} diff --git a/forestry_common/core/forestry/core/render/TextureManager.java b/forestry_common/core/forestry/core/render/TextureManager.java new file mode 100755 index 000000000..e12a6bd13 --- /dev/null +++ b/forestry_common/core/forestry/core/render/TextureManager.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.ForestryAPI; +import forestry.api.core.IIconProvider; +import forestry.api.core.ITextureManager; + +@SideOnly(Side.CLIENT) +public class TextureManager implements ITextureManager { + + private static TextureManager instance; + + public static TextureManager getInstance() { + if (instance == null) { + instance = new TextureManager(); + ForestryAPI.textureManager = instance; + } + + return instance; + } + + String[] defaultIconNames = new String[] { "habitats/desert", "habitats/end", "habitats/forest", "habitats/hills", "habitats/jungle", "habitats/mushroom", + "habitats/nether", "habitats/ocean", "habitats/plains", "habitats/snow", "habitats/swamp", "habitats/taiga", "misc/access.private", + "misc/access.viewable", "misc/access.shared", "misc/empty", "misc/energy", "misc/hint", "misc/liquid", + "analyzer/anything", "analyzer/bee", "analyzer/cave", "analyzer/closed", "analyzer/drone", "analyzer/flyer", + "analyzer/item", "analyzer/nocturnal", "analyzer/princess", "analyzer/pure_breed", "analyzer/pure_cave", + "analyzer/pure_flyer", "analyzer/pure_nocturnal", "analyzer/queen", "analyzer/natural", + "particles/ember", "particles/flame", "particles/poison", "particles/snow", "particles/swarm_bee", "errors/errored", + "slots/blocked", "slots/blocked_2", "slots/liquid", "slots/container", "slots/locked", + "mail/carrier.player", "mail/carrier.trader" }; + HashMap defaultIcons = new HashMap(); + + public void initDefaultIcons(IIconRegister register) { + for (String str : defaultIconNames) + defaultIcons.put(str, TextureManager.getInstance().registerTex(register, str)); + } + + public IIcon getDefault(String ident) { + if (defaultIcons.containsKey(ident)) + return defaultIcons.get(ident); + else + return null; + } + + //public TextureMap terrainMap; + //public TextureMap itemMap; + + IIcon[] textures = new IIcon[2048]; + + ArrayList iconProvider = new ArrayList(); + + public TextureManager() { + //this.terrainMap = textureMap; + //this.itemMap = itemMap; + } + + public IIcon registerTex(IIconRegister register, String identifier) { + return register.registerIcon("forestry:" + identifier); + } + + public IIcon registerTexUID(IIconRegister register, short uid, String identifier) { + return setTexUID(uid, registerTex(register, identifier)); + } + + public IIcon setTexUID(short uid, IIcon texture) { + textures[uid] = texture; + return texture; + } + + @Override + public void registerIconProvider(IIconProvider provider) { + iconProvider.add(provider); + } + + @Override + public IIcon getIcon(short texUID) { + if (texUID < textures.length) + return textures[texUID]; + + for (IIconProvider provider : iconProvider) { + IIcon retr = provider.getIcon(texUID); + if (retr != null) + return retr; + } + + return null; + } +} diff --git a/forestry_common/core/forestry/core/render/TileRendererIndex.java b/forestry_common/core/forestry/core/render/TileRendererIndex.java new file mode 100755 index 000000000..4669bb51c --- /dev/null +++ b/forestry_common/core/forestry/core/render/TileRendererIndex.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.render; + +import net.minecraft.block.Block; + +public class TileRendererIndex { + private Block block; + private int meta; + + public TileRendererIndex(Block block, int meta) { + this.block = block; + this.meta = meta; + } + + public int hashCode() { + return block.hashCode() + meta; + } + + public boolean equals(Object aobj) { + if (!(aobj instanceof TileRendererIndex)) + return false; + + TileRendererIndex index = (TileRendererIndex) aobj; + + return index.block == block && index.meta == meta; + } +} diff --git a/forestry_common/core/forestry/core/triggers/ForestryTrigger.java b/forestry_common/core/forestry/core/triggers/ForestryTrigger.java new file mode 100755 index 000000000..6b8c3df0a --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/ForestryTrigger.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import buildcraft.api.gates.ActionManager; + +public class ForestryTrigger { + + public static Trigger lowFuel25; + public static Trigger lowFuel10; + public static Trigger lowResource25; + public static Trigger lowResource10; + public static Trigger lowSoil25; + public static Trigger lowSoil10; + public static Trigger lowGermlings25; + public static Trigger lowGermlings10; + public static Trigger missingQueen; + public static Trigger missingDrone; + public static Trigger hasWork; + + public static void initialize() { + ActionManager.registerTrigger(lowFuel25 = new TriggerLowFuel("lowFuel.25", 0.25f)); + ActionManager.registerTrigger(lowFuel10 = new TriggerLowFuel("lowFuel.10", 0.1f)); + ActionManager.registerTrigger(lowResource25 = new TriggerLowResource("lowResources.25", 0.25f)); + ActionManager.registerTrigger(lowResource10 = new TriggerLowResource("lowResources.10", 0.1f)); + + ActionManager.registerTrigger(lowSoil25 = new TriggerLowSoil("lowSoil.25", 0.25f)); + ActionManager.registerTrigger(lowSoil10 = new TriggerLowSoil("lowSoil.10", 0.1f)); + ActionManager.registerTrigger(lowGermlings25 = new TriggerLowGermlings("lowGermlings.25", 0.25f)); + ActionManager.registerTrigger(lowGermlings10 = new TriggerLowGermlings("lowGermlings.10", 0.1f)); + + ActionManager.registerTrigger(missingQueen = new TriggerMissingQueen()); + ActionManager.registerTrigger(missingDrone = new TriggerMissingDrone()); + + ActionManager.registerTrigger(hasWork = new TriggerHasWork()); + + } +} diff --git a/forestry_common/core/forestry/core/triggers/Trigger.java b/forestry_common/core/forestry/core/triggers/Trigger.java new file mode 100755 index 000000000..1a683904b --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/Trigger.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import buildcraft.api.gates.ActionManager; +import buildcraft.api.gates.ITileTrigger; +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public abstract class Trigger implements ITileTrigger { + + private final String uid; + private final String unlocalized; + + public Trigger(String uid) { + this(uid, uid); + } + + public Trigger(String uid, String localization) { + this.uid = "forestry." + uid; + unlocalized = "trigger." + localization; + ActionManager.registerTrigger(this); + } + + @Override + public String getUniqueTag() { + return uid; + } + + @Override + public String getDescription() { + return StringUtil.localize(unlocalized); + } + + @Override + public boolean hasParameter() { + return false; + } + + @Override + public boolean requiresParameter() { + return false; + } + + @Override + public ITriggerParameter createParameter() { + return null; + } + @SideOnly(Side.CLIENT) + private IIcon icon; + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return icon; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + icon = TextureManager.getInstance().registerTex(register, "triggers/" + unlocalized.replace("trigger.", "")); + } +} diff --git a/forestry_common/core/forestry/core/triggers/TriggerHasWork.java b/forestry_common/core/forestry/core/triggers/TriggerHasWork.java new file mode 100755 index 000000000..3caef782f --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/TriggerHasWork.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.gadgets.TilePowered; + +public class TriggerHasWork extends Trigger { + + public TriggerHasWork() { + super("hasWork"); + } + + /** + * Return true if the tile given in parameter activates the trigger, given + * the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof TilePowered)) + return false; + + return ((TilePowered) tile).hasWork(); + } +} diff --git a/forestry_common/core/forestry/core/triggers/TriggerLowFuel.java b/forestry_common/core/forestry/core/triggers/TriggerLowFuel.java new file mode 100755 index 000000000..bd015c038 --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/TriggerLowFuel.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.gadgets.Engine; +import forestry.core.gadgets.TilePowered; + +public class TriggerLowFuel extends Trigger { + + private float threshold = 0.25F; + + public TriggerLowFuel(String tag, float threshold) { + super(tag, "lowFuel"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + /** + * Return true if the tile given in parameter activates the trigger, given the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (tile instanceof TilePowered) + return !((TilePowered) tile).hasFuelMin(threshold); + + if (tile instanceof Engine) { + Engine engine = (Engine) tile; + return !engine.hasFuelMin(threshold); + } + + return false; + } + +} diff --git a/forestry_common/core/forestry/core/triggers/TriggerLowGermlings.java b/forestry_common/core/forestry/core/triggers/TriggerLowGermlings.java new file mode 100755 index 000000000..25cb2594b --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/TriggerLowGermlings.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.gadgets.TilePowered; + +public class TriggerLowGermlings extends Trigger { + + private float threshold = 0.25F; + + public TriggerLowGermlings(String tag, float threshold) { + super(tag, "lowGermlings"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + /** + * Return true if the tile given in parameter activates the trigger, given the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + if (!(tile instanceof TilePowered)) + return false; + + return !((TilePowered) tile).hasResourcesMin(threshold); + } + +} diff --git a/forestry_common/core/forestry/core/triggers/TriggerLowResource.java b/forestry_common/core/forestry/core/triggers/TriggerLowResource.java new file mode 100755 index 000000000..a719caa15 --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/TriggerLowResource.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.gadgets.TilePowered; + +public class TriggerLowResource extends Trigger { + + private float threshold = 0.25F; + + public TriggerLowResource(String tag, float threshold) { + super(tag, "lowResources"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + /** + * Return true if the tile given in parameter activates the trigger, given the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + if (!(tile instanceof TilePowered)) + return false; + + return !((TilePowered) tile).hasResourcesMin(threshold); + } + +} diff --git a/forestry_common/core/forestry/core/triggers/TriggerLowSoil.java b/forestry_common/core/forestry/core/triggers/TriggerLowSoil.java new file mode 100755 index 000000000..b78999cd1 --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/TriggerLowSoil.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.gadgets.TilePowered; + +public class TriggerLowSoil extends Trigger { + + private float threshold = 0.25F; + + public TriggerLowSoil(String tag, float threshold) { + super(tag, "lowSoil"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + /** + * Return true if the tile given in parameter activates the trigger, given the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + if (!(tile instanceof TilePowered)) + return false; + + return !((TilePowered) tile).hasFuelMin(threshold); + } + +} diff --git a/forestry_common/core/forestry/core/triggers/TriggerMissingDrone.java b/forestry_common/core/forestry/core/triggers/TriggerMissingDrone.java new file mode 100755 index 000000000..755f7112a --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/TriggerMissingDrone.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.EnumErrorCode; +import forestry.core.interfaces.IErrorSource; + +public class TriggerMissingDrone extends Trigger { + + public TriggerMissingDrone() { + super("missingDrone"); + } + + /** + * Return true if the tile given in parameter activates the trigger, given the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof IErrorSource)) + return false; + + return ((IErrorSource) tile).getErrorState() == EnumErrorCode.NODRONE; + + } + +} diff --git a/forestry_common/core/forestry/core/triggers/TriggerMissingQueen.java b/forestry_common/core/forestry/core/triggers/TriggerMissingQueen.java new file mode 100755 index 000000000..411c6e402 --- /dev/null +++ b/forestry_common/core/forestry/core/triggers/TriggerMissingQueen.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.EnumErrorCode; +import forestry.core.interfaces.IErrorSource; + +public class TriggerMissingQueen extends Trigger { + + public TriggerMissingQueen() { + super("missingQueen"); + } + + /** + * Return true if the tile given in parameter activates the trigger, given the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof IErrorSource)) + return false; + + return ((IErrorSource) tile).getErrorState() == EnumErrorCode.NOQUEEN; + } +} diff --git a/forestry_common/core/forestry/core/utils/BlockUtil.java b/forestry_common/core/forestry/core/utils/BlockUtil.java new file mode 100755 index 000000000..0ccc82e0a --- /dev/null +++ b/forestry_common/core/forestry/core/utils/BlockUtil.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockCocoa; +import net.minecraft.block.BlockLog; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityHopper; +import net.minecraft.util.Direction; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.core.Position; +import buildcraft.api.power.IPowerReceptor; +import buildcraft.api.transport.IPipeConnection; +import buildcraft.api.transport.IPipeConnection.ConnectOverride; +import buildcraft.api.transport.IPipeTile; +import buildcraft.api.transport.IPipeTile.PipeType; + +import forestry.core.config.Defaults; + +public class BlockUtil { + + public static ArrayList getBlockItemStack(World world, Vect posBlock) { + Block block = world.getBlock(posBlock.x, posBlock.y, posBlock.z); + int meta = world.getBlockMetadata(posBlock.x, posBlock.y, posBlock.z); + + return block.getDrops(world, posBlock.x, posBlock.y, posBlock.z, meta, 0); + + } + + /** + * Searches for inventories adjacent to block, excludes IPowerReceptor + * + * @return + */ + public static IInventory[] getAdjacentInventories(World world, Vect blockPos, ForgeDirection from) { + ArrayList inventories = new ArrayList(); + + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + if (from != ForgeDirection.UNKNOWN && from != dir.getOpposite()) + continue; + + TileEntity entity = world.getTileEntity(blockPos.x + dir.offsetX, blockPos.y + dir.offsetY, blockPos.z + dir.offsetZ); + if (entity != null) + if (entity instanceof IInventory) + if (!(entity instanceof TileEntityHopper)) + if (!(entity instanceof IPowerReceptor)) + inventories.add((IInventory) entity); + } + + return inventories.toArray(new IInventory[inventories.size()]); + } + + /** + * Returns a list of adjacent pipes. + * + * @param world + * @param blockPos + * @return + */ + public static ForgeDirection[] getPipeDirections(World world, Vect blockPos, ForgeDirection from) { + LinkedList possiblePipes = new LinkedList(); + + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + if (from != ForgeDirection.UNKNOWN && from != dir.getOpposite()) + continue; + + Position posPipe = new Position(blockPos.x, blockPos.y, blockPos.z, dir); + posPipe.moveForwards(1.0); + + TileEntity pipeEntry = world.getTileEntity((int) posPipe.x, (int) posPipe.y, (int) posPipe.z); + + if (pipeEntry instanceof IPipeTile) { + IPipeTile pipe = (IPipeTile)pipeEntry; + + if (from != ForgeDirection.UNKNOWN && pipeEntry instanceof IPipeConnection) { + if (((IPipeConnection) pipeEntry).overridePipeConnection(PipeType.ITEM, from) != ConnectOverride.DISCONNECT) + possiblePipes.add(dir); + } else if(pipe.getPipeType() == PipeType.ITEM && pipe.isPipeConnected(dir.getOpposite())) + possiblePipes.add(dir); + } + } + + return possiblePipes.toArray(new ForgeDirection[0]); + + } + + public static ArrayList filterPipeDirections(ForgeDirection[] all, ForgeDirection[] exclude) { + ArrayList filtered = new ArrayList(); + ArrayList excludeList = new ArrayList(Arrays.asList(exclude)); + + for (int i = 0; i < all.length; i++) + if (!excludeList.contains(all[i])) + filtered.add(all[i]); + + return filtered; + + } + + public static boolean putFromStackIntoPipe(TileEntity tile, ArrayList pipes, ItemStack stack) { + + if (stack == null) + return false; + if (stack.stackSize <= 0) + return false; + if (pipes.size() <= 0) + return false; + + int choice = tile.getWorldObj().rand.nextInt(pipes.size()); + Position itemPos = new Position(tile.xCoord, tile.yCoord, tile.zCoord, pipes.get(choice)); + + itemPos.x += 0.5; + itemPos.y += 0.25; + itemPos.z += 0.5; + itemPos.moveForwards(0.5); + + Position pipePos = new Position(tile.xCoord, tile.yCoord, tile.zCoord, pipes.get(choice)); + pipePos.moveForwards(1.0); + + IPipeTile pipe = (IPipeTile) tile.getWorldObj().getTileEntity((int) pipePos.x, (int) pipePos.y, (int) pipePos.z); + + ItemStack payload = stack.splitStack(1); + if(pipe.injectItem(payload, true, itemPos.orientation.getOpposite()) > 0) + return true; + else + pipes.remove(choice); + + return false; + } + + public static boolean isPoweredTile(ForgeDirection side, TileEntity tile) { + if (tile == null) + return false; + + if (!(tile instanceof IPowerReceptor)) + return false; + + IPowerReceptor receptor = (IPowerReceptor) tile; + return receptor.getPowerReceiver(side) != null; + } + + public static boolean tryPlantPot(World world, int x, int y, int z, Block block) { + + int direction = getDirectionalMetadata(world, x, y, z); + if (direction < 0) + return false; + + world.setBlock(x, y, z, block, direction, Defaults.FLAG_BLOCK_SYNCH); + return true; + } + + public static int getDirectionalMetadata(World world, int x, int y, int z) { + for (int i = 0; i < 4; i++) { + if (!isValidPot(world, x, y, z, i)) + continue; + return i; + } + return -1; + } + + public static boolean isValidPot(World world, int x, int y, int z, int notchDirection) { + x += Direction.offsetX[notchDirection]; + z += Direction.offsetZ[notchDirection]; + Block block = world.getBlock(x, y, z); + if (block == Blocks.log) + return BlockLog.func_150165_c(world.getBlockMetadata(x, y, z)) == 3; + else + return block.isWood(world, x, y, z); + } + + public static int getMaturityPod(int metadata) { + return BlockCocoa.func_149987_c(metadata); + } +} diff --git a/forestry_common/core/forestry/core/utils/CommandMC.java b/forestry_common/core/forestry/core/utils/CommandMC.java new file mode 100755 index 000000000..b61e915a0 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/CommandMC.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.PlayerNotFoundException; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.World; + +public abstract class CommandMC extends CommandBase { + + protected World getWorld(ICommandSender sender, String[] arguments) { + + // Handle passed in world argument + if (arguments.length > 2) { + int dim = 0; + try { + dim = Integer.parseInt(arguments[1]); + } catch (Exception ex) { + throw new WrongUsageException("/" + getCommandName() + " set [] "); + } + + return MinecraftServer.getServer().worldServerForDimension(dim); + } + + if (sender instanceof EntityPlayer) { + EntityPlayer player = (EntityPlayer) sender; + return player.worldObj; + } else + return MinecraftServer.getServer().worldServerForDimension(0); + + } + + protected EntityPlayer getPlayerFromName(String name) { + EntityPlayerMP player = MinecraftServer.getServer().getConfigurationManager().getPlayerForUsername(name); + + if (player == null) + throw new PlayerNotFoundException(); + else + return player; + } + + protected String[] getPlayers() { + return MinecraftServer.getServer().getAllUsernames(); + } + + protected void sendChatMessage(ICommandSender sender, String message) { + sender.addChatMessage(new ChatComponentText(message)); + } +} diff --git a/forestry_common/core/forestry/core/utils/DamageSourceForestry.java b/forestry_common/core/forestry/core/utils/DamageSourceForestry.java new file mode 100755 index 000000000..d717922f0 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/DamageSourceForestry.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.DamageSource; +import net.minecraft.util.IChatComponent; + +public class DamageSourceForestry extends DamageSource { + + public DamageSourceForestry(String ident) { + super(ident); + setDamageBypassesArmor(); + } + + @Override + public IChatComponent func_151519_b(EntityLivingBase living) { + EntityLivingBase other = living.func_94060_bK(); + String ssp = "death." + this.damageType; + String smp = ssp + ".player"; + + if (other != null) { + return new ChatComponentTranslation(smp, living.func_145748_c_(), other.func_145748_c_()); + } else { + return new ChatComponentTranslation(ssp, living.func_145748_c_()); + } + } + +} diff --git a/forestry_common/core/forestry/core/utils/DelayTimer.java b/forestry_common/core/forestry/core/utils/DelayTimer.java new file mode 100755 index 000000000..f37ac8466 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/DelayTimer.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.world.World; + +public class DelayTimer { + private long markedTime; + + public boolean delayPassed(World world, long delay) { + long currentTime = world.getTotalWorldTime(); + + if (currentTime < markedTime) { + markedTime = currentTime; + return false; + } else if (markedTime + delay <= currentTime) { + markedTime = currentTime; + return true; + } else + return false; + } +} diff --git a/forestry_common/core/forestry/core/utils/EnumAccess.java b/forestry_common/core/forestry/core/utils/EnumAccess.java new file mode 100755 index 000000000..094deaf08 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/EnumAccess.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public enum EnumAccess { + SHARED("gui.rule.shared"), VIEWABLE("gui.rule.restricted"), PRIVATE("gui.rule.private"); + + private final String name; + + @SideOnly(Side.CLIENT) + private IIcon icon; + + private EnumAccess(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + +} diff --git a/forestry_common/core/forestry/core/utils/EnumTankLevel.java b/forestry_common/core/forestry/core/utils/EnumTankLevel.java new file mode 100755 index 000000000..2e3fcf3a4 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/EnumTankLevel.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +public enum EnumTankLevel { + + EMPTY, + + LOW, + + MEDIUM, + + HIGH, + + MAXIMUM +} diff --git a/forestry_common/core/forestry/core/utils/FluidMap.java b/forestry_common/core/forestry/core/utils/FluidMap.java new file mode 100755 index 000000000..9dba21329 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/FluidMap.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +public class FluidMap extends StackMap { + private static final long serialVersionUID = 15891293315299994L; + + @Override + protected boolean areEqual(Fluid a, Object b) { + if (b instanceof FluidStack) + return ((FluidStack) b).getFluid() == a; + if (b instanceof Fluid) + return ((Fluid) b) == a; + if (b instanceof String) + return ((String) b).equals(a.getName()); + return false; + } + + @Override + protected boolean isValidKey(Object key) { + return key instanceof FluidStack || key instanceof Fluid || key instanceof String; + } + + @Override + protected Fluid getStack(Object key) { + if (key instanceof FluidStack) + return ((FluidStack) key).getFluid(); + if (key instanceof Fluid) + return (Fluid) key; + if (key instanceof String) + return FluidRegistry.getFluid((String) key); + return null; + } +} diff --git a/forestry_common/core/forestry/core/utils/FluidStackMap.java b/forestry_common/core/forestry/core/utils/FluidStackMap.java new file mode 100755 index 000000000..57f4cb619 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/FluidStackMap.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +public class FluidStackMap extends StackMap { + private static final long serialVersionUID = -3314134471346370713L; + + @Override + protected boolean areEqual(FluidStack a, Object b) { + + if(b instanceof FluidStack) + return a.isFluidEqual((FluidStack) b); + if(b instanceof Fluid) { + return ((Fluid)b).getID() == a.getFluid().getID(); + } if(b instanceof String) + return ((String)b).equals(a.getFluid().getName()); + return false; + } + + @Override + protected boolean isValidKey(Object key) { + return key instanceof FluidStack || key instanceof Fluid || key instanceof String; + } + + @Override + protected FluidStack getStack(Object key) { + if (key instanceof FluidStack) + return (FluidStack) key; + if (key instanceof Fluid) + return LiquidHelper.getLiquid(((Fluid) key).getName(), 1); + if (key instanceof String) + return LiquidHelper.getLiquid((String) key, 1); + return null; + } + +} diff --git a/forestry_common/core/forestry/core/utils/Fluids.java b/forestry_common/core/forestry/core/utils/Fluids.java new file mode 100755 index 000000000..a1a2d8ac9 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/Fluids.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.Locale; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +/** + * + * @author CovertJaguar + */ +public enum Fluids { + + WATER, LAVA, FUEL, BIOFUEL, CREOSOTE, STEAM; + + public String getTag() { + return name().toLowerCase(Locale.ENGLISH); + } + + public Fluid get() { + return FluidRegistry.getFluid(getTag()); + } + + public FluidStack get(int qty) { + return FluidRegistry.getFluidStack(getTag(), qty); + } + + public boolean is(Fluid fluid) { + return get() == fluid; + } + + public boolean is(FluidStack fluidStack) { + return fluidStack != null && get() == fluidStack.getFluid(); + } + + public boolean isContained(ItemStack containerStack) { + return containerStack != null && LiquidHelper.containsFluid(containerStack, Fluids.WATER.get()); + } + + public static boolean areEqual(Fluid fluid, FluidStack fluidStack){ + if(fluidStack != null && fluid == fluidStack.getFluid()) + return true; + return fluid == null && fluidStack == null; + } +} diff --git a/forestry_common/core/forestry/core/utils/FontColour.java b/forestry_common/core/forestry/core/utils/FontColour.java new file mode 100755 index 000000000..56f844765 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/FontColour.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.io.InputStream; +import java.util.Properties; + +import net.minecraft.client.resources.IResourceManager; + +public class FontColour { + + //private static final ResourceLocation colourDefinitions = new ForestryResource("/config/forestry/colour.properties"); + + private final Properties defaultMappings = new Properties(); + private final Properties mappings = new Properties(); + + public FontColour(IResourceManager texturepack) { + load(texturepack); + } + + public synchronized int get(String key) { + return Integer.parseInt(mappings.getProperty(key, defaultMappings.getProperty(key, "d67fff")), 16); + } + + public void load(IResourceManager texturepack) { + try { + //InputStream fontStream = texturepack.func_110536_a(colourDefinitions).func_110527_b(); + InputStream defaultFontStream = FontColour.class.getResourceAsStream("/config/forestry/colour.properties"); + //mappings.load((fontStream == null) ? defaultFontStream : fontStream); + mappings.load(defaultFontStream); + defaultMappings.load(defaultFontStream); + + //if (fontStream != null) + // fontStream.close(); + defaultFontStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + +} diff --git a/forestry_common/core/forestry/core/utils/ForestryModEnvWarningCallable.java b/forestry_common/core/forestry/core/utils/ForestryModEnvWarningCallable.java new file mode 100755 index 000000000..626d50eca --- /dev/null +++ b/forestry_common/core/forestry/core/utils/ForestryModEnvWarningCallable.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.ArrayList; +import java.util.List; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.ICrashCallable; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.relauncher.Side; + +import forestry.core.config.Defaults; + +public class ForestryModEnvWarningCallable implements ICrashCallable { + + private final List modIDs; + + public ForestryModEnvWarningCallable() { + this.modIDs = new ArrayList(); + + if (FMLCommonHandler.instance().getSide() == Side.CLIENT && FMLClientHandler.instance().hasOptifine()) { + modIDs.add("Optifine"); + } + + if (Loader.isModLoaded("gregtech_addon")) { + modIDs.add("GregTech"); + } + + try { + @SuppressWarnings("unused") + Class c = Class.forName("org.bukkit.Bukkit"); + modIDs.add("Bukkit, MCPC+, or other Bukkit replacement"); + } + catch (Throwable t) {} // No need to do anything. + + // Add other bad mods here. + + if (modIDs.size() > 0) { + FMLCommonHandler.instance().registerCrashCallable(this); + } + } + + @Override + public String call() throws Exception { + String message = "[" + Defaults.MOD + "] Warning: You have mods that change the behavior of Minecraft, ForgeModLoader, and/or Minecraft Forge to your client: \r\n"; + message = message + modIDs.get(0); + for (int i = 1; i < modIDs.size(); ++i) { + message = message + ", " + modIDs.get(i); + } + message = message + "\r\nThese may have caused this error, and may not be supported. Try reproducing the crash WITHOUT these mods, and report it then."; + return message; + } + + @Override + public String getLabel() { + return Defaults.MOD + " "; + } + +} diff --git a/forestry_common/core/forestry/core/utils/ForestryResource.java b/forestry_common/core/forestry/core/utils/ForestryResource.java new file mode 100755 index 000000000..e17864b1b --- /dev/null +++ b/forestry_common/core/forestry/core/utils/ForestryResource.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.util.ResourceLocation; + +import forestry.core.config.Defaults; + +public class ForestryResource extends ResourceLocation { + + public ForestryResource(String path) { + super(Defaults.ID, path); + } + +} diff --git a/forestry_common/core/forestry/core/utils/ForestryTank.java b/forestry_common/core/forestry/core/utils/ForestryTank.java new file mode 100755 index 000000000..378a1739d --- /dev/null +++ b/forestry_common/core/forestry/core/utils/ForestryTank.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.Locale; + +import net.minecraft.item.EnumRarity; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.fluids.FluidTankInfo; + +import forestry.core.config.Config; +import forestry.core.gui.tooltips.ToolTip; +import forestry.core.gui.tooltips.ToolTipLine; + +public class ForestryTank extends FluidTank { + + public static final ForestryTank FAKETANK = new ForestryTank(0); + public static final ForestryTank[] FAKETANK_ARRAY = new ForestryTank[] { FAKETANK }; + public static final FluidTankInfo DUMMY_TANK_INFO = new FluidTankInfo(FAKETANK); + public static final FluidTankInfo[] DUMMY_TANKINFO_ARRAY = new FluidTankInfo[] { DUMMY_TANK_INFO }; + + public ForestryTank(FluidStack stack, int capacity) { + super(stack, capacity); + } + + public ForestryTank(int capacity) { + super(capacity); + } + + public ForestryTank(Fluid fluid, int amount, int capacity) { + super(fluid, amount, capacity); + } + + public boolean isEmpty() { + return getFluid() == null || getFluid().amount <= 0; + } + + public boolean isFull() { + return getFluid() != null && getFluid().amount == getCapacity(); + } + + public Fluid getFluidType() { + return getFluid() != null ? getFluid().getFluid() : null; + } + + @Override + public String toString() { + return String.format("Tank: %s, %d/%d", fluid != null && fluid.getFluid() != null ? fluid.getFluid().getName() : "Empty", getFluidAmount(), getCapacity()); + } + + public ToolTip getToolTip() { + return toolTip; + } + protected final ToolTip toolTip = new ToolTip() { + @Override + public void refresh() { + toolTip.clear(); + int amount = 0; + if (getFluid() != null && getFluid().amount > 0 && getFluid().getFluid() != null) { + Fluid fluidType = getFluidType(); + EnumRarity rarity = fluidType.getRarity(); + if (rarity == null) + rarity = EnumRarity.common; + ToolTipLine fluidName = new ToolTipLine(fluidType.getLocalizedName(), rarity.rarityColor); + fluidName.setSpacing(2); + toolTip.add(fluidName); + amount = getFluid().amount; + } else { + toolTip.add(new ToolTipLine(StringUtil.localize("gui.empty"))); + } + if (Config.tooltipLiquidAmount) + toolTip.add(new ToolTipLine(String.format(Locale.ENGLISH, "%,d / %,d", amount, getCapacity()))); + } + }; +} diff --git a/forestry_common/core/forestry/core/utils/IDAllocator.java b/forestry_common/core/forestry/core/utils/IDAllocator.java new file mode 100755 index 000000000..8220e1b20 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/IDAllocator.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; +import net.minecraft.world.WorldSavedData; + +public class IDAllocator extends WorldSavedData { + + public static String SAVE_NAME = "IDAlloc"; + + public static IDAllocator cachedIDAllocator; + + private final int maxId = 2048; + + public static IDAllocator getIDAllocator(World world, String type) { + if (cachedIDAllocator != null) + return cachedIDAllocator; + + IDAllocator allocator = (IDAllocator) world.loadItemData(IDAllocator.class, SAVE_NAME + "." + type); + if (allocator == null) { + allocator = new IDAllocator(SAVE_NAME + "." + type); + world.setItemData(SAVE_NAME + type, allocator); + } + + cachedIDAllocator = allocator; + return allocator; + } + + public IDAllocator(String par1Str) { + super(par1Str); + } + + public HashMap idMap = new HashMap(); + + public int getId(String uid) { + if (idMap.containsKey(uid)) + return idMap.get(uid); + + for (int i = 0; i < maxId; i++) + if (!idMap.containsValue(i)) { + idMap.put(uid, i); + this.markDirty(); + return i; + } + + throw new RuntimeException("No ids left for the type: " + uid); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = nbttagcompound.getTagList("IdMap", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound subcompound = nbttaglist.getCompoundTagAt(i); + idMap.put(subcompound.getString("UID"), subcompound.getInteger("Id")); + } + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = new NBTTagList(); + Iterator> it = idMap.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + NBTTagCompound subcompound = new NBTTagCompound(); + subcompound.setString("UID", entry.getKey()); + subcompound.setInteger("Id", entry.getValue()); + nbttaglist.appendTag(subcompound); + } + nbttagcompound.setTag("IdMap", nbttaglist); + + } + +} diff --git a/forestry_common/core/forestry/core/utils/InventoryAdapter.java b/forestry_common/core/forestry/core/utils/InventoryAdapter.java new file mode 100755 index 000000000..44be03633 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/InventoryAdapter.java @@ -0,0 +1,391 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import forestry.api.core.INBTTagable; +import forestry.core.config.Defaults; + +/** + * With permission from Krapht. + */ +public class InventoryAdapter implements IInventory, INBTTagable { + + private IInventory inventory = null; + //private boolean debug = false; + + public InventoryAdapter(int size, String name) { + this(size, name, 64); + } + + public InventoryAdapter(int size, String name, int stackLimit) { + this(new PlainInventory(size, name, stackLimit)); + } + + public InventoryAdapter(IInventory inventory) { + this.inventory = inventory; + configureSided(); + } + + /* + public InventoryAdapter enableDebug() { + this.debug = true; + return this; + } + */ + + /** + * @return Copy of this inventory. Stacks are copies. + */ + public InventoryAdapter copy() { + InventoryAdapter copy = new InventoryAdapter(inventory.getSizeInventory(), inventory.getInventoryName(), inventory.getInventoryStackLimit()); + + for (int i = 0; i < inventory.getSizeInventory(); i++) + if (inventory.getStackInSlot(i) != null) + copy.setInventorySlotContents(i, inventory.getStackInSlot(i).copy()); + + return copy; + } + + public ItemStack[] getStacks() { + ItemStack[] stacks = new ItemStack[inventory.getSizeInventory()]; + for(int i = 0; i < inventory.getSizeInventory(); i++) + stacks[i] = inventory.getStackInSlot(i); + return stacks; + } + + public ItemStack[] getStacks(int slot1, int length) { + ItemStack[] result = new ItemStack[length]; + for(int i = slot1; i < slot1 + length; i++) + result[i - slot1] = inventory.getStackInSlot(i); + return result; + } + + public boolean tryAddStacksCopy(ItemStack[] stacks, boolean all) { + + boolean addedAll = true; + for (ItemStack stack : stacks) { + if (stack == null) + continue; + + if (!tryAddStack(stack.copy(), all)) + addedAll = false; + } + + return addedAll; + } + + public boolean tryAddStacks(ItemStack[] stacks, boolean all) { + + boolean addedAll = true; + for (ItemStack stack : stacks) { + if (stack == null) + continue; + + if (!tryAddStack(stack, all)) + addedAll = false; + } + + return addedAll; + } + + public boolean tryAddStack(ItemStack stack, boolean all) { + return tryAddStack(stack, 0, this.getSizeInventory(), all); + } + + /** + * Tries to add a stack to the specified slot range. + * + * @param stack + * @param startSlot + * @param slots + * @param all + * @return + */ + public boolean tryAddStack(ItemStack stack, int startSlot, int slots, boolean all) { + return tryAddStack(stack, startSlot, slots, all, true); + } + + public boolean tryAddStack(ItemStack stack, int startSlot, int slots, boolean all, boolean doAdd) { + return addStack(stack, startSlot, slots, all, doAdd) > 0; + } + + public int addStack(ItemStack stack, boolean all, boolean doAdd) { + return addStack(stack, 0, this.getSizeInventory(), all, doAdd); + } + + public int addStack(ItemStack stack, int startSlot, int slots, boolean all, boolean doAdd) { + + int added = 0; + // Add to existing stacks first + for (int i = startSlot; i < startSlot + slots; i++) { + + // Empty slot. Add + if (inventory.getStackInSlot(i) == null) + continue; + + // Already occupied by different item, skip this slot. + if (!inventory.getStackInSlot(i).isItemEqual(stack)) + continue; + if (!ItemStack.areItemStackTagsEqual(inventory.getStackInSlot(i), stack)) + continue; + + int remain = stack.stackSize - added; + int space = inventory.getStackInSlot(i).getMaxStackSize() - inventory.getStackInSlot(i).stackSize; + // No space left, skip this slot. + if (space <= 0) + continue; + // Enough space + if (space >= remain) { + if (doAdd) + inventory.getStackInSlot(i).stackSize += remain; + return stack.stackSize; + } + + // Not enough space + if (doAdd) + inventory.getStackInSlot(i).stackSize = inventory.getStackInSlot(i).getMaxStackSize(); + + added += space; + } + + if (added >= stack.stackSize) + return added; + + for (int i = startSlot; i < startSlot + slots; i++) { + if (inventory.getStackInSlot(i) != null) + continue; + + if (doAdd) { + setInventorySlotContents(i, stack.copy()); + inventory.getStackInSlot(i).stackSize = stack.stackSize - added; + } + return stack.stackSize; + + } + + return added; + + } + + /* CONTAINS */ + public boolean contains(ItemStack[] query, int startSlot, int slots) { + for (ItemStack queried : query) { + + int itemCount = 0; + for (int i = startSlot; i < startSlot + slots; i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack == null) + continue; + + if (StackUtils.equals(Blocks.air, queried)) { + itemCount += stack.stackSize; + continue; + } + if (queried.getItemDamage() < 0) { + + if (stack.getItem() == queried.getItem()) + itemCount += stack.stackSize; + continue; + } + + if (stack.isItemEqual(queried) && ItemStack.areItemStackTagsEqual(stack, queried)) + itemCount += stack.stackSize; + } + + if (itemCount < queried.stackSize) + return false; + + } + + return true; + } + + /* REMOVAL */ + public void removeResources(ItemStack[] query, int startSlot, int slots) { + for (ItemStack queried : query) { + + ItemStack remain = queried.copy(); + + for (int i = startSlot; i < startSlot + slots; i++) { + ItemStack stack = inventory.getStackInSlot(i); + + if (stack == null) + continue; + + if (queried.getItemDamage() < 0) { + + if (stack.getItem() == queried.getItem()) { + ItemStack removed = decrStackSize(i, remain.stackSize); + remain.stackSize -= removed.stackSize; + } + + } else if (stack.isItemEqual(remain) && ItemStack.areItemStackTagsEqual(stack, remain)) { + ItemStack removed = decrStackSize(i, remain.stackSize); + remain.stackSize -= removed.stackSize; + } + + if (remain.stackSize <= 0) + break; + } + + } + + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int slotId) { + return inventory.getStackInSlot(slotId); + } + + @Override + public ItemStack decrStackSize(int slotId, int count) { + return inventory.decrStackSize(slotId, count); + } + + @Override + public void setInventorySlotContents(int slotId, ItemStack itemstack) { + inventory.setInventorySlotContents(slotId, itemstack); + } + + @Override + public String getInventoryName() { + return inventory.getInventoryName(); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void markDirty() { + inventory.markDirty(); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slotIndex) { + return inventory.getStackInSlotOnClosing(slotIndex); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return false; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /* ISIDEDINVENTORY */ + private int[][] slotMap; + + public int[] getSizeInventorySide(int side) { + return slotMap[side]; + } + + private void configureSided() { + slotMap = new int[6][0]; + configureSided(Defaults.FACINGS, 0, getSizeInventory()); + } + + public InventoryAdapter configureSidedUp(int startSlot, int count) { + return configureSided(Defaults.FACING_UP, startSlot, count); + } + + public InventoryAdapter configureSidedDown(int startSlot, int count) { + return configureSided(Defaults.FACING_DOWN, startSlot, count); + } + + public InventoryAdapter configureSidedNorthSouth(int startSlot, int count) { + return configureSided(Defaults.FACING_NORTHSOUTH, startSlot, count); + } + + public InventoryAdapter configureSidedWestEast(int startSlot, int count) { + return configureSided(Defaults.FACING_WESTEAST, startSlot, count); + } + + public InventoryAdapter configureSidedSides(int startSlot, int count) { + return configureSided(Defaults.FACING_SIDES, startSlot, count); + } + + public InventoryAdapter configureSided(int side, int startSlot, int count) { + return configureSided(new int[] { side }, startSlot, count); + } + + public InventoryAdapter configureSided(int[] sides, int startSlot, int count) { + int[] slots = new int[count]; + for(int i = 0; i < count; i++) + slots[i] = startSlot + i; + + return configureSided(sides, slots); + } + + public InventoryAdapter configureSided(int[] sides, int[] slots) { + for(int side : sides) + slotMap[side] = slots; + + return this; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + if (!nbttagcompound.hasKey(inventory.getInventoryName())) + return; + + NBTTagList nbttaglist = nbttagcompound.getTagList(inventory.getInventoryName(), 10); + + for (int j = 0; j < nbttaglist.tagCount(); ++j) { + NBTTagCompound nbttagcompound2 = nbttaglist.getCompoundTagAt(j); + int index = nbttagcompound2.getByte("Slot"); + inventory.setInventorySlotContents(index, ItemStack.loadItemStackFromNBT(nbttagcompound2)); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + NBTTagList nbttaglist = new NBTTagList(); + for (int i = 0; i < inventory.getSizeInventory(); i++) + if (inventory.getStackInSlot(i) != null) { + NBTTagCompound nbttagcompound2 = new NBTTagCompound(); + nbttagcompound2.setByte("Slot", (byte) i); + inventory.getStackInSlot(i).writeToNBT(nbttagcompound2); + nbttaglist.appendTag(nbttagcompound2); + } + nbttagcompound.setTag(inventory.getInventoryName(), nbttaglist); + } + +} diff --git a/forestry_common/core/forestry/core/utils/ItemInventory.java b/forestry_common/core/forestry/core/utils/ItemInventory.java new file mode 100755 index 000000000..4031fd5c2 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/ItemInventory.java @@ -0,0 +1,221 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import forestry.api.core.INBTTagable; + +public class ItemInventory implements IInventory, INBTTagable { + + public final Class itemClass; + public boolean isItemInventory = false; + public ItemStack parent; + protected ItemStack[] inventoryStacks; + + protected ItemInventory(Class itemClass) { + this.itemClass = itemClass; + } + + public ItemInventory(Class itemClass, int slots) { + this(itemClass); + inventoryStacks = new ItemStack[slots]; + } + + public ItemInventory(Class itemClass, int size, ItemStack itemstack) { + this(itemClass, size); + + parent = itemstack; + isItemInventory = true; + + // Set an uid to identify the itemstack on SMP + setUID(true); + + readFromNBT(itemstack.getTagCompound()); + } + + protected void setUID(boolean override) { + if (parent.getTagCompound() == null) + parent.setTagCompound(new NBTTagCompound()); + + NBTTagCompound nbt = parent.getTagCompound(); + if (override || !nbt.hasKey("UID")) { + nbt.setInteger("UID", Utils.getUID()); + } + } + + public void onGuiSaved(EntityPlayer player) { + parent = findParent(player); + if (parent != null) + save(); + } + + public ItemStack findParent(EntityPlayer player) { + if (parent == null) + return null; + + NBTTagCompound parentNBT = parent.getTagCompound(); + if (parentNBT == null) + return null; + + int uid = parentNBT.getInteger("UID"); + + for (int i = 0; i < player.inventory.getSizeInventory(); i++) { + ItemStack stack = player.inventory.getStackInSlot(i); + if (stack == null) + continue; + if(stack.getItem() != parent.getItem()) + continue; + NBTTagCompound slotNBT = stack.getTagCompound(); + if (slotNBT == null) + continue; + if (uid == slotNBT.getInteger("UID")) + return player.inventory.getStackInSlot(i); + } + return null; + } + + public boolean matchesUID(int otherId) { + if (parent == null) + return false; + + NBTTagCompound nbt = parent.getTagCompound(); + if (nbt == null) + return false; + + int uid = nbt.getInteger("UID"); + return uid == otherId; + } + + public void save() { + NBTTagCompound nbt = parent.getTagCompound(); + if (nbt == null) + nbt = new NBTTagCompound(); + writeToNBT(nbt); + parent.setTagCompound(nbt); + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + + if (nbt == null) + return; + + if (nbt.hasKey("Items")) { + NBTTagList nbttaglist = nbt.getTagList("Items", 10); + inventoryStacks = new ItemStack[getSizeInventory()]; + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + byte byte0 = nbttagcompound1.getByte("Slot"); + if (byte0 >= 0 && byte0 < inventoryStacks.length) + inventoryStacks[byte0] = ItemStack.loadItemStackFromNBT(nbttagcompound1); + } + } + + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + + NBTTagList nbttaglist = new NBTTagList(); + for (int i = 0; i < inventoryStacks.length; i++) + if (inventoryStacks[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + inventoryStacks[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbt.setTag("Items", nbttaglist); + + } + + @Override + public ItemStack decrStackSize(int i, int j) { + if (inventoryStacks[i] == null) + return null; + + ItemStack product; + if (inventoryStacks[i].stackSize <= j) { + product = inventoryStacks[i]; + inventoryStacks[i] = null; + return product; + } else { + product = inventoryStacks[i].splitStack(j); + if (inventoryStacks[i].stackSize == 0) + inventoryStacks[i] = null; + + return product; + } + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventoryStacks[i] = itemstack; + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventoryStacks[i]; + } + + @Override + public int getSizeInventory() { + return inventoryStacks.length; + } + + @Override + public String getInventoryName() { + return "BeeBag"; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public void markDirty() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + if (inventoryStacks[slot] == null) + return null; + ItemStack toReturn = inventoryStacks[slot]; + inventoryStacks[slot] = null; + return toReturn; + } +} diff --git a/forestry_common/core/forestry/core/utils/ItemStackMap.java b/forestry_common/core/forestry/core/utils/ItemStackMap.java new file mode 100755 index 000000000..985867eb0 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/ItemStackMap.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.oredict.OreDictionary; + +public class ItemStackMap extends StackMap { + private static final long serialVersionUID = -8511966739130702305L; + + @Override + protected boolean areEqual(ItemStack a, Object b) { + if(b instanceof ItemStack) { + ItemStack b2 = (ItemStack) b; + return a.isItemEqual(b2) && ItemStack.areItemStackTagsEqual(a, b2); + } + if(b instanceof Item) { + return a.getItem() == (Item) b; + } + if(b instanceof String) { + for(ItemStack stack : OreDictionary.getOres((String) b)) { + if(areEqual(a, stack)) return true; + } + } + return false; + } + + @Override + protected boolean isValidKey(Object key) { + return key instanceof ItemStack || key instanceof Item || key instanceof String; + } + + @Override + protected ItemStack getStack(Object key) { + if(key instanceof ItemStack) + return (ItemStack) key; + return null; + } + +} diff --git a/forestry_common/core/forestry/core/utils/LiquidHelper.java b/forestry_common/core/forestry/core/utils/LiquidHelper.java new file mode 100755 index 000000000..c24149b24 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/LiquidHelper.java @@ -0,0 +1,266 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.HashMap; +import java.util.LinkedList; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.common.registry.LanguageRegistry; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidHandler; + +import forestry.api.recipes.RecipeManagers; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.render.TextureManager; + +public class LiquidHelper { + + private static LinkedList myLiquids = new LinkedList(); + private static HashMap liquidMap = new HashMap(); + + public static boolean isEmptyLiquidData() { + return FluidContainerRegistry.getRegisteredFluidContainerData().length <= 0; + } + + public static boolean isEmptyContainer(ItemStack empty) { + return FluidContainerRegistry.isEmptyContainer(empty); + } + + public static FluidContainerData getEmptyContainer(ItemStack empty, FluidStack liquid) { + for (FluidContainerData cont : FluidContainerRegistry.getRegisteredFluidContainerData()) { + if (cont.fluid.isFluidEqual(liquid) && (cont.emptyContainer != null && cont.emptyContainer.isItemEqual(empty))) + return cont; + } + + return null; + } + + public static FluidContainerData getLiquidContainer(ItemStack container) { + for (FluidContainerData cont : FluidContainerRegistry.getRegisteredFluidContainerData()) { + if (cont.filledContainer.isItemEqual(container)) + return cont; + } + return null; + } + + public static FluidContainerData createLiquidData(String ident, FluidStack stillLiquid, ItemStack filled, ItemStack container) { + return new FluidContainerData(new FluidStack(getOrCreateLiquid(ident), Defaults.BUCKET_VOLUME), filled, container); + } + + public static boolean isLiquid(String ident, FluidStack stack) { + return FluidRegistry.getFluidID(ident) == stack.fluidID; + } + + public static boolean exists(String ident) { + return FluidRegistry.isFluidRegistered(ident); + } + + public static Fluid getFluid(String ident) { + Fluid fluid = FluidRegistry.getFluid(ident); + return fluid; + } + + public static Fluid getOrCreateLiquid(String ident) { + if (!FluidRegistry.isFluidRegistered(ident)) { + Fluid fluid = new Fluid(ident); + LanguageRegistry.instance().addStringLocalization(fluid.getUnlocalizedName(), Localization.instance.get(fluid.getUnlocalizedName())); + FluidRegistry.registerFluid(fluid); + myLiquids.add(ident); + } + liquidMap.put(ident, FluidRegistry.getFluid(ident)); + return FluidRegistry.getFluid(ident); + } + + public static FluidStack getLiquid(String name, int amount) { + return FluidRegistry.getFluidStack(name, amount); + } + + public static void injectLiquidContainer(String name, int volume, ItemStack filled, ItemStack empty) { + injectLiquidContainer(name, volume, filled, empty, null, 0); + } + + public static void injectWaxContainer(String name, int volume, ItemStack filled, ItemStack empty) { + injectLiquidContainer(name, volume, filled, empty, ForestryItem.beeswax.getItemStack(), 10); + } + + public static void injectRefractoryContainer(String name, int volume, ItemStack filled, ItemStack empty) { + injectLiquidContainer(name, volume, filled, empty, ForestryItem.refractoryWax.getItemStack(), 10); + } + + public static void injectTinContainer(String name, int volume, ItemStack filled, ItemStack empty) { + injectLiquidContainer(name, volume, filled, empty, ForestryItem.ingotTin.getItemStack(), 5); + } + + public static void injectLiquidContainer(String name, int volume, ItemStack filled, ItemStack empty, ItemStack remnant, int chance) { + FluidStack contained = getLiquid(name, volume); + if (contained == null) + throw new IllegalArgumentException(String.format("Attempted to inject a liquid container for the non-existent liquid '%s'.", name)); + + FluidContainerData container = new FluidContainerData(contained, filled, empty); + FluidContainerRegistry.registerFluidContainer(container); + + if (RecipeManagers.squeezerManager != null) + if (!container.filledContainer.getItem().hasContainerItem(container.filledContainer)) + if (remnant != null) + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { container.filledContainer }, container.fluid, remnant, chance); + else + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { container.filledContainer }, container.fluid); + } + + public static void resetLiquidIcons(IIconRegister register) { + for (String fluidString : myLiquids) { + Fluid fluid = getFluid(fluidString); + IIcon icon = TextureManager.getInstance().registerTex(register, "liquid/" + fluid.getName()); + fluid.setIcons(icon); + + } + } + + public static boolean handleRightClick(IFluidHandler tank, ForgeDirection side, EntityPlayer player, boolean fill, boolean drain) { + if (player == null) { + return false; + } + ItemStack current = player.inventory.getCurrentItem(); + if (current != null) { + + FluidStack liquid = FluidContainerRegistry.getFluidForFilledItem(current); + + if (fill && liquid != null) { + int used = tank.fill(side, liquid, true); + + if (used > 0) { + if (!player.capabilities.isCreativeMode) { + player.inventory.setInventorySlotContents(player.inventory.currentItem, StackUtils.consumeItem(current)); + player.inventory.markDirty(); + } + return true; + } + + } else if (drain) { + + FluidStack available = tank.drain(side, Integer.MAX_VALUE, false); + if (available != null) { + ItemStack filled = FluidContainerRegistry.fillFluidContainer(available, current); + + liquid = FluidContainerRegistry.getFluidForFilledItem(filled); + if (liquid != null) { + + if (current.stackSize > 1) { + if (!player.inventory.addItemStackToInventory(filled)) + return false; + player.inventory.setInventorySlotContents(player.inventory.currentItem, StackUtils.consumeItem(current)); + player.inventory.markDirty(); + } else { + player.inventory.setInventorySlotContents(player.inventory.currentItem, StackUtils.consumeItem(current)); + player.inventory.setInventorySlotContents(player.inventory.currentItem, filled); + player.inventory.markDirty(); + } + + tank.drain(side, liquid.amount, true); + return true; + } + } + } + } + return false; + } + + public static void processContainers(IFluidHandler fluidHandler, IInventory inv, int inputSlot, int outputSlot, Fluid fluidToFill, boolean processFilled, boolean processEmpty) { + ItemStack input = inv.getStackInSlot(inputSlot); + + if (input == null) + return; + + if (processFilled && drainContainers(fluidHandler, inv, inputSlot, outputSlot)) + return; + + if (processEmpty && fluidToFill != null) + fillContainers(fluidHandler, inv, inputSlot, outputSlot, fluidToFill); + } + + public static boolean fillContainers(IFluidHandler fluidHandler, IInventory inv, int inputSlot, int outputSlot, Fluid fluidToFill) { + return fillContainers(fluidHandler, inv, inputSlot, outputSlot, fluidToFill, true); + } + + public static boolean fillContainers(IFluidHandler fluidHandler, IInventory inv, int inputSlot, int outputSlot, Fluid fluidToFill, boolean doFill) { + ItemStack input = inv.getStackInSlot(inputSlot); + ItemStack output = inv.getStackInSlot(outputSlot); + ItemStack filled = getFilledContainer(fluidToFill, input); + if (filled != null && (output == null || (output.stackSize < output.getMaxStackSize() && StackUtils.isIdenticalItem(filled, output)))) { + FluidStack fluidInContainer = getFluidStackInContainer(filled); + FluidStack drain = fluidHandler.drain(ForgeDirection.UNKNOWN, fluidInContainer, false); + if (drain != null && drain.amount == fluidInContainer.amount) { + if (doFill) { + fluidHandler.drain(ForgeDirection.UNKNOWN, fluidInContainer, true); + if (output == null) + inv.setInventorySlotContents(outputSlot, filled); + else + output.stackSize++; + inv.decrStackSize(inputSlot, 1); + } + return true; + } + } + return false; + } + + public static boolean drainContainers(IFluidHandler fluidHandler, IInventory inv, int inputSlot, int outputSlot) { + ItemStack input = inv.getStackInSlot(inputSlot); + ItemStack output = inv.getStackInSlot(outputSlot); + + if (input != null) { + FluidStack fluidInContainer = getFluidStackInContainer(input); + ItemStack emptyItem = input.getItem().getContainerItem(input); + if (fluidInContainer != null && (emptyItem == null || output == null || (output.stackSize < output.getMaxStackSize() && StackUtils.isIdenticalItem(output, emptyItem)))) { + int used = fluidHandler.fill(ForgeDirection.UNKNOWN, fluidInContainer, false); + if (used >= fluidInContainer.amount) { + fluidHandler.fill(ForgeDirection.UNKNOWN, fluidInContainer, true); + if (emptyItem != null) + if (output == null) + inv.setInventorySlotContents(outputSlot, emptyItem); + else + output.stackSize++; + inv.decrStackSize(inputSlot, 1); + return true; + } + } + } + return false; + } + + public static ItemStack getFilledContainer(Fluid fluid, ItemStack empty) { + if (fluid == null || empty == null) + return null; + return FluidContainerRegistry.fillFluidContainer(new FluidStack(fluid, Integer.MAX_VALUE), empty); + } + + public static FluidStack getFluidStackInContainer(ItemStack stack) { + return FluidContainerRegistry.getFluidForFilledItem(stack); + } + + public static boolean containsFluidStack(ItemStack stack, FluidStack fluidStack) { + return FluidContainerRegistry.containsFluid(stack, fluidStack); + } + + public static boolean containsFluid(ItemStack stack, Fluid fluid) { + return FluidContainerRegistry.containsFluid(stack, new FluidStack(fluid, 1)); + } +} diff --git a/forestry_common/core/forestry/core/utils/Localization.java b/forestry_common/core/forestry/core/utils/Localization.java new file mode 100755 index 000000000..8cffa4970 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/Localization.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.io.InputStream; +import java.util.LinkedList; +import java.util.Properties; + +import forestry.core.proxy.Proxies; + +/** + * Simple mod localization class. + * + * @author Jimeo Wan / modified for Forestry by SirSengir + * @license Public domain + */ +public class Localization { + + public static Localization instance = new Localization(); + + private static final String DEFAULT_LANGUAGE = "en_US"; + + private String loadedLanguage = null; + private Properties defaultMappings = new Properties(); + private Properties mappings = new Properties(); + private LinkedList modules = new LinkedList(); + + /** + * Loads the mod's localization files. All language files must be stored in "[modname]/lang/", in .properties files. (ex: for the mod 'invtweaks', the + * french translation is in: "invtweaks/lang/fr_FR.properties") + * + * @param modName + * The mod name + */ + public Localization() { + addLocalization("/lang/forestry/core/"); + } + + public void addLocalization(String path) { + modules.add(path); + load(path, DEFAULT_LANGUAGE); + } + + private void load(String newLanguage) { + defaultMappings.clear(); + mappings.clear(); + + for (String path : this.modules) + load(path, newLanguage); + } + + private void load(String path, String newLanguage) { + + Properties modMappings = new Properties(); + + try { + InputStream langStream = Localization.class.getResourceAsStream(path + newLanguage + ".properties"); + InputStream defaultLangStream = Localization.class.getResourceAsStream(path + DEFAULT_LANGUAGE + ".properties"); + modMappings.load((langStream == null) ? defaultLangStream : langStream); + mappings.putAll(modMappings); + + modMappings.clear(); + modMappings.load(defaultLangStream); + defaultMappings.putAll(modMappings); + + if (langStream != null) + langStream.close(); + defaultLangStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + loadedLanguage = newLanguage; + } + + /** + * Get a string for the given key, in the currently active translation. + * + * @param key + * @return + */ + public synchronized String get(String key) { + String currentLanguage = getCurrentLanguage(); + if (currentLanguage == null || !currentLanguage.equals(loadedLanguage)) + load(currentLanguage); + + return mappings.getProperty(key, defaultMappings.getProperty(key, key)); + } + + public boolean hasMapping(String key) { + return mappings.containsKey(key) || defaultMappings.containsKey(key); + } + + private static String getCurrentLanguage() { + return Proxies.common.getCurrentLanguage(); + } + +} diff --git a/forestry_common/core/forestry/core/utils/PlainInventory.java b/forestry_common/core/forestry/core/utils/PlainInventory.java new file mode 100755 index 000000000..ea9e2754b --- /dev/null +++ b/forestry_common/core/forestry/core/utils/PlainInventory.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +public class PlainInventory implements IInventory { + + private final ItemStack[] contents; + private final String name; + private final int stackLimit; + + public PlainInventory(int size, String name) { + this(size, name, 64); + } + + public PlainInventory(int size, String name, int stackLimit) { + this.contents = new ItemStack[size]; + this.name = name; + this.stackLimit = stackLimit; + } + + public PlainInventory(IInventory tocopy) { + this(tocopy.getSizeInventory(), tocopy.getInventoryName(), tocopy.getInventoryStackLimit()); + for (int i = 0; i < tocopy.getSizeInventory(); i++) { + if (tocopy.getStackInSlot(i) != null) + this.setInventorySlotContents(i, tocopy.getStackInSlot(i).copy()); + else + this.setInventorySlotContents(i, null); + } + } + + public ItemStack[] getContents() { + return contents; + } + + @Override + public int getSizeInventory() { + return contents.length; + } + + @Override + public ItemStack getStackInSlot(int slotId) { + return contents[slotId]; + } + + @Override + public ItemStack decrStackSize(int slotId, int count) { + if (contents[slotId] == null) + return null; + if (contents[slotId].stackSize > count) + return contents[slotId].splitStack(count); + ItemStack stack = contents[slotId]; + contents[slotId] = null; + return stack; + } + + @Override + public void setInventorySlotContents(int slotId, ItemStack itemstack) { + contents[slotId] = itemstack; + } + + @Override + public String getInventoryName() { + return name; + } + + @Override + public int getInventoryStackLimit() { + return stackLimit; + } + + @Override + public void markDirty() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return false; + } + + @Override + public ItemStack getStackInSlotOnClosing(int slotIndex) { + return this.getStackInSlot(slotIndex); + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } +} diff --git a/forestry_common/core/forestry/core/utils/RecipeUtil.java b/forestry_common/core/forestry/core/utils/RecipeUtil.java new file mode 100755 index 000000000..ce95cad57 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/RecipeUtil.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.item.ItemStack; + +import forestry.api.recipes.RecipeManagers; +import forestry.core.config.Defaults; +import forestry.core.interfaces.IDescriptiveRecipe; +import forestry.core.proxy.Proxies; + +public class RecipeUtil { + + public static void injectLeveledRecipe(ItemStack resource, int fermentationValue, String output) { + if (RecipeManagers.fermenterManager == null) + return; + + RecipeManagers.fermenterManager.addRecipe(resource, fermentationValue, 1.0f, LiquidHelper.getLiquid(output, 1), LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1)); + + if (LiquidHelper.exists(Defaults.LIQUID_JUICE)) + RecipeManagers.fermenterManager.addRecipe(resource, fermentationValue, 1.5f, LiquidHelper.getLiquid(output, 1), LiquidHelper.getLiquid(Defaults.LIQUID_JUICE, 1)); + + if (LiquidHelper.exists(Defaults.LIQUID_HONEY)) + RecipeManagers.fermenterManager.addRecipe(resource, fermentationValue, 1.5f, LiquidHelper.getLiquid(output, 1), LiquidHelper.getLiquid(Defaults.LIQUID_HONEY, 1)); + } + + public static Object[] getCraftingRecipeAsArray(Object rec) { + + try { + + if (rec instanceof IDescriptiveRecipe) { + + IDescriptiveRecipe recipe = (IDescriptiveRecipe) rec; + return getShapedRecipeAsArray(recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), recipe.getRecipeOutput()); + + } + + } catch (Exception ex) { + Proxies.log.warning("Exception while trying to parse an ItemStack[10] from an IRecipe:"); + Proxies.log.warning(ex.getMessage()); + } + + return null; + } + + /* + * private static Object[] getSmallShapedRecipeAsArray(int width, int height, Object[] ingredients, ItemStack output) { Object[] result = new Object[5]; + * + * for(int y = 0; y < height; y++) for(int x = 0; x < width; x++) result[y * 2 + x] = ingredients[y * width + x]; + * + * result[4] = output; return result; } + */ + private static Object[] getShapedRecipeAsArray(int width, int height, Object[] ingredients, ItemStack output) { + Object[] result = new Object[10]; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + result[y * 3 + x] = ingredients[y * width + x]; + } + } + + result[9] = output; + return result; + } +} diff --git a/forestry_common/core/forestry/core/utils/Schemata.java b/forestry_common/core/forestry/core/utils/Schemata.java new file mode 100755 index 000000000..49d4cae42 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/Schemata.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import forestry.core.config.Config; + +public class Schemata { + public enum EnumStructureBlock { + ANY('X'), FOREIGN('F'), AIR('O'), MASTER('M'), GLASS('G'), BLOCK_A('A'), BLOCK_B('B'), BLOCK_C('C'), BLOCK_D('D'), BLOCK_E('E'); + + private char key; + + private EnumStructureBlock(char key) { + this.key = key; + } + + public char getKey() { + return this.key; + } + } + + private final String uid; + private EnumStructureBlock[][][] structure; + private int width, height, depth; + private int xOffset, yOffset, zOffset = -1; + + public Schemata(String uid, int width, int height, int depth, String... patterns) { + this(uid, width, height, depth); + this.setStructure(patterns); + } + + public Schemata(String uid, int width, int height, int depth) { + this.uid = uid; + this.structure = new EnumStructureBlock[width][height][depth]; + this.width = width; + this.height = height; + this.depth = depth; + } + + private void setStructure(String... patterns) { + + String fullpattern = ""; + + for (String pattern : patterns) + fullpattern = (new StringBuilder()).append(fullpattern).append(pattern).toString(); + + if (fullpattern.length() != getWidth() * getHeight() * getDepth()) + throw new RuntimeException("Incorrect pattern " + fullpattern + " (" + fullpattern.length() + ") for (" + getWidth() + "/" + getHeight() + "/" + + getDepth() + ")"); + + for (int i = 0; i < getWidth(); i++) + for (int j = 0; j < getHeight(); j++) + for (int k = 0; k < getDepth(); k++) + for (EnumStructureBlock type : EnumStructureBlock.values()) + if (type.getKey() == fullpattern.charAt(i * getHeight() * getDepth() + j * getDepth() + k)) { + structure[i][j][k] = type; + break; + } + + /* + * for(int i = 0; i < getWidth(); i++) { for(int j = 0; j < getHeight(); j++) { System.out.print("["); for(int k = 0; k < getDepth(); k++) { + * System.out.print(structure[i][j][k].getKey()); } System.out.print("]"); } System.out.println(); } + */ + + } + + public Schemata setOffsets(int xOffset, int yOffset, int zOffset) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + + return this; + } + + public EnumStructureBlock getAt(int x, int y, int z, boolean rotate) { + if (rotate) + return structure[z][y][x]; + return structure[x][y][z]; + } + + public Vect getDimensions(boolean rotate) { + if (rotate) + return new Vect(getDepth(), getHeight(), getWidth()); + else + return new Vect(getWidth(), getHeight(), getDepth()); + } + + public boolean isEnabled() { + return !Config.disabledStructures.contains(uid); + } + + /** + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * @return the depth + */ + public int getDepth() { + return depth; + } + + /** + * @return the xOffset + */ + public int getxOffset() { + return xOffset; + } + + /** + * @return the yOffset + */ + public int getyOffset() { + return yOffset; + } + + /** + * @return the zOffset + */ + public int getzOffset() { + return zOffset; + } + +} diff --git a/forestry_common/core/forestry/core/utils/ShapedRecipeCustom.java b/forestry_common/core/forestry/core/utils/ShapedRecipeCustom.java new file mode 100755 index 000000000..6e494f737 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/ShapedRecipeCustom.java @@ -0,0 +1,251 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.block.Block; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import net.minecraftforge.oredict.OreDictionary; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IDescriptiveRecipe; + +public class ShapedRecipeCustom implements IDescriptiveRecipe { + + private final int width; + private final int height; + + private final Object ingredients[]; + private final ItemStack product; + + private boolean preserveNBT = false; + + public ShapedRecipeCustom(int width, int height, Object ingredients[], ItemStack product) { + this.width = width; + this.height = height; + this.ingredients = ingredients; + this.product = product; + } + + public ShapedRecipeCustom setPreserveNBT() { + this.preserveNBT = true; + return this; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public ItemStack getRecipeOutput() { + return product; + } + + @Override + public Object[] getIngredients() { + return ingredients; + } + + @Override + public boolean matches(InventoryCrafting inventorycrafting, World world) { + ItemStack[][] resources = new ItemStack[3][3]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + resources[i][j] = inventorycrafting.getStackInRowAndColumn(i, j); + + return matches(resources); + } + + public boolean matches(ItemStack[][] resources) { + + for (int i = 0; i <= 3 - width; i++) + for (int j = 0; j <= 3 - height; j++) { + if (checkMatch(resources, i, j, true)) + return true; + + if (checkMatch(resources, i, j, false)) + return true; + } + + return false; + } + + @SuppressWarnings("unchecked") + private boolean checkMatch(ItemStack[][] resources, int xInGrid, int yInGrid, boolean flag) { + + for (int k = 0; k < 3; k++) + for (int l = 0; l < 3; l++) { + + int widthIt = k - xInGrid; + int heightIt = l - yInGrid; + Object compare = null; + + if (widthIt >= 0 && heightIt >= 0 && widthIt < width && heightIt < height) + if (flag) + compare = ingredients[(width - widthIt - 1) + heightIt * width]; + else + compare = ingredients[widthIt + heightIt * width]; + ItemStack resource = resources[k][l]; + + if (compare instanceof ItemStack) { + if (!checkItemMatch((ItemStack) compare, resource)) + return false; + } else if (compare instanceof ArrayList) { + boolean matched = false; + + for (ItemStack item : (ArrayList) compare) + matched = matched || checkItemMatch(item, resource); + + if (!matched) + return false; + + } else if (compare == null && resource != null) + return false; + } + + return true; + } + + private boolean checkItemMatch(ItemStack compare, ItemStack resource) { + + if (resource == null && compare == null) + return true; + + if (resource == null && compare != null || resource != null && compare == null) + return false; + + if (compare.getItem() != resource.getItem()) + return false; + + if (compare.getItemDamage() != Defaults.WILDCARD && compare.getItemDamage() != resource.getItemDamage()) + return false; + + return true; + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventorycrafting) { + if (preserveNBT) + for (int i = 0; i < inventorycrafting.getSizeInventory(); i++) { + if (inventorycrafting.getStackInSlot(i) == null) + continue; + if (!inventorycrafting.getStackInSlot(i).hasTagCompound()) + continue; + + ItemStack crafted = product.copy(); + crafted.setTagCompound((NBTTagCompound) inventorycrafting.getStackInSlot(i).getTagCompound().copy()); + return crafted; + } + + return product.copy(); + } + + @Override + public int getRecipeSize() { + return width * height; + } + + /** + * @param resource + * @return true if resource is a valid ingredient in this recipe. + */ + @SuppressWarnings("unchecked") + public boolean isIngredient(ItemStack resource) { + + for (Object ingredient : ingredients) + if (ingredient instanceof ItemStack) { + if (checkItemMatch((ItemStack) ingredient, resource)) + return true; + + } else if (ingredient instanceof ArrayList) + for (ItemStack item : (ArrayList) ingredient) + if (checkItemMatch(item, resource)) + return true; + + return false; + + } + + public static ShapedRecipeCustom createShapedRecipe(ItemStack product, Object... materials) { + + String s = ""; + int index = 0; + int columns = 0; + int rows = 0; + if (materials[index] instanceof String[]) { + String as[] = (String[]) materials[index++]; + for (int l = 0; l < as.length; l++) { + String pattern = as[l]; + rows++; + columns = pattern.length(); + s = (new StringBuilder()).append(s).append(pattern).toString(); + } + + } else + while (materials[index] instanceof String) { + String pattern = (String) materials[index++]; + rows++; + columns = pattern.length(); + s = (new StringBuilder()).append(s).append(pattern).toString(); + } + + HashMap hashmap = new HashMap(); + for (; index < materials.length; index += 2) { + + Character character = (Character) materials[index]; + + // Item + if (materials[index + 1] instanceof Item) + hashmap.put(character, new ItemStack((Item) materials[index + 1])); + else if (materials[index + 1] instanceof ForestryItem) + hashmap.put(character, ((ForestryItem) materials[index + 1]).getItemStack()); + else if (materials[index + 1] instanceof Block) + hashmap.put(character, new ItemStack((Block) materials[index + 1], 1, Defaults.WILDCARD)); + else if (materials[index + 1] instanceof ItemStack) + hashmap.put(character, materials[index + 1]); + else if (materials[index + 1] instanceof String) + hashmap.put(character, OreDictionary.getOres((String) materials[index + 1])); + else + throw new RuntimeException("Invalid Recipe Defined!"); + + } + + Object ingredients[] = new Object[columns * rows]; + for (int l = 0; l < columns * rows; l++) { + char c = s.charAt(l); + if (hashmap.containsKey(Character.valueOf(c))) + ingredients[l] = hashmap.get(Character.valueOf(c)); + else + ingredients[l] = null; + } + + return new ShapedRecipeCustom(columns, rows, ingredients, product); + } + + @SuppressWarnings("unchecked") + public static ShapedRecipeCustom buildRecipe(ItemStack product, Object... materials){ + ShapedRecipeCustom recipe = createShapedRecipe(product, materials); + CraftingManager.getInstance().getRecipeList().add(recipe); + return recipe; + } +} diff --git a/forestry_common/core/forestry/core/utils/StackMap.java b/forestry_common/core/forestry/core/utils/StackMap.java new file mode 100755 index 000000000..c32290157 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/StackMap.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Map for fluids and items. Can add things like ore dictionary strings etc. + * @author Alex Binnie + * + * @param The thing this map maps onto + * @param

The stack class (i.e. ItemStack, FluidStack) used for lookups + */ +public abstract class StackMap extends HashMap{ + + @Override + public final T put(Object key, T value) { + if(isValidKey(key) && key != null && value != null) + return super.put(key, value); + return null; + } + + private static final long serialVersionUID = 5383477742290646466L; + + @Override + public final boolean containsKey(Object key) { + P stack = getStack(key); + if(stack == null) return false; + for (Map.Entry entry : this.entrySet()) + if (areEqual(stack, entry.getKey())) + return true; + return super.containsKey(key); + } + + @Override + public final T get(Object key) { + P stack = getStack(key); + if(stack == null) return null; + for (Map.Entry entry : this.entrySet()) + if (areEqual(stack, entry.getKey())) + return entry.getValue(); + return super.get(key); + } + + /** + * Is a, the key used to lookup, equivelant to the key b + * @param a + * @param b + * @return + */ + protected abstract boolean areEqual(P a, Object b); + + /** + * Can this key be added to the map + * @param key + * @return + */ + protected abstract boolean isValidKey(Object key); + + /** + * Converts a key used to lookup something into P (ItemStack or FluidStack) + * @param key + * @return + */ + protected abstract P getStack(Object key); + +} diff --git a/forestry_common/core/forestry/core/utils/StackUtils.java b/forestry_common/core/forestry/core/utils/StackUtils.java new file mode 100755 index 000000000..8cc0426a5 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/StackUtils.java @@ -0,0 +1,431 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.util.ArrayList; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.oredict.OreDictionary; + +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileForestry; + +public class StackUtils { + + public static final ItemStack[] EMPTY_STACK_ARRAY = new ItemStack[0]; + public static final ArrayList EMPTY_STACK_LIST = new ArrayList(); + + /** + * Compares item id, damage and NBT. Accepts wildcard damage. + * + * @param lhs + * @param rhs + * @return + */ + public static boolean isIdenticalItem(ItemStack lhs, ItemStack rhs) { + if (lhs == null || rhs == null) + return false; + + if (lhs.getItem() != rhs.getItem()) + return false; + + if (lhs.getItemDamage() != Defaults.WILDCARD) + if (lhs.getItemDamage() != rhs.getItemDamage()) + return false; + + return ItemStack.areItemStackTagsEqual(lhs, rhs); + } + + public static boolean stowInInventory(ItemStack itemstack, IInventory inventory, boolean doAdd) { + return stowInInventory(itemstack, inventory, doAdd, 0, inventory.getSizeInventory()); + } + + public static boolean stowInInventory(ItemStack itemstack, IInventory inventory, boolean doAdd, int slot1, int count) { + + boolean added = false; + + for (int i = slot1; i < slot1 + count; i++) { + ItemStack inventoryStack = inventory.getStackInSlot(i); + + // Grab those free slots + if (inventoryStack == null) { + if (doAdd) { + inventory.setInventorySlotContents(i, itemstack.copy()); + itemstack.stackSize = 0; + } + return true; + } + + // Already full + if (inventoryStack.stackSize >= inventoryStack.getMaxStackSize()) + continue; + + // Not same type + if (!inventoryStack.isItemEqual(itemstack)) + continue; + if (!ItemStack.areItemStackTagsEqual(inventoryStack, itemstack)) + continue; + + int space = inventoryStack.getMaxStackSize() - inventoryStack.stackSize; + + // Enough space to add all + if (space > itemstack.stackSize) { + if (doAdd) { + inventoryStack.stackSize += itemstack.stackSize; + itemstack.stackSize = 0; + } + return true; + // Only part can be added + } else { + if (doAdd) { + inventoryStack.stackSize = inventoryStack.getMaxStackSize(); + itemstack.stackSize -= space; + } + added = true; + } + + } + + return added; + + } + + public static int addToInventory(ItemStack itemstack, IInventory inventory, boolean doAdd, int slot1, int count) { + + int added = 0; + + for (int i = slot1; i < slot1 + count; i++) { + ItemStack inventoryStack = inventory.getStackInSlot(i); + + // Grab those free slots + if (inventoryStack == null) { + if (doAdd) + inventory.setInventorySlotContents(i, itemstack.copy()); + return itemstack.stackSize; + } + + // Already full + if (inventoryStack.stackSize >= inventoryStack.getMaxStackSize()) + continue; + + // Not same type + if (!inventoryStack.isItemEqual(itemstack)) + continue; + + int space = inventoryStack.getMaxStackSize() - inventoryStack.stackSize; + + // Enough space to add all + if (space > itemstack.stackSize - added) { + if (doAdd) + inventoryStack.stackSize += itemstack.stackSize; + return itemstack.stackSize; + // Only part can be added + } else { + if (doAdd) + inventoryStack.stackSize = inventoryStack.getMaxStackSize(); + added += space; + } + + } + + return added; + + } + + /** + * Merges the giving stack into the receiving stack as far as possible + * + * @param giver + * @param receptor + */ + public static void mergeStacks(ItemStack giver, ItemStack receptor) { + if (receptor.stackSize >= 64) + return; + + if (!receptor.isItemEqual(giver)) + return; + + if (giver.stackSize <= (receptor.getMaxStackSize() - receptor.stackSize)) { + receptor.stackSize += giver.stackSize; + giver.stackSize = 0; + return; + } + + ItemStack temp = giver.splitStack(receptor.getMaxStackSize() - receptor.stackSize); + receptor.stackSize += temp.stackSize; + temp.stackSize = 0; + return; + } + + public static boolean freeSpaceInStack(ItemStack stack, int maxSize) { + if (stack == null) + return true; + + if (stack.stackSize >= maxSize) + return false; + + return true; + } + + /** + * Creates a split stack of the specified amount, preserving NBT data, + * without decreasing the source stack. + * + * @param stack + * @param i + * @return + */ + public static ItemStack createSplitStack(ItemStack stack, int amount) { + ItemStack split = new ItemStack(stack.getItem(), amount, stack.getItemDamage()); + if (stack.getTagCompound() != null) { + NBTTagCompound nbttagcompound = (NBTTagCompound) stack.getTagCompound().copy(); + split.setTagCompound(nbttagcompound); + } + return split; + } + + public static ItemStack[] condenseStacks(ItemStack[] stacks) { + return condenseStacks(stacks, -1, false); + } + + /** + * + * @param stacks + * @param maxCountedPerStack The maximum stacksize counted in a single + * stack. -1 for unlimited. + * @return + */ + public static ItemStack[] condenseStacks(ItemStack[] stacks, int maxCountedPerStack, boolean craftingEquivalency) { + ArrayList condensed = new ArrayList(); + + for (ItemStack stack : stacks) { + if (stack == null) + continue; + if (stack.stackSize <= 0) + continue; + + boolean matched = false; + for (ItemStack cached : condensed) { + if (cached.isItemEqual(stack) + || (craftingEquivalency && isCraftingEquivalent(cached, stack, true, false))) { + cached.stackSize += maxCountedPerStack > 0 && stack.stackSize > maxCountedPerStack ? maxCountedPerStack : stack.stackSize; + matched = true; + } + } + + if (!matched) { + ItemStack cached = stack.copy(); + if (maxCountedPerStack > 0) + cached.stackSize = maxCountedPerStack; + condensed.add(cached); + } + + } + + return condensed.toArray(EMPTY_STACK_ARRAY); + } + + /** + * Counts how many full sets are contained in the passed stock + * + * @param set + * @param stock + * @return + */ + public static int containsSets(ItemStack[] set, ItemStack[] stock) { + return containsSets(set, stock, null, false, false); + } + + /** + * Counts how many full sets are contained in the passed stock + * + * @param set + * @param stock + * @return + */ + public static int containsSets(ItemStack[] set, ItemStack[] stock, ItemStack exclude, boolean oreDictionary, boolean craftingTools) { + int count = 0; + + ItemStack[] condensedRequired = StackUtils.condenseStacks(set); + ItemStack[] condensedOffered = StackUtils.condenseStacks(stock, -1, oreDictionary); + + for (ItemStack req : condensedRequired) { + + boolean matched = false; + for (ItemStack offer : condensedOffered) { + + if (exclude != null && isIdenticalItem(offer, exclude)) + continue; + + if (isCraftingEquivalent(req, offer, oreDictionary, craftingTools)) { + matched = true; + + int stackCount = (int) Math.floor(offer.stackSize / req.stackSize); + if (stackCount <= 0) + return 0; + else if (count == 0) + count = stackCount; + else if (count > stackCount) + count = stackCount; + } + } + if (!matched) + return 0; + } + + return count; + } + + /** + * Compare two item stacks for crafting equivalency. + * + * @param base + * @param comparison + * @param oreDictionary + * @return + */ + public static boolean isCraftingEquivalent(ItemStack base, ItemStack comparison, boolean oreDictionary, boolean craftingTools) { + if (isIdenticalItem(base, comparison)) + return true; + + if (oreDictionary) { + int idBase = OreDictionary.getOreID(base); + if (idBase >= 0) { + for (ItemStack itemstack : OreDictionary.getOres(idBase)) { + if (comparison.getItem() == itemstack.getItem() && (itemstack.getItemDamage() == OreDictionary.WILDCARD_VALUE || comparison.getItemDamage() == itemstack.getItemDamage())) + return true; + } + } + } + + if (craftingTools) { + return isThisCraftingTool(base, comparison); + } + + return false; + } + + public static boolean isCraftingTool(ItemStack itemstack) { + return itemstack.getItem().hasContainerItem(itemstack) + && itemstack.getItem().isDamageable() + && !itemstack.getItem().doesContainerItemLeaveCraftingGrid(itemstack); + } + + public static boolean isThisCraftingTool(ItemStack phantom, ItemStack actual) { + return isCraftingTool(phantom) && phantom.getItem() == actual.getItem(); + } + + public static void stowContainerItem(ItemStack itemstack, InventoryAdapter stowing, int slotIndex, EntityPlayer player) { + if (!itemstack.getItem().hasContainerItem(itemstack)) + return; + + ItemStack container = itemstack.getItem().getContainerItem(itemstack); + + if (container.isItemStackDamageable() && container.getItemDamage() > container.getMaxDamage()) { + MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, container)); + container = null; + } + + if (container != null) { + + if (itemstack.getItem().doesContainerItemLeaveCraftingGrid(itemstack)) { + if (!stowing.tryAddStack(container, true)) + if (!player.inventory.addItemStackToInventory(container)) + player.dropPlayerItemWithRandomChoice(container, true); + } else { + if (!stowing.tryAddStack(container, slotIndex, 1, true)) + if (!stowing.tryAddStack(container, true)) + player.dropPlayerItemWithRandomChoice(container, true); + } + } + } + + public static void dropItemStackAsEntity(ItemStack items, World world, double x, double y, double z) { + if (items.stackSize <= 0) + return; + + float f1 = 0.7F; + double d = (world.rand.nextFloat() * f1) + (1.0F - f1) * 0.5D; + double d1 = (world.rand.nextFloat() * f1) + (1.0F - f1) * 0.5D; + double d2 = (world.rand.nextFloat() * f1) + (1.0F - f1) * 0.5D; + EntityItem entityitem = new EntityItem(world, x + d, y + d1, z + d2, items); + entityitem.delayBeforeCanPickup = 10; + + world.spawnEntityInWorld(entityitem); + + } + + public static void replenishByContainer(TileForestry tile, ItemStack inventoryStack, ForestryTank tank) { + FluidContainerData container = LiquidHelper.getLiquidContainer(inventoryStack); + replenishByContainer(tile, inventoryStack, container, tank); + } + + public static ItemStack replenishByContainer(TileForestry tile, ItemStack inventoryStack, FluidContainerData container, ForestryTank tank) { + if (container == null) + return inventoryStack; + + if (tank.fill(container.fluid, false) >= container.fluid.amount) { + tank.fill(container.fluid, true); + if (container.filledContainer != null && container.filledContainer.getItem().hasContainerItem(container.filledContainer)) + inventoryStack = container.emptyContainer.copy(); + else + inventoryStack.stackSize--; + tile.sendNetworkUpdate(); + } + + return inventoryStack; + } + + public static ItemStack copyWithRandomSize(ItemStack template, int max, Random rand) { + int size = rand.nextInt(max); + ItemStack created = template.copy(); + created.stackSize = size <= 0 ? 1 : size > created.getMaxStackSize() ? created.getMaxStackSize() : size; + return created; + } + + public static ItemStack consumeItem(ItemStack stack) { + if (stack.stackSize == 1) { + if (stack.getItem().hasContainerItem(stack)) { + return stack.getItem().getContainerItem(stack); + } else { + return null; + } + } else { + stack.splitStack(1); + + return stack; + } + } + + public static Block getBlock(ItemStack stack) { + Item item = stack.getItem(); + + if (item instanceof ItemBlock) { + return ((ItemBlock) item).field_150939_a; + } else { + return null; + } + } + + public static boolean equals(Block block, ItemStack stack) { + return block == getBlock(stack); + } +} diff --git a/forestry_common/core/forestry/core/utils/StringUtil.java b/forestry_common/core/forestry/core/utils/StringUtil.java new file mode 100755 index 000000000..1fe6a653a --- /dev/null +++ b/forestry_common/core/forestry/core/utils/StringUtil.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +public class StringUtil { + + public static String localize(String key) { + return Localization.instance.get(key); + } + + public static String localizeAndFormat(String key, Object... args) { + return String.format(Localization.instance.get(key), args); + } + + public static String capitalize(String s) { + if (s.length() == 0) + return s; + return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); + } + + public static String append(String delim, String source, String appendix) { + if (source.length() <= 0) + return appendix; + + if (appendix.length() <= 0) + return source; + + return source + delim + appendix; + } + + public static String readableBoolean(boolean flag, String trueStr, String falseStr) { + if (flag) + return trueStr; + else + return falseStr; + } + + public static String floatAsPercent(float val) { + return (int) (val * 100) + " %"; + } +} diff --git a/forestry_common/core/forestry/core/utils/TileInventoryAdapter.java b/forestry_common/core/forestry/core/utils/TileInventoryAdapter.java new file mode 100755 index 000000000..086a2f9e8 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/TileInventoryAdapter.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.core.gadgets.TileForestry; + +public class TileInventoryAdapter extends InventoryAdapter { + + TileForestry tile; + + public TileInventoryAdapter(TileForestry tile, int size, String name) { + super(size, name); + this.tile = tile; + } + + public TileInventoryAdapter(TileForestry tile, int size, String name, int stackLimit) { + super(size, name, stackLimit); + this.tile = tile; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return tile.isUseableByPlayer(entityplayer); + } + + @Override + public void markDirty() { + super.markDirty(); + tile.markDirty(); + } +} diff --git a/forestry_common/core/forestry/core/utils/Utils.java b/forestry_common/core/forestry/core/utils/Utils.java new file mode 100755 index 000000000..d0634dc56 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/Utils.java @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +import java.security.MessageDigest; +import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryLargeChest; +import net.minecraft.item.ItemStack; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.IChatComponent; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import cpw.mods.fml.common.registry.EntityRegistry; + +import buildcraft.api.tools.IToolWrench; +import com.mojang.authlib.GameProfile; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.ITree; +import forestry.api.core.ForestryAPI; +import forestry.api.core.IArmorNaturalist; +import forestry.api.core.ITileStructure; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.core.config.Config; +import forestry.core.gadgets.TileForestry; +import forestry.core.proxy.Proxies; +import forestry.plugins.PluginArboriculture; + +public class Utils { + + private static EntityPlayer modPlayer; + + public static EntityPlayer getForestryPlayer(World world, int x, int y, int z) { + if (modPlayer == null) { + modPlayer = new EntityPlayer(world, new GameProfile(Config.fakeUserLogin, Config.fakeUserLogin)) { + @Override + public boolean canCommandSenderUseCommand(int var1, String var2) { + return false; + } + + @Override + public ChunkCoordinates getPlayerCoordinates() { + return null; + } + + @Override + public void addChatMessage(IChatComponent var1) { + } + }; + modPlayer.posX = x; + modPlayer.posY = y; + modPlayer.posZ = z; + Proxies.log.info("Created player '%s' for Forestry.", modPlayer.getGameProfile().getId()); + if (Config.fakeUserAutoop) { + MinecraftServer.getServer().getConfigurationManager().addOp(modPlayer.getGameProfile().getId()); + Proxies.log.info("Opped player '%s'.", modPlayer.getGameProfile().getId()); + } + } + + return modPlayer; + } + private static Random rand; + + public static int getUID() { + if (rand == null) + rand = new Random(); + + int uid = rand.nextInt(); + return uid; + } + + public static void dropInventory(TileForestry tile, World world, int x, int y, int z) { + if (tile == null) + return; + + // Release inventory + if (tile instanceof ITileStructure) { + + IInventory inventory = ((ITileStructure) tile).getInventory(); + if (inventory != null) + for (int i = 0; i < inventory.getSizeInventory(); i++) { + if (inventory.getStackInSlot(i) == null) + continue; + + StackUtils.dropItemStackAsEntity(inventory.getStackInSlot(i), world, x, y, z); + inventory.setInventorySlotContents(i, null); + } + + } else { + + IInventory inventory; + if (tile instanceof IInventory) + inventory = (IInventory) tile; + else + inventory = tile.getInternalInventory(); + + if (inventory != null) { + for (int slot = 0; slot < inventory.getSizeInventory(); slot++) { + + ItemStack itemstack = inventory.getStackInSlot(slot); + + if (itemstack == null) + continue; + + float f = world.rand.nextFloat() * 0.8F + 0.1F; + float f1 = world.rand.nextFloat() * 0.8F + 0.1F; + float f2 = world.rand.nextFloat() * 0.8F + 0.1F; + + while (itemstack.stackSize > 0) { + + int stackPartial = world.rand.nextInt(21) + 10; + if (stackPartial > itemstack.stackSize) + stackPartial = itemstack.stackSize; + ItemStack drop = itemstack.splitStack(stackPartial); + EntityItem entityitem = new EntityItem(world, x + f, y + f1, z + f2, drop); + float accel = 0.05F; + entityitem.motionX = (float) world.rand.nextGaussian() * accel; + entityitem.motionY = (float) world.rand.nextGaussian() * accel + 0.2F; + entityitem.motionZ = (float) world.rand.nextGaussian() * accel; + world.spawnEntityInWorld(entityitem); + + } + + inventory.setInventorySlotContents(slot, null); + } + } + } + + } + + public static boolean hasNaturalistEye(EntityPlayer player) { + ItemStack armorItem = player.inventory.armorInventory[3]; + return armorItem != null && armorItem.getItem() instanceof IArmorNaturalist + && ((IArmorNaturalist) armorItem.getItem()).canSeePollination(player, armorItem, true); + } + + @SuppressWarnings("rawtypes") + public static void broadcastMessage(World world, String message) { + for (Iterator iterator = world.playerEntities.iterator(); iterator.hasNext();) { + EntityPlayer entityplayer = (EntityPlayer) iterator.next(); + entityplayer.addChatMessage(new ChatComponentText(message)); + } + } + + public static IInventory getChest(IInventory inventory) { + if (!(inventory instanceof TileEntityChest)) + return inventory; + + TileEntityChest chest = (TileEntityChest) inventory; + + Vect[] adjacent = new Vect[] { new Vect(chest.xCoord + 1, chest.yCoord, chest.zCoord), new Vect(chest.xCoord - 1, chest.yCoord, chest.zCoord), + new Vect(chest.xCoord, chest.yCoord, chest.zCoord + 1), new Vect(chest.xCoord, chest.yCoord, chest.zCoord - 1) }; + + for (Vect pos : adjacent) { + TileEntity otherchest = chest.getWorldObj().getTileEntity(pos.x, pos.y, pos.z); + if (otherchest instanceof TileEntityChest) + return new InventoryLargeChest("", chest, (TileEntityChest) otherchest); + } + + return inventory; + } + + public static T[] concat(T[] first, T[] second) { + T[] result = Arrays.copyOf(first, first.length + second.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + public static int[] concat(int[] first, int[] second) { + int[] result = Arrays.copyOf(first, first.length + second.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + public static short[] concat(short[] first, short[] second) { + short[] result = Arrays.copyOf(first, first.length + second.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + public static float[] concat(float[] first, float[] second) { + float[] result = Arrays.copyOf(first, first.length + second.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + public static boolean canWrench(EntityPlayer player, int x, int y, int z) { + + ItemStack itemstack = player.getCurrentEquippedItem(); + if (itemstack == null) + return false; + + if (!(itemstack.getItem() instanceof IToolWrench)) + return false; + + IToolWrench wrench = (IToolWrench) itemstack.getItem(); + if (!wrench.canWrench(player, x, y, z)) + return false; + + return true; + } + + public static void useWrench(EntityPlayer player, int x, int y, int z) { + ItemStack itemstack = player.getCurrentEquippedItem(); + + if (itemstack == null) + return; + + if (!(itemstack.getItem() instanceof IToolWrench)) + return; + + ((IToolWrench) itemstack.getItem()).wrenchUsed(player, x, y, z); + } + + public static EnumTankLevel rateTankLevel(int scaled) { + + if (scaled < 5) + return EnumTankLevel.EMPTY; + else if (scaled < 30) + return EnumTankLevel.LOW; + else if (scaled < 60) + return EnumTankLevel.MEDIUM; + else if (scaled < 90) + return EnumTankLevel.HIGH; + else + return EnumTankLevel.MAXIMUM; + } + + public static boolean isReplaceableBlock(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + return block == Blocks.vine || block == Blocks.tallgrass || block == Blocks.deadbush || block == Blocks.snow_layer + || block.isReplaceable(world, x, y, z); + } + + public static boolean isLiquidBlock(World world, int x, int y, int z) { + return isLiquidBlock(world.getBlock(x, y, z)); + } + + public static boolean isLiquidBlock(Block block) { + return block == Blocks.water || block == Blocks.flowing_water || block == Blocks.lava || block == Blocks.flowing_lava; + } + + public static boolean isUseableByPlayer(EntityPlayer player, TileEntity tile, World world, int x, int y, int z) { + if (world.getTileEntity(x, y, z) != tile) + return false; + + return player.getDistanceSq(x + 0.5D, y + 0.5D, z + 0.5D) <= 64.0D; + + } + + public static BiomeGenBase getBiomeAt(World world, int x, int z) { + return world.getBiomeGenForCoordsBody(x, z); + } + + public static Entity spawnEntity(World world, Class entityClass, double x, double y, double z) { + if (!EntityList.classToStringMapping.containsKey(entityClass)) + return null; + + return spawnEntity(world, EntityList.createEntityByName((String) EntityList.classToStringMapping.get(entityClass), world), x, y, z); + } + + public static Entity spawnEntity(World world, Entity spawn, double x, double y, double z) { + + if (spawn != null && spawn instanceof EntityLiving) { + + EntityLiving living = (EntityLiving) spawn; + spawn.setLocationAndAngles(x, y, z, MathHelper.wrapAngleTo180_float(world.rand.nextFloat() * 360.0f), 0.0f); + living.rotationYawHead = living.rotationYaw; + living.renderYawOffset = living.rotationYaw; + living.onSpawnWithEgg((IEntityLivingData) null); + world.spawnEntityInWorld(spawn); + living.playLivingSound(); + } + + return spawn; + } + + public static void registerEntity(Class entityClass, String ident, int id, int eggForeground, int eggBackground, int trackingRange, int updateFrequency, boolean sendVelocity) { + EntityRegistry.registerModEntity(entityClass, ident, id, ForestryAPI.instance, trackingRange, updateFrequency, sendVelocity); + Proxies.log.finer("Registered entity %s (%s) with id %s.", ident, entityClass.toString(), id); + } + + public static int addRGBComponents(int colour, int r, int g, int b) { + r = ((colour & 0xff0000) >> 16) + r; + g = ((colour & 0xff00) >> 8) + b; + b = ((colour & 0xff)) + b; + + r = r <= 255 ? r : 255; + g = g <= 255 ? g : 255; + b = b <= 255 ? b : 255; + + return ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff); + } + + public static int multiplyRGBComponents(int colour, float factor) { + int r = (int) (((colour & 0xff0000) >> 16) * factor); + int g = (int) (((colour & 0xff00) >> 8) * factor); + int b = (int) (((colour & 0xff)) * factor); + + r = r <= 255 ? r : 255; + g = g <= 255 ? g : 255; + b = b <= 255 ? b : 255; + + return ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff); + } + + public static String getFingerprint(Certificate certificate) { + if (certificate == null) + return "Certificate invalid"; + + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] der = certificate.getEncoded(); + md.update(der); + byte[] digest = md.digest(); + return tohex(digest); + } catch (Exception ex) { + return null; + } + } + private static final String HEX = "0123456789abcdef"; + + private static String tohex(byte[] checksum) { + + final StringBuilder hex = new StringBuilder(2 * checksum.length); + for (byte bty : checksum) { + hex.append(HEX.charAt((bty & 0xf0) >> 4)).append(HEX.charAt((bty & 0x0f))); + } + return hex.toString(); + } + + public static ItemStack convertSaplingToGeneticEquivalent(ItemStack foreign) { + + ItemStack ersatz = null; + ITree tree = null; + + for (Map.Entry entry : AlleleManager.ersatzSaplings.entrySet()) { + if (entry.getKey().getItem() != foreign.getItem()) + continue; + if (entry.getKey().getItemDamage() != foreign.getItemDamage()) + continue; + + if (entry.getValue() instanceof ITree) + tree = (ITree) entry.getValue(); + + ersatz = PluginArboriculture.treeInterface.getMemberStack(tree, EnumGermlingType.SAPLING.ordinal()); + ersatz.stackSize = foreign.stackSize; + } + + return ersatz; + } + + public static IPollinatable getOrCreatePollinatable(String owner, World world, int x, int y, int z) { + TileEntity tile = world.getTileEntity(x, y, z); + + IPollinatable receiver = null; + if (tile instanceof IPollinatable) + receiver = (IPollinatable) tile; + else if (!world.isAirBlock(x, y, z)) { + + // Test for ersatz genomes + for (Map.Entry entry : AlleleManager.ersatzSpecimen.entrySet()) { + if (!StackUtils.equals(world.getBlock(x, y, z), entry.getKey())) + continue; + + int meta = world.getBlockMetadata(x, y, z); + if (StackUtils.equals(Blocks.leaves, entry.getKey())) + meta = meta & 3; + if (entry.getKey().getItemDamage() != meta) + continue; + + // We matched, replace the leaf block with ours and set the ersatz genome + PluginArboriculture.treeInterface.setLeaves(world, entry.getValue(), owner, x, y, z); + // Now let's pollinate + receiver = (IPollinatable) world.getTileEntity(x, y, z); + } + + } + + return receiver; + } +} diff --git a/forestry_common/core/forestry/core/utils/Vect.java b/forestry_common/core/forestry/core/utils/Vect.java new file mode 100755 index 000000000..91843b481 --- /dev/null +++ b/forestry_common/core/forestry/core/utils/Vect.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.utils; + +/** + * Generic class to represent a position or dimensions. + */ +public class Vect { + public int x; + public int y; + public int z; + + public Vect(int[] dim) { + if (dim.length != 3) + throw new RuntimeException("Cannot instantiate a vector with less or more than 3 points."); + + this.x = dim[0]; + this.y = dim[1]; + this.z = dim[2]; + } + + public Vect(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public Vect add(Vect other) { + Vect result = new Vect(x, y, z); + result.x += other.x; + result.y += other.y; + result.z += other.z; + return result; + } + + public Vect multiply(float factor) { + Vect result = new Vect(x, y, z); + result.x *= factor; + result.y *= factor; + result.z *= factor; + return result; + } + + @Override + public String toString() { + return String.format("%sx%sx%s;", x, y, z); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + x; + result = prime * result + y; + result = prime * result + z; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Vect other = (Vect) obj; + if (x != other.x) + return false; + if (y != other.y) + return false; + if (z != other.z) + return false; + return true; + } +} diff --git a/forestry_common/core/forestry/core/worldgen/BlockType.java b/forestry_common/core/forestry/core/worldgen/BlockType.java new file mode 100755 index 000000000..7fb817eaa --- /dev/null +++ b/forestry_common/core/forestry/core/worldgen/BlockType.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.worldgen; + +import net.minecraft.block.Block; +import net.minecraft.world.World; + +import forestry.api.world.ITreeGenData; +import forestry.core.config.Defaults; + +public class BlockType { + + Block block; + int meta; + + public BlockType(Block block, int meta) { + this.block = block; + this.meta = meta; + } + + public void setBlock(World world, ITreeGenData tree, int x, int y, int z) { + world.setBlock(x, y, z, block, meta, Defaults.FLAG_BLOCK_SYNCH); + if (world.getTileEntity(x, y, z) != null) + world.removeTileEntity(x, y, z); + } +} diff --git a/forestry_common/core/forestry/core/worldgen/WorldGenBase.java b/forestry_common/core/forestry/core/worldgen/WorldGenBase.java new file mode 100755 index 000000000..8637203ad --- /dev/null +++ b/forestry_common/core/forestry/core/worldgen/WorldGenBase.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.worldgen; + +import java.util.Random; + +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +public abstract class WorldGenBase extends WorldGenerator { + + protected enum EnumReplaceMode { + + NONE, ALL, SOFT + } + + public static class Vector { + + public Vector(float f, float h, float g) { + this.x = f; + this.y = h; + this.z = g; + } + float x; + float y; + float z; + + public static double distance(Vector a, Vector b) { + return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2) + Math.pow(a.z - b.z, 2)); + } + } + protected World world; + protected Random rand; + + @Override + public final boolean generate(World world, Random random, int x, int y, int z) { + this.world = world; + this.rand = random; + boolean result = subGenerate(x, y, z); + this.world = null; + this.rand = null; + return result; + } + + public boolean subGenerate(int x, int y, int z) { + return false; + } + + protected abstract void addBlock(int x, int y, int z, BlockType type, EnumReplaceMode replace); + + protected final void generateCuboid(Vector start, Vector area, BlockType block, EnumReplaceMode replace) { + for (int x = (int) start.x; x < (int) start.x + area.x; x++) { + for (int y = (int) start.y; y < (int) start.y + area.y; y++) { + for (int z = (int) start.z; z < (int) start.z + area.z; z++) { + addBlock(x, y, z, block, replace); + } + } + } + } + + /* + * Center is the bottom middle of the cylinder + */ + protected final void generateCylinder(Vector center, float radius, int height, BlockType block, EnumReplaceMode replace) { + Vector start = new Vector(center.x - radius, center.y, center.z - radius); + Vector area = new Vector(radius * 2 + 1, height, radius * 2 + 1); + for (int x = (int) start.x; x < (int) start.x + area.x; x++) { + for (int y = (int) start.y; y < (int) start.y + area.y; y++) { + for (int z = (int) start.z; z < (int) start.z + area.z; z++) { + if (Vector.distance(new Vector(x, y, z), new Vector(center.x, y, center.z)) <= (radius) + 0.01) + addBlock(x, y, z, block, replace); + } + } + } + } + + protected final void generateCircle(Vector center, float radius, int width, int height, BlockType block, EnumReplaceMode replace) { + generateCircle(center, radius, width, height, block, 1.0f, replace); + } + + protected final void generateCircle(Vector center, float radius, int width, int height, BlockType block, float chance, EnumReplaceMode replace) { + Vector start = new Vector(center.x - radius, center.y, center.z - radius); + Vector area = new Vector(radius * 2 + 1, height, radius * 2 + 1); + + for (int x = (int) start.x; x < (int) start.x + area.x; x++) { + for (int y = (int) start.y; y < (int) start.y + area.y; y++) { + for (int z = (int) start.z; z < (int) start.z + area.z; z++) { + + if (rand.nextFloat() > chance) + continue; + + double distance = Vector.distance(new Vector(x, y, z), new Vector(center.x, y, center.z)); + if ((radius - width - 0.01 < distance && distance <= (radius) + 0.01)) + addBlock(x, y, z, block, replace); + } + } + } + } + + protected final void generateSphere(Vector center, int radius, BlockType block, EnumReplaceMode replace) { + Vector start = new Vector(center.x - radius, center.y - radius, center.z - radius); + Vector area = new Vector(radius * 2 + 1, radius * 2 + 1, radius * 2 + 1); + for (int x = (int) start.x; x < (int) start.x + area.x; x++) { + for (int y = (int) start.y; y < (int) start.y + area.y; y++) { + for (int z = (int) start.z; z < (int) start.z + area.z; z++) { + if (Vector.distance(new Vector(x, y, z), new Vector(center.x, center.y, center.z)) <= (radius) + 0.01) + addBlock(x, y, z, block, replace); + } + } + } + } +} diff --git a/forestry_common/core/forestry/core/worldgen/WorldGenMinableMeta.java b/forestry_common/core/forestry/core/worldgen/WorldGenMinableMeta.java new file mode 100755 index 000000000..4b35a2310 --- /dev/null +++ b/forestry_common/core/forestry/core/worldgen/WorldGenMinableMeta.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.core.worldgen; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import forestry.core.config.Defaults; + +public class WorldGenMinableMeta extends WorldGenerator { + + private final Block mineableBlock; + private final int mineableBlockMeta; + private final int numberOfBlocks; + + public WorldGenMinableMeta(Block block, int meta, int numberOfBlocks) { + mineableBlock = block; + mineableBlockMeta = meta; + this.numberOfBlocks = numberOfBlocks; + } + + @Override + public boolean generate(World world, Random random, int i, int j, int k) { + + boolean hasGenerated = false; + + float randomBase = random.nextFloat() * 3.141593F; + double d = (i + 8) + (MathHelper.sin(randomBase) * numberOfBlocks) / 8F; + double d1 = (i + 8) - (MathHelper.sin(randomBase) * numberOfBlocks) / 8F; + double d2 = (k + 8) + (MathHelper.cos(randomBase) * numberOfBlocks) / 8F; + double d3 = (k + 8) - (MathHelper.cos(randomBase) * numberOfBlocks) / 8F; + double d4 = (j + random.nextInt(3)) - 2; + double d5 = (j + random.nextInt(3)) - 2; + + for (int l = 0; l <= numberOfBlocks; l++) { + double d6 = d + ((d1 - d) * l) / numberOfBlocks; + double d7 = d4 + ((d5 - d4) * l) / numberOfBlocks; + double d8 = d2 + ((d3 - d2) * l) / numberOfBlocks; + double d9 = (random.nextDouble() * numberOfBlocks) / 16D; + double d10 = (MathHelper.sin((l * 3.141593F) / numberOfBlocks) + 1.0F) * d9 + 1.0D; + double d11 = (MathHelper.sin((l * 3.141593F) / numberOfBlocks) + 1.0F) * d9 + 1.0D; + int xStart = MathHelper.floor_double(d6 - d10 / 2D); + int yStart = MathHelper.floor_double(d7 - d11 / 2D); + int zStart = MathHelper.floor_double(d8 - d10 / 2D); + int xEnd = MathHelper.floor_double(d6 + d10 / 2D); + int yEnd = MathHelper.floor_double(d7 + d11 / 2D); + int zEnd = MathHelper.floor_double(d8 + d10 / 2D); + + for (int targetX = xStart; targetX <= xEnd; targetX++) { + double d12 = ((targetX + 0.5D) - d6) / (d10 / 2D); + if (d12 * d12 >= 1.0D) + continue; + + for (int targetY = yStart; targetY <= yEnd; targetY++) { + double d13 = ((targetY + 0.5D) - d7) / (d11 / 2D); + if (d12 * d12 + d13 * d13 >= 1.0D) + continue; + + for (int targetZ = zStart; targetZ <= zEnd; targetZ++) { + double d14 = ((targetZ + 0.5D) - d8) / (d10 / 2D); + if (d12 * d12 + d13 * d13 + d14 * d14 < 1.0D && world.getBlock(targetX, targetY, targetZ) == Blocks.stone) { + world.setBlock(targetX, targetY, targetZ, mineableBlock, mineableBlockMeta, Defaults.FLAG_BLOCK_SYNCH); + hasGenerated = true; + } + } + } + } + } + + return hasGenerated; + } + +} diff --git a/forestry_common/core/forestry/plugins/NativePlugin.java b/forestry_common/core/forestry/plugins/NativePlugin.java new file mode 100755 index 000000000..6d78e510c --- /dev/null +++ b/forestry_common/core/forestry/plugins/NativePlugin.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.Random; + +import net.minecraft.command.ICommand; +import net.minecraft.world.World; + +import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage; +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.core.IPlugin; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.interfaces.IPickupHandler; +import forestry.core.interfaces.IResupplyHandler; +import forestry.core.interfaces.ISaveEventHandler; + +public abstract class NativePlugin implements IPlugin { + + @Override + public void preInit() { + registerItems(); + } + + @Override + public void doInit() { + registerBackpackItems(); + registerCrates(); + } + + @Override + public void postInit() { + registerRecipes(); + } + + public boolean processIMCMessage(IMCMessage message) { + return false; + } + + public IGuiHandler getGuiHandler() { + return null; + } + + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } + + public void generateSurface(World world, Random rand, int chunkX, int chunkZ) { + } + + public IPacketHandler getPacketHandler() { + return null; + } + + public IPickupHandler getPickupHandler() { + return null; + } + + public IResupplyHandler getResupplyHandler() { + return null; + } + + public ICommand[] getConsoleCommands() { + return null; + } + + protected abstract void registerItems(); + + protected abstract void registerBackpackItems(); + + protected abstract void registerCrates(); + + protected abstract void registerRecipes(); + +} diff --git a/forestry_common/core/forestry/plugins/PluginBuildCraft.java b/forestry_common/core/forestry/plugins/PluginBuildCraft.java new file mode 100755 index 000000000..d95e36654 --- /dev/null +++ b/forestry_common/core/forestry/plugins/PluginBuildCraft.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.LinkedList; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.fuels.IronEngineCoolant; +import buildcraft.api.fuels.IronEngineFuel; +import buildcraft.api.gates.ActionManager; +import buildcraft.api.gates.ITrigger; +import buildcraft.api.gates.ITriggerProvider; +import buildcraft.api.power.PowerHandler; +import buildcraft.api.power.PowerHandler.PowerReceiver; +import buildcraft.api.recipes.BuildcraftRecipes; +import buildcraft.api.transport.IPipeTile; + +import forestry.api.core.IPlugin; +import forestry.api.core.PluginInfo; +import forestry.core.GameMode; +import forestry.core.config.Config; +import forestry.core.config.Configuration; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.config.Property; +import forestry.core.gadgets.TileForestry; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; + +@PluginInfo(pluginID = "BC3", name = "BuildCraft 3", author = "SirSengir", url = Defaults.URL, description = "Compatibility plugin for BuildCraft 3.") +public class PluginBuildCraft implements IPlugin, ITriggerProvider { + + public static PluginBuildCraft instance; + public static Configuration config; + // Ignore Buildcraft? + public static boolean ignore; + public static Item wrench; + public static Item stoneGear; + public static Item pipeWaterproof; + + public PluginBuildCraft() { + if (PluginBuildCraft.instance == null) + PluginBuildCraft.instance = this; + } + + /** + * @return true if BuildCraftCore is installed. + */ + @Override + public boolean isAvailable() { + return (Proxies.common.isModLoaded("BuildCraft|Core") && Proxies.common.isModLoaded("BuildCraft|Transport")); + } + + @Override + public void doInit() { + config = Config.config; + + Property buildcraftignore = config.get("buildcraft.ignore", Config.CATEGORY_COMMON, false); + buildcraftignore.Comment = "set to true to ignore buildcraft"; + PluginBuildCraft.ignore = Boolean.parseBoolean(buildcraftignore.Value); + + IronEngineCoolant.addCoolant(LiquidHelper.getLiquid(Defaults.LIQUID_ICE, 1).getFluid(), 10.0f); + + addIronEngineFuel(LiquidHelper.getLiquid(Defaults.LIQUID_ETHANOL, 1).getFluid(), 4, + Defaults.ENGINE_CYCLE_DURATION_ETHANOL * GameMode.getGameMode().getFloatSetting("fuel.ethanol.combustion")); + + // Add recipe for ethanol + addRefineryRecipe(LiquidHelper.getLiquid(Defaults.LIQUID_BIOMASS, 4), null, LiquidHelper.getLiquid(Defaults.LIQUID_ETHANOL, 1), 10, 1); + + // Add custom trigger handler + ActionManager.registerTriggerProvider(this); + + initStoneGear(); + initWaterproof(); + initLiquids(); + } + + @Override + public void postInit() { + } + + private void initLiquids() { + LiquidHelper.injectWaxContainer(Defaults.LIQUID_OIL, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleOil.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectWaxContainer(Defaults.LIQUID_FUEL, Defaults.BUCKET_VOLUME, ForestryItem.waxCapsuleFuel.getItemStack(), ForestryItem.waxCapsule.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_OIL, Defaults.BUCKET_VOLUME, ForestryItem.refractoryOil.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + LiquidHelper.injectRefractoryContainer(Defaults.LIQUID_FUEL, Defaults.BUCKET_VOLUME, ForestryItem.refractoryFuel.getItemStack(), ForestryItem.refractoryEmpty.getItemStack()); + LiquidHelper.injectTinContainer(Defaults.LIQUID_OIL, Defaults.BUCKET_VOLUME, ForestryItem.canOil.getItemStack(), ForestryItem.canEmpty.getItemStack()); + LiquidHelper.injectTinContainer(Defaults.LIQUID_FUEL, Defaults.BUCKET_VOLUME, ForestryItem.canFuel.getItemStack(), ForestryItem.canEmpty.getItemStack()); + + } + + private void addIronEngineFuel(Fluid fuel, float powerPerCycle, float totalBurningTime) { + IronEngineFuel.addFuel(fuel, (int) powerPerCycle, (int) totalBurningTime); + } + + private void addRefineryRecipe(FluidStack ingredient1, FluidStack ingredient2, FluidStack result, int energy, int delay) { + BuildcraftRecipes.refinery.addRecipe(ingredient1, ingredient2, result, energy, delay); + + } + + private void initStoneGear() { + try { + stoneGear = (Item) Class.forName("buildcraft.BuildCraftCore").getField("stoneGearItem").get(null); + } catch (Exception ex) { + Proxies.log.fine("No BuildCraft stone gear found."); + return; + } + } + + private void initWaterproof() { + try { + pipeWaterproof = (Item) Class.forName("buildcraft.BuildCraftTransport").getField("pipeWaterproof").get(null); + } catch (Exception ex) { + Proxies.log.fine("No BuildCraft pipe waterproof found."); + return; + } + + Proxies.common.addRecipe(new ItemStack(pipeWaterproof), new Object[] { "#", Character.valueOf('#'), ForestryItem.beeswax }); + } + + public double invokeUseEnergyMethod(PowerHandler workProvider, float min, float max, boolean doUse) { + return workProvider.useEnergy(min, max, doUse); + } + + public void invokeReceiveEnergyMethod(PowerHandler.Type type, PowerReceiver receiver, double extractedEnergy, ForgeDirection from) { + receiver.receiveEnergy(type, extractedEnergy, from); + } + + // / ITRIGGERPROVIDER + @Override + public LinkedList getPipeTriggers(IPipeTile pipe) { + return null; + } + + @Override + public LinkedList getNeighborTriggers(Block block, TileEntity tile) { + if (tile instanceof TileForestry) + return ((TileForestry) tile).getCustomTriggers(); + + return null; + } + + @Override + public void preInit() { + } +} diff --git a/forestry_common/core/forestry/plugins/PluginCore.java b/forestry_common/core/forestry/plugins/PluginCore.java new file mode 100755 index 000000000..cf93aaf6b --- /dev/null +++ b/forestry_common/core/forestry/plugins/PluginCore.java @@ -0,0 +1,608 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.LinkedList; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.command.ICommand; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.item.crafting.IRecipe; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.IFuelHandler; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.common.registry.GameRegistry; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.oredict.OreDictionary; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.core.PluginInfo; +import forestry.api.core.Tabs; +import forestry.api.genetics.AlleleManager; +import forestry.core.CommandForestry; +import forestry.core.CreativeTabForestry; +import forestry.core.GameMode; +import forestry.core.PickupHandlerCore; +import forestry.core.SaveEventHandlerCore; +import forestry.core.circuits.CircuitRegistry; +import forestry.core.circuits.ItemCircuitBoard; +import forestry.core.circuits.ItemSolderingIron; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.BlockBase; +import forestry.core.gadgets.BlockResource; +import forestry.core.gadgets.BlockSoil; +import forestry.core.gadgets.BlockStainedGlass; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.gadgets.TileAnalyzer; +import forestry.core.gadgets.TileEscritoire; +import forestry.core.genetics.Allele; +import forestry.core.genetics.AlleleRegistry; +import forestry.core.genetics.ItemResearchNote; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPickupHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.items.ItemArmorNaturalist; +import forestry.core.items.ItemAssemblyKit; +import forestry.core.items.ItemCrated; +import forestry.core.items.ItemForestry; +import forestry.core.items.ItemForestryBlock; +import forestry.core.items.ItemForestryPickaxe; +import forestry.core.items.ItemForestryShovel; +import forestry.core.items.ItemFruit; +import forestry.core.items.ItemLiquidContainer; +import forestry.core.items.ItemLiquidContainer.EnumContainerType; +import forestry.core.items.ItemMisc; +import forestry.core.items.ItemOverlay; +import forestry.core.items.ItemOverlay.OverlayInfo; +import forestry.core.items.ItemPipette; +import forestry.core.items.ItemScoop; +import forestry.core.items.ItemWrench; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryModEnvWarningCallable; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.core.utils.Utils; + +@PluginInfo(pluginID = "Core", name = "Core", author = "SirSengir", url = Defaults.URL, description = "Core mechanics for Forestry. Required by all other plugins.") +public class PluginCore extends NativePlugin implements IFuelHandler { + + public static MachineDefinition definitionAnalyzer; + public static MachineDefinition definitionEscritoire; + // ICrashCallable for highlighting certain mods during crashes. + public static ForestryModEnvWarningCallable crashCallable; + + @Override + public void preInit() { + super.preInit(); + + ChipsetManager.solderManager = new ItemSolderingIron.SolderManager(); + + CircuitRegistry circuitRegistry = new CircuitRegistry(); + ChipsetManager.circuitRegistry = circuitRegistry; + circuitRegistry.initialize(); + + AlleleRegistry alleleRegistry = new AlleleRegistry(); + AlleleManager.alleleRegistry = alleleRegistry; + alleleRegistry.initialize(); + + Allele.initialize(); + + ForestryBlock.core = new BlockBase(Material.iron, true); + ForestryBlock.core.setBlockName("for.core"); + Proxies.common.registerBlock(ForestryBlock.core, ItemForestryBlock.class); + + definitionAnalyzer = ForestryBlock.core.addDefinition(new MachineDefinition(Defaults.DEFINITION_ANALYZER_META, "forestry.Analyzer", TileAnalyzer.class, + PluginApiculture.proxy.getRendererAnalyzer(Defaults.TEXTURE_PATH_BLOCKS + "/analyzer_"), new IRecipe[0])); + definitionEscritoire = ForestryBlock.core.addDefinition(new MachineDefinition(Defaults.DEFINITION_ESCRITOIRE_META, "forestry.Escritoire", TileEscritoire.class, + Proxies.render.getRenderEscritoire(), new IRecipe[0])); + + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) + $$______$$(); + + + + ForestryBlock.soil = new BlockSoil().setBlockName("soil"); + Proxies.common.registerBlock(ForestryBlock.soil, ItemForestryBlock.class); + ForestryBlock.soil.setHarvestLevel("shovel", 0, 0); + ForestryBlock.soil.setHarvestLevel("shovel", 0, 1); + + ForestryBlock.resources = new BlockResource().setBlockName("resources"); + Proxies.common.registerBlock(ForestryBlock.resources, ItemForestryBlock.class); + ForestryBlock.resources.setHarvestLevel("pickaxe", 1, 0); + ForestryBlock.resources.setHarvestLevel("pickaxe", 1, 1); + ForestryBlock.resources.setHarvestLevel("pickaxe", 1, 2); + + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) + $$____$$(); + + OreDictionary.registerOre("oreApatite", new ItemStack(ForestryBlock.resources, 1, 0)); + OreDictionary.registerOre("oreCopper", new ItemStack(ForestryBlock.resources, 1, 1)); + OreDictionary.registerOre("oreTin", new ItemStack(ForestryBlock.resources, 1, 2)); + + ForestryBlock.glass = new BlockStainedGlass().setBlockName("stained"); + Proxies.common.registerBlock(ForestryBlock.glass, ItemForestryBlock.class); + + /* SMELTING RECIPES */ + FurnaceRecipes.smelting().func_151394_a(new ItemStack(ForestryBlock.resources, 1), ForestryItem.ingotCopper.getItemStack(), 0.5f); + FurnaceRecipes.smelting().func_151394_a(new ItemStack(ForestryBlock.resources, 2), ForestryItem.ingotTin.getItemStack(), 0.5f); + + GameRegistry.registerFuelHandler(this); + + } + + @Override + public void doInit() { + super.doInit(); + definitionAnalyzer.recipes = $$_____$$(ForestryBlock.core, Defaults.DEFINITION_ANALYZER_META); + + for ($___$ prop : $________$) { + prop.$$_______$$(); + } + + definitionAnalyzer.register(); + definitionEscritoire.register(); + crashCallable = new ForestryModEnvWarningCallable(); + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public IGuiHandler getGuiHandler() { + return null; + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return new SaveEventHandlerCore(); + } + + @Override + protected void registerItems() { + + // / FERTILIZERS + ForestryItem.fertilizerBio.registerItem((new ItemForestry()), "fertilizerBio"); + ForestryItem.fertilizerCompound.registerItem((new ItemForestry()).setBonemeal(true), "fertilizerCompound"); + + // / GEMS + ForestryItem.apatite.registerItem((new ItemForestry()), "apatite"); + OreDictionary.registerOre("gemApatite", ForestryItem.apatite.getItemStack()); + + ForestryItem.researchNote.registerItem(new ItemResearchNote(), "researchNote"); + + // / INGOTS + ForestryItem.ingotCopper.registerItem(new ItemForestry(), "ingotCopper"); + ForestryItem.ingotTin.registerItem(new ItemForestry(), "ingotTin"); + ForestryItem.ingotBronze.registerItem(new ItemForestry(), "ingotBronze"); + + OreDictionary.registerOre("ingotCopper", ForestryItem.ingotCopper.getItemStack()); + OreDictionary.registerOre("ingotTin", ForestryItem.ingotTin.getItemStack()); + OreDictionary.registerOre("ingotBronze", ForestryItem.ingotBronze.getItemStack()); + + // / TOOLS + ForestryItem.wrench.registerItem((new ItemWrench()), "wrench"); + ForestryItem.pipette.registerItem(new ItemPipette(), "pipette"); + ForestryItem.scoop.registerItem(new ItemScoop(), "scoop"); + ForestryItem.scoop.item().setHarvestLevel("scoop", 3); + + // / MACHINES + ForestryItem.sturdyCasing.registerItem((new ItemForestry()), "sturdyMachine"); + ForestryItem.hardenedCasing.registerItem((new ItemForestry()), "hardenedMachine"); + ForestryItem.impregnatedCasing.registerItem((new ItemForestry()), "impregnatedCasing"); + + ForestryItem.craftingMaterial.registerItem(new ItemMisc(), "craftingMaterial"); + + /* ARMOR */ + ForestryItem.naturalistHat.registerItem(new ItemArmorNaturalist(0), "naturalistHelmet"); + + // / DISCONTINUED + // ForestryItem.vialEmpty = (new + // ItemForestry(Config.getOrCreateIntProperty("vialEmpty", + // Config.CATEGORY_ITEM, Defaults.ID_ITEM_VIAL_EMPTY))) + // .setItemName("vialEmpty").setIconIndex(10); + ForestryItem.vialCatalyst.registerItem((new ItemForestry()), "vialCatalyst"); + + + $$_________$$(); + + // / EMPTY LIQUID CONTAINERS + ForestryItem.waxCapsule.registerItem(new ItemLiquidContainer(EnumContainerType.CAPSULE, -1).setMaxStackSize(64), "waxCapsule"); + ForestryItem.canEmpty.registerItem(new ItemLiquidContainer(EnumContainerType.CAN, -1).setMaxStackSize(64), "canEmpty"); + ForestryItem.refractoryEmpty.registerItem(new ItemLiquidContainer(EnumContainerType.REFRACTORY, -1).setMaxStackSize(64), "refractoryEmpty"); + + // / BUCKETS + ForestryItem.bucketBiomass.registerItem(new ItemForestry().setContainerItem(Items.bucket).setMaxStackSize(1), "bucketBiomass"); + ForestryItem.bucketBiofuel.registerItem(new ItemForestry().setContainerItem(Items.bucket).setMaxStackSize(1), "bucketBiofuel"); + + // / WAX CAPSULES + ForestryItem.waxCapsuleWater.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0x2432ec)), "waxCapsuleWater"); + ForestryItem.waxCapsuleBiomass.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0x83d41c)), "waxCapsuleBiomass"); + ForestryItem.waxCapsuleBiofuel.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0xff7909)), "waxCapsuleBiofuel"); + ForestryItem.waxCapsuleOil.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0x404040)), "waxCapsuleOil"); + ForestryItem.waxCapsuleFuel.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0xffff00)), "waxCapsuleFuel"); + ForestryItem.waxCapsuleSeedOil.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0xffffa9)), "waxCapsuleSeedOil"); + ForestryItem.waxCapsuleHoney.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0xffda47)).setDrink(Defaults.FOOD_HONEY_HEAL, Defaults.FOOD_HONEY_SATURATION), "waxCapsuleHoney"); + ForestryItem.waxCapsuleJuice.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0x99d04e)).setDrink(Defaults.FOOD_JUICE_HEAL, Defaults.FOOD_JUICE_SATURATION), "waxCapsuleJuice"); + ForestryItem.waxCapsuleIce.registerItem((new ItemLiquidContainer(EnumContainerType.CAPSULE, 0xdcffff)), "waxCapsuleIce"); + + // / CANS + ForestryItem.canWater.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0x2432ec)), "waterCan"); + ForestryItem.canBiomass.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0x83d41c)), "biomassCan"); + ForestryItem.canBiofuel.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0xff7909)), "biofuelCan"); + ForestryItem.canOil.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0x404040)), "canOil"); + ForestryItem.canFuel.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0xffff00)), "canFuel"); + ForestryItem.canLava.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0xfd461f)), "canLava"); + ForestryItem.canSeedOil.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0xffffa9)), "canSeedOil"); + ForestryItem.canHoney.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0xffda47)).setDrink(Defaults.FOOD_HONEY_HEAL, Defaults.FOOD_HONEY_SATURATION), "canHoney"); + ForestryItem.canJuice.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0x99d04e)).setDrink(Defaults.FOOD_JUICE_HEAL, Defaults.FOOD_JUICE_SATURATION), "canJuice"); + ForestryItem.canIce.registerItem((new ItemLiquidContainer(EnumContainerType.CAN, 0xdcffff)), "canIce"); + + // / REFRACTORY CAPSULES + ForestryItem.refractoryWater.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0x2432ec)), "refractoryWater"); + ForestryItem.refractoryBiomass.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0x83d41c)), "refractoryBiomass"); + ForestryItem.refractoryBiofuel.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0xff7909)), "refractoryBiofuel"); + ForestryItem.refractoryOil.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0x404040)), "refractoryOil"); + ForestryItem.refractoryFuel.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0xffff00)), "refractoryFuel"); + ForestryItem.refractoryLava.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0xfd461f)), "refractoryLava"); + ForestryItem.refractorySeedOil.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0xffffa9)), "refractorySeedOil"); + ForestryItem.refractoryHoney.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0xffda47)).setDrink(Defaults.FOOD_HONEY_HEAL, Defaults.FOOD_HONEY_SATURATION), "refractoryHoney"); + ForestryItem.refractoryJuice.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0x99d04e)).setDrink(Defaults.FOOD_JUICE_HEAL, Defaults.FOOD_JUICE_SATURATION), "refractoryJuice"); + ForestryItem.refractoryIce.registerItem((new ItemLiquidContainer(EnumContainerType.REFRACTORY, 0xdcffff)), "refractoryIce"); + + } + + private void $$_________$$() { + + // / PEAT PRODUCTION + ForestryItem.peat.registerItem((new ItemForestry()), "peat"); + OreDictionary.registerOre("brickPeat", ForestryItem.peat.getItemStack()); + + ForestryItem.ash.registerItem((new ItemForestry()), "ash"); + OreDictionary.registerOre("dustAsh", ForestryItem.ash.getItemStack()); + + Proxies.common.addSmelting(ForestryItem.peat.getItemStack(), ForestryItem.ash.getItemStack()); + ForestryItem.bituminousPeat.registerItem(new ItemForestry(), "bituminousPeat"); + + // / GEARS + ForestryItem.gearBronze.registerItem((new ItemForestry()), "gearBronze"); + OreDictionary.registerOre("gearBronze", ForestryItem.gearBronze.getItemStack()); + ForestryItem.gearCopper.registerItem((new ItemForestry()), "gearCopper"); + OreDictionary.registerOre("gearCopper", ForestryItem.gearCopper.getItemStack()); + ForestryItem.gearTin.registerItem((new ItemForestry()), "gearTin"); + OreDictionary.registerOre("gearTin", ForestryItem.gearTin.getItemStack()); + + // / CIRCUIT BOARDS + ForestryItem.circuitboards.registerItem(new ItemCircuitBoard(), "chipsets"); + ForestryItem.solderingIron.registerItem(new ItemSolderingIron(), "solderingIron"); + ForestryItem.tubes.registerItem(new ItemOverlay(CreativeTabForestry.tabForestry, + new OverlayInfo[] { new OverlayInfo("ex-0", 0xffffff, 0xe3b78e), new OverlayInfo("ex-1", 0xffffff, 0xe1eef4), + new OverlayInfo("ex-2", 0xffffff, 0xddc276), new OverlayInfo("ex-3", 0xffffff, 0xd8d8d8), new OverlayInfo("ex-4", 0xffffff, 0xffff8b), + new OverlayInfo("ex-5", 0xffffff, 0x7bd1b8), new OverlayInfo("ex-6", 0xffffff, 0x866bc0), new OverlayInfo("ex-7", 0xfff87e, 0xd96600), + new OverlayInfo("ex-8", 0xffffff, 0x444444), new OverlayInfo("ex-9", 0xffffff, 0xbfffdd), new OverlayInfo("ex-10", 0xffffff, 0x68ccee), + new OverlayInfo("ex-11", 0xffffff, 0x1c57c6) }), "thermionicTubes"); + + // / CRATES AND CARTONS + ForestryItem.carton.registerItem((new ItemForestry()), "carton"); + ForestryItem.crate.registerItem((new ItemForestry()), "crate"); + + // / CRAFTING CARPENTER + ForestryItem.stickImpregnated.registerItem((new ItemForestry()), "oakStick"); + ForestryItem.woodPulp.registerItem((new ItemForestry()), "woodPulp"); + OreDictionary.registerOre("pulpWood", ForestryItem.woodPulp.getItemStack()); + + // / RECLAMATION + ForestryItem.brokenBronzePickaxe.registerItem((new ItemForestry()), "brokenBronzePickaxe"); + ForestryItem.brokenBronzeShovel.registerItem((new ItemForestry()), "brokenBronzeShovel"); + + // / TOOLS + ForestryItem.bronzePickaxe.registerItem(new ItemForestryPickaxe(ForestryItem.brokenBronzePickaxe.getItemStack()), "bronzePickaxe"); + ForestryItem.bronzePickaxe.item().setHarvestLevel("pickaxe", 3); + MinecraftForge.EVENT_BUS.register(ForestryItem.bronzePickaxe.item()); + ForestryItem.bronzeShovel.registerItem(new ItemForestryShovel(ForestryItem.brokenBronzeShovel.getItemStack()), "bronzeShovel"); + ForestryItem.bronzeShovel.item().setHarvestLevel("shovel", 3); + MinecraftForge.EVENT_BUS.register(ForestryItem.bronzeShovel.item()); + + // / ASSEMBLY KITS + ForestryItem.kitShovel.registerItem(new ItemAssemblyKit(ForestryItem.bronzeShovel.getItemStack()), "kitShovel"); + ForestryItem.kitPickaxe.registerItem(new ItemAssemblyKit(ForestryItem.bronzePickaxe.getItemStack()), "kitPickaxe"); + + // / MOISTENER RESOURCES + ForestryItem.mouldyWheat.registerItem((new ItemForestry()), "mouldyWheat"); + ForestryItem.decayingWheat.registerItem((new ItemForestry()), "decayingWheat"); + ForestryItem.mulch.registerItem((new ItemForestry()), "mulch"); + + // / RAINMAKER SUBSTRATES + ForestryItem.iodineCharge.registerItem((new ItemForestry()), "iodineCapsule"); + + ForestryItem.phosphor.registerItem((new ItemForestry()), "phosphor"); + + // / BEE RESOURCES + ForestryItem.beeswax.registerItem(new ItemForestry().setCreativeTab(Tabs.tabApiculture), "beeswax"); + OreDictionary.registerOre("itemBeeswax", ForestryItem.beeswax.getItemStack()); + + ForestryItem.refractoryWax.registerItem(new ItemForestry(), "refractoryWax"); + + // FRUITS + ForestryItem.fruits.registerItem(new ItemFruit(), "fruits"); + + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerCrates() { + // / CRATES + ForestryItem.cratedWood.registerItem(new ItemCrated(new ItemStack(Blocks.log)), "cratedWood"); + ForestryItem.cratedCobblestone.registerItem(new ItemCrated(new ItemStack(Blocks.cobblestone)), "cratedCobblestone"); + ForestryItem.cratedDirt.registerItem(new ItemCrated(new ItemStack(Blocks.dirt)), "cratedDirt"); + ForestryItem.cratedStone.registerItem(new ItemCrated(new ItemStack(Blocks.stone)), "cratedStone"); + ForestryItem.cratedBrick.registerItem(new ItemCrated(new ItemStack(Blocks.brick_block)), "cratedBrick"); + ForestryItem.cratedCacti.registerItem(new ItemCrated(new ItemStack(Blocks.cactus)), "cratedCacti"); + ForestryItem.cratedSand.registerItem(new ItemCrated(new ItemStack(Blocks.sand)), "cratedSand"); + ForestryItem.cratedObsidian.registerItem(new ItemCrated(new ItemStack(Blocks.obsidian)), "cratedObsidian"); + ForestryItem.cratedNetherrack.registerItem(new ItemCrated(new ItemStack(Blocks.netherrack)), "cratedNetherrack"); + ForestryItem.cratedSoulsand.registerItem(new ItemCrated(new ItemStack(Blocks.soul_sand)), "cratedSoulsand"); + ForestryItem.cratedSandstone.registerItem(new ItemCrated(new ItemStack(Blocks.sandstone)), "cratedSandstone"); + ForestryItem.cratedBogearth.registerItem(new ItemCrated(new ItemStack(ForestryBlock.soil, 1, 1)), "cratedBogearth"); + ForestryItem.cratedHumus.registerItem(new ItemCrated(new ItemStack(ForestryBlock.soil, 1, 0)), "cratedHumus"); + ForestryItem.cratedNetherbrick.registerItem(new ItemCrated(new ItemStack(Blocks.nether_brick)), "cratedNetherbrick"); + ForestryItem.cratedPeat.registerItem(new ItemCrated(ForestryItem.peat.getItemStack()), "cratedPeat"); + ForestryItem.cratedApatite.registerItem(new ItemCrated(ForestryItem.apatite.getItemStack()), "cratedApatite"); + ForestryItem.cratedFertilizer.registerItem(new ItemCrated(ForestryItem.fertilizerCompound.getItemStack()), "cratedFertilizer"); + ForestryItem.cratedTin.registerItem(new ItemCrated(ForestryItem.ingotTin.getItemStack()), "cratedTin"); + ForestryItem.cratedCopper.registerItem(new ItemCrated(ForestryItem.ingotCopper.getItemStack()), "cratedCopper"); + ForestryItem.cratedBronze.registerItem(new ItemCrated(ForestryItem.ingotBronze.getItemStack()), "cratedBronze"); + ForestryItem.cratedWheat.registerItem(new ItemCrated(new ItemStack(Items.wheat)), "cratedWheat"); + ForestryItem.cratedMycelium.registerItem(new ItemCrated(new ItemStack(Blocks.mycelium)), "cratedMycelium"); + ForestryItem.cratedMulch.registerItem(new ItemCrated(ForestryItem.mulch.getItemStack()), "cratedMulch"); + ForestryItem.cratedSilver.registerItem(new ItemCrated(), "cratedSilver"); + ForestryItem.cratedBrass.registerItem(new ItemCrated(), "cratedBrass"); + ForestryItem.cratedNikolite.registerItem(new ItemCrated(), "cratedNikolite"); + ForestryItem.cratedCookies.registerItem(new ItemCrated(new ItemStack(Items.cookie)), "cratedCookies"); + ForestryItem.cratedRedstone.registerItem(new ItemCrated(new ItemStack(Items.redstone)), "cratedRedstone"); + ForestryItem.cratedLapis.registerItem(new ItemCrated(new ItemStack(Items.dye, 1, 4)), "cratedLapis"); + ForestryItem.cratedReeds.registerItem(new ItemCrated(new ItemStack(Items.reeds)), "cratedReeds"); + ForestryItem.cratedClay.registerItem(new ItemCrated(new ItemStack(Items.clay_ball)), "cratedClay"); + ForestryItem.cratedGlowstone.registerItem(new ItemCrated(new ItemStack(Items.glowstone_dust)), "cratedGlowstone"); + ForestryItem.cratedApples.registerItem(new ItemCrated(new ItemStack(Items.apple)), "cratedApples"); + ForestryItem.cratedNetherwart.registerItem(new ItemCrated(new ItemStack(Items.nether_wart)), "cratedNetherwart"); + ForestryItem.cratedResin.registerItem(new ItemCrated(), "cratedResin"); + ForestryItem.cratedRubber.registerItem(new ItemCrated(), "cratedRubber"); + ForestryItem.cratedScrap.registerItem(new ItemCrated(), "cratedScrap"); + ForestryItem.cratedUUM.registerItem(new ItemCrated(), "cratedUUM"); + ForestryItem.cratedPhosphor.registerItem(new ItemCrated(ForestryItem.phosphor.getItemStack()), "cratedPhosphor"); + ForestryItem.cratedAsh.registerItem(new ItemCrated(ForestryItem.ash.getItemStack()), "cratedAsh"); + ForestryItem.cratedCharcoal.registerItem(new ItemCrated(new ItemStack(Items.coal, 1, 1)), "cratedCharcoal"); + ForestryItem.cratedGravel.registerItem(new ItemCrated(new ItemStack(Blocks.gravel)), "cratedGravel"); + ForestryItem.cratedCoal.registerItem(new ItemCrated(new ItemStack(Items.coal, 1, 0)), "cratedCoal"); + ForestryItem.cratedSeeds.registerItem(new ItemCrated(new ItemStack(Items.wheat_seeds)), "cratedSeeds"); + ForestryItem.cratedSaplings.registerItem(new ItemCrated(new ItemStack(Blocks.sapling)), "cratedSaplings"); + } + + @Override + protected void registerRecipes() { + + /* BRONZE INGOTS */ + if (Config.getCraftingBronzeEnabled()) { + Proxies.common.addShapelessRecipe(ForestryItem.ingotBronze.getItemStack(4), "ingotTin", "ingotCopper", "ingotCopper", "ingotCopper"); + } + + /* STURDY MACHINE */ + Proxies.common.addRecipe(ForestryItem.sturdyCasing.getItemStack(), "###", "# #", "###", '#', "ingotBronze"); + + // / EMPTY CANS + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.can"), " # ", "# #", '#', "ingotTin"); + + // / GEARS + if (PluginBuildCraft.stoneGear != null) { + + Proxies.common.addRecipe(ForestryItem.gearBronze.getItemStack(), " # ", "#Y#", " # ", '#', "ingotBronze", 'Y', PluginBuildCraft.stoneGear); + Proxies.common.addRecipe(ForestryItem.gearCopper.getItemStack(), " # ", "#Y#", " # ", '#', "ingotCopper", 'Y', PluginBuildCraft.stoneGear); + Proxies.common.addRecipe(ForestryItem.gearTin.getItemStack(), " # ", "#Y#", " # ", '#', "ingotTin", 'Y', PluginBuildCraft.stoneGear); + + } else { + + Proxies.common.addRecipe(ForestryItem.gearBronze.getItemStack(), " # ", "#X#", " # ", '#', "ingotBronze", 'X', "ingotCopper"); + Proxies.common.addRecipe(ForestryItem.gearCopper.getItemStack(), " # ", "#X#", " # ", '#', "ingotCopper", 'X', "ingotCopper"); + Proxies.common.addRecipe(ForestryItem.gearTin.getItemStack(), " # ", "#X#", " # ", '#', "ingotTin", 'X', "ingotCopper"); + } + + // / SURVIVALIST TOOLS + Proxies.common.addRecipe(ForestryItem.bronzePickaxe.getItemStack(), " X ", " X ", "###", '#', "ingotBronze", 'X', "stickWood"); + Proxies.common.addRecipe(ForestryItem.bronzeShovel.getItemStack(), " X ", " X ", " # ", '#', "ingotBronze", 'X', "stickWood"); + Proxies.common.addShapelessRecipe(ForestryItem.kitPickaxe.getItemStack(), ForestryItem.bronzePickaxe, ForestryItem.carton); + Proxies.common.addShapelessRecipe(ForestryItem.kitShovel.getItemStack(), ForestryItem.bronzeShovel, ForestryItem.carton); + + /* NATURALIST'S ARMOR */ + Proxies.common.addRecipe(ForestryItem.naturalistHat.getItemStack(), " X ", "Y Y", 'X', "ingotBronze", 'Y', Blocks.glass_pane); + + // / WRENCH + Proxies.common.addRecipe(ForestryItem.wrench.getItemStack(), "# #", " # ", " # ", '#', "ingotBronze"); + + // Manure and Fertilizer + if (GameMode.getGameMode().getStackSetting("recipe.output.compost.wheat").stackSize > 0) + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.compost.wheat"), " X ", "X#X", " X ", '#', Blocks.dirt, 'X', Items.wheat); + if (GameMode.getGameMode().getStackSetting("recipe.output.compost.ash").stackSize > 0) + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.compost.ash"), " X ", "X#X", " X ", '#', Blocks.dirt, 'X', "dustAsh"); + if (GameMode.getGameMode().getStackSetting("recipe.output.fertilizer.apatite").stackSize > 0) + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.fertilizer.apatite"), " # ", " X ", " # ", '#', Blocks.sand, 'X', "gemApatite"); + if (GameMode.getGameMode().getStackSetting("recipe.output.fertilizer.ash").stackSize > 0) + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.fertilizer.ash"), "###", "#X#", "###", '#', "dustAsh", 'X', "gemApatite"); + + // Humus + if (GameMode.getGameMode().getStackSetting("recipe.output.humus.compost").stackSize > 0) + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.humus.compost"), "###", "#X#", "###", '#', Blocks.dirt, 'X', ForestryItem.fertilizerBio); + if (GameMode.getGameMode().getStackSetting("recipe.output.humus.fertilizer").stackSize > 0) + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.humus.fertilizer"), "###", "#X#", "###", '#', Blocks.dirt, 'X', ForestryItem.fertilizerCompound); + + // Bog earth + if (GameMode.getGameMode().getStackSetting("recipe.output.bogearth.bucket").stackSize > 0) + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.bogearth.bucket"), "#Y#", "YXY", "#Y#", '#', Blocks.dirt, 'X', Items.water_bucket, 'Y', Blocks.sand); + + if (GameMode.getGameMode().getStackSetting("recipe.output.bogearth.can").stackSize > 0) { + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.bogearth.can"), "#Y#", "YXY", "#Y#", '#', Blocks.dirt, 'X', ForestryItem.canWater, 'Y', Blocks.sand); + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.bogearth.can"), "#Y#", "YXY", "#Y#", '#', Blocks.dirt, 'X', ForestryItem.waxCapsuleWater, 'Y', Blocks.sand); + Proxies.common.addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.bogearth.can"), "#Y#", "YXY", "#Y#", '#', Blocks.dirt, 'X', ForestryItem.refractoryWater, 'Y', Blocks.sand); + } + + // Vials and catalyst + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(3), "###", "YXY", '#', ForestryItem.waxCapsule.item(), 'X', Items.bone, 'Y', ForestryItem.fertilizerCompound); + Proxies.common.addRecipe(ForestryItem.vialCatalyst.getItemStack(3), "###", "YXY", '#', ForestryItem.canEmpty.item(), 'X', Items.bone, 'Y', ForestryItem.fertilizerCompound); + + // Crafting Material + Proxies.common.addRecipe(new ItemStack(Items.string), "#", "#", "#", '#', ForestryItem.craftingMaterial.getItemStack(1, 2)); + + // / Pipette + Proxies.common.addRecipe(ForestryItem.pipette.getItemStack(), " #", " X ", "X ", 'X', Blocks.glass_pane, '#', new ItemStack(Blocks.wool, 1, Defaults.WILDCARD)); + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } + + @Override + public IPickupHandler getPickupHandler() { + return new PickupHandlerCore(); + } + + @Override + public ICommand[] getConsoleCommands() { + return new ICommand[] { new CommandForestry() }; + } + + @Override + public int getBurnTime(ItemStack fuel) { + if (fuel != null && fuel.getItem() == ForestryItem.peat.item()) + return 2000; + if (fuel != null && fuel.getItem() == ForestryItem.bituminousPeat.item()) + return 4200; + + return 0; + } + + /*@Override + public boolean processIMCMessage(IMCMessage message) { + if (message.key.equals(new String(new byte[] { 115, 101, 99, 117, 114, 105, 116, 121, 86, 105, 111, 108, 97, 116, 105, 111, 110 }))) + Config.invalidFingerprint = true; + return false; + }*/ + public IRecipe[] $$_____$$(Block block, int meta) { + ArrayList recipes = new ArrayList(); + if (ForestryItem.beealyzer != null) + recipes.add(ShapedRecipeCustom.createShapedRecipe(new ItemStack(block, 1, meta), "XTX", " Y ", "X X", 'Y', ForestryItem.sturdyCasing, 'T', ForestryItem.beealyzer, 'X', "ingotBronze")); + + if (ForestryItem.treealyzer != null) + recipes.add(ShapedRecipeCustom.createShapedRecipe(new ItemStack(block, 1, meta), "XTX", " Y ", "X X", 'Y', ForestryItem.sturdyCasing, 'T', ForestryItem.treealyzer, 'X', "ingotBronze")); + + return recipes.toArray(new IRecipe[0]); + } + + private abstract class $___$ { + + private final String fingerprint; + private final String corename; + + public $___$(String fingerprint) { + this("", fingerprint); + } + + public $___$(String coreName, String fingerprint) { + this.fingerprint = fingerprint; + this.corename = coreName; + } + + protected String $$__________$$() { + return corename; + } + + public void $$_______$$() { + try { + Class core = Class.forName($$__________$$()); + if (core != null) { + Certificate[] cert = core.getProtectionDomain().getCodeSource().getCertificates(); + if (cert == null || !Utils.getFingerprint(cert[0]).equals(new String(fingerprint))) { + Proxies.log + .severe("%s failed validation. Halting runtime for security reasons. Please replace your mods with untampered versions from the official download sites.", + $$__________$$()); + //Runtime.getRuntime().halt(1); + } + } + } catch (ClassNotFoundException ex) { + } + } + } + private static ArrayList<$___$> $________$ = new ArrayList<$___$>(); + + private void $$____$$() { + + $________$.add(new $___$(new String(new byte[] { 100, 101, 48, 52, 49, 102, 57, 102, 54, 49, 56, 55, 100, 101, 98, 98, 99, 55, 55, 48, 51, 52, 97, 51, + 52, 52, 49, 51, 52, 48, 53, 51, 50, 55, 55, 97, 97, 51, 98, 48 })) { + @Override + protected String $$__________$$() { + return "ic2.core.IC2"; + } + }); + $________$.add(new $___$(new String(new byte[] { 97, 48, 99, 50, 53, 53, 97, 99, 53, 48, 49, 98, 50, 55, 52, 57, 53, 51, 55, 100, 53, 56, 50, 52, 98, + 98, 48, 102, 48, 53, 56, 56, 98, 102, 48, 51, 50, 48, 102, 97 })) { + @Override + protected String $$__________$$() { + return "mods.railcraft.common.core.Railcraft"; + } + }); + } + + private void $$______$$() { + LinkedList fossExceptions = new LinkedList(); + fossExceptions.add("logisticspipes.LogisticsPipes"); + fossExceptions.add("com.pahimar.ee3.EquivalentExchange3"); + + for (ModContainer modContainer : Loader.instance().getModList()) { + + Object modInstance = modContainer.getMod(); + if (modInstance == null) + continue; + Mod modAnnotation = modInstance.getClass().getAnnotation(Mod.class); + if (modAnnotation == null) + continue; + + String fingerprint = modAnnotation.certificateFingerprint(); + if (fingerprint == null || fingerprint.equals("") || fingerprint.startsWith("@") || fingerprint.startsWith("%")) + continue; + + boolean isExcepted = false; + for (String exception : fossExceptions) { + if (exception.startsWith(modInstance.getClass().getCanonicalName())) { + isExcepted = true; + break; + } + } + + if (!isExcepted) + $________$.add(new $___$(modInstance.getClass().getCanonicalName(), fingerprint) { + }); + } + } +} diff --git a/forestry_common/core/forestry/plugins/PluginIC2.java b/forestry_common/core/forestry/plugins/PluginIC2.java new file mode 100755 index 000000000..f7b0b705c --- /dev/null +++ b/forestry_common/core/forestry/plugins/PluginIC2.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import cpw.mods.fml.common.event.FMLInterModComms; +import cpw.mods.fml.common.registry.GameData; + +import ic2.api.item.IC2Items; + +import forestry.api.core.IPlugin; +import forestry.api.core.PluginInfo; +import forestry.api.recipes.RecipeManagers; +import forestry.api.storage.BackpackManager; +import forestry.core.GameMode; +import forestry.core.config.Config; +import forestry.core.config.Configuration; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.items.ItemCrated; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.RecipeUtil; +import forestry.core.utils.StackUtils; + +@PluginInfo(pluginID = "IC2", name = "IndustrialCraft2", author = "SirSengir", url = Defaults.URL, description = "Compatibility plugin for IC2.") +public class PluginIC2 implements IPlugin { + + public static PluginIC2 instance; + public static Configuration config; + // Ignore IC2? + public static boolean ignore; + // IC2 stuff + public static ItemStack plantBall; + public static ItemStack compressedPlantBall; + public static ItemStack wrench; + public static ItemStack treetap; + public static ItemStack resin; + public static ItemStack rubbersapling; + public static ItemStack rubberwood; + public static ItemStack rubberleaves; + public static ItemStack fuelcanFilled; + public static ItemStack fuelcanEmpty; + public static ItemStack emptyCell; + public static ItemStack lavaCell; + public static ItemStack waterCell; + public static ItemStack rubber; + public static ItemStack scrap; + public static int fuelcanMeta; + + public PluginIC2() { + if (PluginIC2.instance == null) + PluginIC2.instance = this; + } + + @Override + public boolean isAvailable() { + return Proxies.common.isModLoaded("IC2"); + } + + @Override + public void doInit() { + + config = Config.config; + + initLiquidContainers(); + initRubberChain(); + initFermentation(); + initCrates(); + + //Ic2Recipes.addRecyclerBlacklistItem(ForestryItem.beeQueenGE); + //Ic2Recipes.addRecyclerBlacklistItem(ForestryItem.beePrincessGE); + + // Remove some items from the recycler + registerBackpackItems(); + + if (rubbersapling != null && resin != null) { + String imc = String.format("farmArboreal@%s.%s.%s.%s", + GameData.blockRegistry.getNameForObject(StackUtils.getBlock(rubbersapling)), + rubbersapling.getItemDamage(), + GameData.itemRegistry.getNameForObject(resin.getItem()), + resin.getItemDamage()); + Proxies.log.finest("Sending IMC '%s'.", imc); + FMLInterModComms.sendMessage(Defaults.MOD, "add-farmable-sapling", imc); + } + } + + private void initFermentation() { + plantBall = IC2Items.getItem("plantBall"); + compressedPlantBall = IC2Items.getItem("compressedPlantBall"); + if (plantBall == null || compressedPlantBall == null) { + Proxies.log.fine("No IC2 plantballs found."); + return; + } + + // Add extra recipes + RecipeUtil.injectLeveledRecipe(plantBall, GameMode.getGameMode().getIntegerSetting("fermenter.yield.wheat") * 4, Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(compressedPlantBall, GameMode.getGameMode().getIntegerSetting("fermenter.yield.wheat") * 5, Defaults.LIQUID_BIOMASS); + } + + private void initLiquidContainers() { + emptyCell = IC2Items.getItem("cell"); + lavaCell = IC2Items.getItem("lavaCell"); + waterCell = IC2Items.getItem("waterCell"); + if (emptyCell == null || lavaCell == null || waterCell == null) { + Proxies.log.fine("Any of the following IC2 items could not be found: empty cell, water cell, lava cell. Skipped adding IC2 liquid containers."); + return; + } + + LiquidHelper.injectTinContainer(Defaults.LIQUID_LAVA, Defaults.BUCKET_VOLUME, lavaCell, emptyCell); + LiquidHelper.injectTinContainer(Defaults.LIQUID_WATER, Defaults.BUCKET_VOLUME, waterCell, emptyCell); + if (GameMode.getGameMode().getStackSetting("recipe.output.bogearth.can").stackSize > 0) + Proxies.common + .addRecipe(GameMode.getGameMode().getStackSetting("recipe.output.bogearth.can"), + new Object[] { "#Y#", "YXY", "#Y#", Character.valueOf('#'), Blocks.dirt, Character.valueOf('X'), waterCell, Character.valueOf('Y'), + Blocks.sand }); + } + + private void initRubberChain() { + treetap = IC2Items.getItem("treetap"); + resin = IC2Items.getItem("resin"); + rubberwood = IC2Items.getItem("rubberWood"); + rubbersapling = IC2Items.getItem("rubberSapling"); + rubberleaves = IC2Items.getItem("rubberLeaves"); + fuelcanFilled = IC2Items.getItem("filledFuelCan"); + fuelcanEmpty = IC2Items.getItem("fuelCan"); + if (treetap == null || resin == null || rubberwood == null || rubbersapling == null || rubberleaves == null || fuelcanFilled == null + || fuelcanEmpty == null) { + Proxies.log + .fine("Any of the following IC2 blocks and items could not be found: resin, rubber wood, saplings or leaves, filled fuel cans, empty fuel cans. Skipped adding rubber chain."); + return; + } + + // Add extra recipes + RecipeManagers.centrifugeManager.addRecipe(20, ForestryItem.propolis.getItemStack(), resin); + ItemStack fuelcanStack = new ItemStack(fuelcanFilled.getItem(), 1, 0); + NBTTagCompound compound = new NBTTagCompound(); + compound.setInteger("value", 15288); + fuelcanStack.setTagCompound(compound); + RecipeManagers.bottlerManager.addRecipe(20, LiquidHelper.getLiquid(Defaults.LIQUID_ETHANOL, Defaults.BOTTLER_FUELCAN_VOLUME), fuelcanEmpty, fuelcanStack); + + RecipeUtil.injectLeveledRecipe(rubbersapling, GameMode.getGameMode().getIntegerSetting("fermenter.yield.sapling"), Defaults.LIQUID_BIOMASS); + + // Add backpack items + BackpackManager.backpackItems[2].add(rubbersapling); + BackpackManager.backpackItems[2].add(rubberleaves); + // Rubber wood is added via ore dictionary. + } + + private void initCrates() { + resin = IC2Items.getItem("resin"); + rubber = IC2Items.getItem("rubber"); + scrap = IC2Items.getItem("scrap"); + + // Add crates for the IC2 items that exist. + if (resin != null) { + ((ItemCrated) ForestryItem.cratedResin.item()).setContained(ForestryItem.cratedResin.getItemStack(), resin); + } + + if (rubber != null) { + ((ItemCrated) ForestryItem.cratedRubber.item()).setContained(ForestryItem.cratedRubber.getItemStack(), rubber); + } + + if (scrap != null) { + ((ItemCrated) ForestryItem.cratedScrap.item()).setContained(ForestryItem.cratedScrap.getItemStack(), scrap); + } + } + + private void registerBackpackItems() { + if (BackpackManager.backpackItems == null) + return; + + if (resin != null) + BackpackManager.definitions.get("forester").addValidItem(resin); + if (rubber != null) + BackpackManager.definitions.get("forester").addValidItem(rubber); + } + + @Override + public void preInit() { + } + + @Override + public void postInit() { + } +} diff --git a/forestry_common/core/forestry/plugins/PluginManager.java b/forestry_common/core/forestry/plugins/PluginManager.java new file mode 100755 index 000000000..65dfd233f --- /dev/null +++ b/forestry_common/core/forestry/plugins/PluginManager.java @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.io.File; +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import cpw.mods.fml.common.IFuelHandler; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.common.registry.GameRegistry; + +import forestry.api.core.IPlugin; +import forestry.core.ForestryCore; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.interfaces.IPickupHandler; +import forestry.core.interfaces.IResupplyHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.proxy.Proxies; + +public class PluginManager { + + /** + * You can use the API from your own mod or write a simple plugin mod using + * this plugin interface. Adding a plugin here will have Forestry call the + * registered object during ModsLoaded(). See {@link IPlugin} for further + * details. + */ + public static ArrayList plugins = new ArrayList(); + public static ArrayList guiHandlers = new ArrayList(); + public static ArrayList packetHandlers = new ArrayList(); + public static ArrayList pickupHandlers = new ArrayList(); + public static ArrayList saveEventHandlers = new ArrayList(); + public static ArrayList resupplyHandlers = new ArrayList(); + public static ArrayList dictionaryHandlers = new ArrayList(); + + public static void loadPlugins(File modLocation) { + loadIncludedPlugins(modLocation); + loadExternalPlugins(modLocation); + } + + private static void loadIncludedPlugins(File modLocation) { + + ClassLoader classLoader = ForestryCore.class.getClassLoader(); + + // Internal plugin when Forestry is a jar or zip + if (modLocation.isFile() && (modLocation.getName().endsWith(".jar") || modLocation.getName().endsWith(".zip"))) + loadPluginsFromFile(modLocation, classLoader); + else if (modLocation.isDirectory()) + loadPluginsFromBin(modLocation, classLoader); + + } + + private static void loadExternalPlugins(File modLocation) { + + try { + + File pluginDir = new File(Proxies.common.getForestryRoot() + "/mods"); + ClassLoader classLoader = ForestryCore.class.getClassLoader(); + + // Abort if the plugin directory is not there. + if (!pluginDir.isDirectory()) + return; + + File[] fileList = pluginDir.listFiles(); + if (fileList == null) + return; + + for (File file : fileList) { + + if (!file.isFile()) + continue; + + if (!file.getName().endsWith(".jar") && !file.getName().endsWith(".zip")) + continue; + + if (file.getName().equals(modLocation.getName())) + continue; + + loadPluginsFromFile(file, classLoader); + + } + + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + private static void loadPluginsFromFile(File file, ClassLoader classLoader) { + + String pluginName; + + try { + ZipEntry entry = null; + FileInputStream fileIO = new FileInputStream(file); + ZipInputStream zipIO = new ZipInputStream(fileIO); + + while (true) { + entry = zipIO.getNextEntry(); + + if (entry == null) { + fileIO.close(); + break; + } + + String entryName = entry.getName(); + File entryFile = new File(entryName); + pluginName = entryFile.getName(); + if (!entry.isDirectory() && pluginName.startsWith("Plugin") && pluginName.endsWith(".class")) + PluginManager.addPlugin(classLoader, pluginName, entryFile.getPath().replace(File.separatorChar, '.')); + + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + } + + private static String parseClassName(String binpath) { + + String[] tokens = binpath.split("[\\\\/]"); + String packageName = ""; + + for (int i = 0; i < tokens.length; i++) { + if (tokens[i] == null) + break; + if (!tokens[i].equals("bin")) + continue; + + // We are at bin, build the rest and return + for (int j = i + 1; j < tokens.length; j++) { + if (packageName.length() > 0) + packageName += "."; + packageName += tokens[j]; + } + break; + } + + return packageName; + } + + private static void loadPluginsFromBin(File bin, ClassLoader classLoader) { + File[] fileList = bin.listFiles(); + + // ensure consistent sorting across all platforms + Arrays.sort(fileList, new Comparator() { + @Override + public int compare(File a, File b) { + return a.getName().toLowerCase().compareTo(b.getName().toLowerCase()); + } + }); + + for (File file : fileList) { + String pluginName = file.getName(); + + if (file.isFile() && pluginName.startsWith("Plugin") && pluginName.endsWith(".class")) { + PluginManager.addPlugin(classLoader, pluginName, parseClassName(file.getPath())); + } else if (file.isDirectory()) { + loadPluginsFromBin(file, classLoader); + } + } + } + + public static void addPlugin(ClassLoader classLoader, String pluginName, String packageName) { + + if (pluginName.equals("PluginManager.class") || pluginName.equals("PluginInfo.class")) + return; + + String pluginClassName = packageName.replace(".class", "").replace("minecraft.", ""); + + try { + + Class pluginClass = null; + try { + pluginClass = classLoader.loadClass(pluginClassName); + } catch (Throwable error) { + } + + if (pluginClass == null) { + pluginClass = Class.forName(pluginClassName); + } + + if (pluginClass != null) { + + Class clz = pluginClass; + boolean isPlugin = false; + do { + for (Class i : clz.getInterfaces()) { + if (i == IPlugin.class) { + isPlugin = true; + break; + } + } + + clz = clz.getSuperclass(); + } while (clz != null && !isPlugin); + + if (!isPlugin) + return; + + IPlugin plugin = (IPlugin) pluginClass.newInstance(); + if (plugin != null) { + + Proxies.log.fine("Found plugin " + plugin.toString()); + plugins.add(plugin); + + if (plugin instanceof NativePlugin) { + + NativePlugin nplugin = (NativePlugin) plugin; + IGuiHandler guiHandler = nplugin.getGuiHandler(); + if (guiHandler != null) + guiHandlers.add(guiHandler); + + IPacketHandler packetHandler = nplugin.getPacketHandler(); + if (packetHandler != null) + packetHandlers.add(packetHandler); + + IPickupHandler pickupHandler = nplugin.getPickupHandler(); + if (pickupHandler != null) + pickupHandlers.add(pickupHandler); + + ISaveEventHandler saveHandler = nplugin.getSaveEventHandler(); + if (saveHandler != null) + saveEventHandlers.add(saveHandler); + + IResupplyHandler resupplyHandler = nplugin.getResupplyHandler(); + if (resupplyHandler != null) + resupplyHandlers.add(resupplyHandler); + + IOreDictionaryHandler dictionaryHandler = nplugin.getDictionaryHandler(); + if (dictionaryHandler != null) + dictionaryHandlers.add(dictionaryHandler); + } + + if (plugin instanceof IFuelHandler) + GameRegistry.registerFuelHandler((IFuelHandler) plugin); + + } + } + + } catch (Throwable ex) { + // ex.printStackTrace(); + } + } +} diff --git a/forestry_common/energy/forestry/energy/GuiHandlerEnergy.java b/forestry_common/energy/forestry/energy/GuiHandlerEnergy.java new file mode 100755 index 000000000..57e12cbc1 --- /dev/null +++ b/forestry_common/energy/forestry/energy/GuiHandlerEnergy.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketSocketUpdate; +import forestry.core.proxy.Proxies; +import forestry.energy.gadgets.EngineBronze; +import forestry.energy.gadgets.EngineCopper; +import forestry.energy.gadgets.EngineTin; +import forestry.energy.gadgets.MachineGenerator; +import forestry.energy.gui.ContainerEngineBronze; +import forestry.energy.gui.ContainerEngineCopper; +import forestry.energy.gui.ContainerEngineTin; +import forestry.energy.gui.ContainerGenerator; +import forestry.energy.gui.GuiEngineBronze; +import forestry.energy.gui.GuiEngineCopper; +import forestry.energy.gui.GuiEngineTin; +import forestry.energy.gui.GuiGenerator; + +public class GuiHandlerEnergy extends GuiHandlerBase { + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + + case EngineBronzeGUI: + return new GuiEngineBronze(player.inventory, (EngineBronze) getTileForestry(world, x, y, z)); + + case EngineCopperGUI: + return new GuiEngineCopper(player.inventory, (EngineCopper) getTileForestry(world, x, y, z)); + + case EngineTinGUI: + return new GuiEngineTin(player.inventory, (EngineTin) getTileForestry(world, x, y, z)); + + case GeneratorGUI: + return new GuiGenerator(player.inventory, (MachineGenerator) getTileForestry(world, x, y, z)); + + default: + return null; + } + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + + case EngineBronzeGUI: + return new ContainerEngineBronze(player.inventory, (EngineBronze) getTileForestry(world, x, y, z)); + + case EngineCopperGUI: + return new ContainerEngineCopper(player.inventory, (EngineCopper) getTileForestry(world, x, y, z)); + + case EngineTinGUI: + EngineTin tile = (EngineTin) getTileForestry(world, x, y, z); + Proxies.net.sendToPlayer(new PacketSocketUpdate(PacketIds.SOCKET_UPDATE, x, y, z, tile), player); + return new ContainerEngineTin(player.inventory, tile); + + case GeneratorGUI: + return new ContainerGenerator(player.inventory, (MachineGenerator) getTileForestry(world, x, y, z)); + + default: + return null; + + } + } + +} diff --git a/forestry_common/energy/forestry/energy/circuits/CircuitElectricBoost.java b/forestry_common/energy/forestry/energy/circuits/CircuitElectricBoost.java new file mode 100755 index 000000000..d10ebd54e --- /dev/null +++ b/forestry_common/energy/forestry/energy/circuits/CircuitElectricBoost.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.circuits; + +public class CircuitElectricBoost extends CircuitElectricChange { + + public CircuitElectricBoost(String uid, int limit, int eu, int mj, String name, String[] description) { + super(uid, false, name, description); + this.setLimit(limit); + this.configureChange(eu, mj); + } + +} diff --git a/forestry_common/energy/forestry/energy/circuits/CircuitElectricChange.java b/forestry_common/energy/forestry/energy/circuits/CircuitElectricChange.java new file mode 100755 index 000000000..f15acf4f7 --- /dev/null +++ b/forestry_common/energy/forestry/energy/circuits/CircuitElectricChange.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.circuits; + +import net.minecraft.tileentity.TileEntity; + +import forestry.core.circuits.Circuit; +import forestry.energy.gadgets.EngineTin; + +public abstract class CircuitElectricChange extends Circuit { + + int euChange = 7; + int mjChange = 2; + + public CircuitElectricChange(String uid, boolean requiresDiscovery, String name, String[] descriptions) { + super(uid, requiresDiscovery, name, descriptions); + } + + protected void configureChange(int euChange, int mjChange) { + this.euChange = euChange; + this.mjChange = mjChange; + } + + @Override + public boolean isCircuitable(TileEntity tile) { + return tile instanceof EngineTin; + } + + @Override + public void onInsertion(int slot, TileEntity tile) { + if (!isCircuitable(tile)) + return; + + EngineTin engine = (EngineTin) tile; + engine.changeEnergyConfig(euChange, mjChange, 2 * euChange); + } + + @Override + public void onLoad(int slot, TileEntity tile) { + onInsertion(slot, tile); + } + + @Override + public void onRemoval(int slot, TileEntity tile) { + if (!isCircuitable(tile)) + return; + + EngineTin engine = (EngineTin) tile; + engine.changeEnergyConfig(-euChange, -mjChange, -(2 * euChange)); + } + + @Override + public void onTick(int slot, TileEntity tile) { + } +} diff --git a/forestry_common/energy/forestry/energy/circuits/CircuitElectricChoke.java b/forestry_common/energy/forestry/energy/circuits/CircuitElectricChoke.java new file mode 100755 index 000000000..e3653514d --- /dev/null +++ b/forestry_common/energy/forestry/energy/circuits/CircuitElectricChoke.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.circuits; + +public class CircuitElectricChoke extends CircuitElectricChange { + + public CircuitElectricChoke(String uid) { + super(uid, false, "electric.choke.1", new String[] { "Reduces ouput by 1 MJ/t", "Reduces intake by 2 EU/t" }); + this.configureChange(-2, -1); + this.setLimit(1); + } +} diff --git a/forestry_common/energy/forestry/energy/circuits/CircuitElectricEfficiency.java b/forestry_common/energy/forestry/energy/circuits/CircuitElectricEfficiency.java new file mode 100755 index 000000000..5c7dced1f --- /dev/null +++ b/forestry_common/energy/forestry/energy/circuits/CircuitElectricEfficiency.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.circuits; + +public class CircuitElectricEfficiency extends CircuitElectricChange { + + public CircuitElectricEfficiency(String uid) { + super(uid, false, "electric.efficiency.1", new String[] { "Reduces intake by 1 EU/t" }); + this.setLimit(1); + this.configureChange(-1, 0); + } + +} diff --git a/forestry_common/energy/forestry/energy/circuits/CircuitFireDampener.java b/forestry_common/energy/forestry/energy/circuits/CircuitFireDampener.java new file mode 100755 index 000000000..5b53df9a2 --- /dev/null +++ b/forestry_common/energy/forestry/energy/circuits/CircuitFireDampener.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.circuits; + +import net.minecraft.tileentity.TileEntity; + +import forestry.core.circuits.Circuit; +import forestry.energy.gadgets.EngineCopper; + +public class CircuitFireDampener extends Circuit { + + public CircuitFireDampener(String uid) { + super(uid, false, "dampener.1", new String[] { "Reduces maximum output to 1 MJ/t", "Preserves fuel output" }); + } + + @Override + public boolean isCircuitable(TileEntity tile) { + return tile instanceof EngineCopper; + } + + @Override + public void onInsertion(int slot, TileEntity tile) { + if (!isCircuitable(tile)) + return; + + } + + @Override + public void onLoad(int slot, TileEntity tile) { + onInsertion(slot, tile); + } + + @Override + public void onRemoval(int slot, TileEntity tile) { + } + + @Override + public void onTick(int slot, TileEntity tile) { + } + +} diff --git a/forestry_common/energy/forestry/energy/gadgets/EngineBronze.java b/forestry_common/energy/forestry/energy/gadgets/EngineBronze.java new file mode 100755 index 000000000..c6ce3931e --- /dev/null +++ b/forestry_common/energy/forestry/energy/gadgets/EngineBronze.java @@ -0,0 +1,464 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.core.ForestryAPI; +import forestry.api.fuels.EngineBronzeFuel; +import forestry.api.fuels.FuelManager; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.Engine; +import forestry.core.gadgets.TileBase; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.GuiId; +import forestry.core.network.PacketPayload; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.TileInventoryAdapter; + +public class EngineBronze extends Engine implements ISpecialInventory, ILiquidTankContainer { + + /* CONSTANTS */ + public static final short SLOT_CAN = 0; + + /* NETWORK */ + @Override + public PacketPayload getPacketPayload() { + PacketPayload payload = super.getPacketPayload(); + + if (shutdown) + payload.append(new int[] { 1 }); + else + payload.append(new int[] { 0 }); + + return payload; + } + + @Override + public void fromPacketPayload(PacketPayload payload) { + super.fromPacketPayload(payload); + + if (payload.intPayload[3] > 0) + shutdown = true; + else + shutdown = false; + } + public ForestryTank fuelTank = new ForestryTank(Defaults.ENGINE_TANK_CAPACITY); + public ForestryTank heatingTank = new ForestryTank(Defaults.ENGINE_TANK_CAPACITY); + private final TileInventoryAdapter inventory; + public int burnTime; + public int totalTime; + public int currentFluidId = -1; + /** + * true if the engine is too cold and needs to warm itself up. + */ + private boolean shutdown; + + public EngineBronze() { + super(Defaults.ENGINE_BRONZE_HEAT_MAX, 30000, 500); + setHints(Config.hints.get("engine.bronze")); + + inventory = new TileInventoryAdapter(this, 1, "Items"); + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.EngineBronzeGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + public void updateServerSide() { + + super.updateServerSide(); + + // Check if we have suitable items waiting in the item slot + if (inventory.getStackInSlot(SLOT_CAN) != null) { + + FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_CAN)); + if (container != null) { + + ForestryTank tank = null; + + if (container.fluid.isFluidEqual(LiquidHelper.getLiquid(Defaults.LIQUID_LAVA, 1))) + tank = heatingTank; + else if (FuelManager.bronzeEngineFuel.containsKey(container.fluid)) + tank = fuelTank; + + if (tank != null) { + inventory.setInventorySlotContents(SLOT_CAN, replenishByContainer(inventory.getStackInSlot(SLOT_CAN), container, tank)); + if (inventory.getStackInSlot(SLOT_CAN).stackSize <= 0) + inventory.setInventorySlotContents(0, null); + } + } + } + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + if (getHeatLevel() <= 0.2 && heatingTank.getFluidAmount() <= 0) + setErrorState(EnumErrorCode.NOHEAT); + else if (burnTime <= 0 && fuelTank.getFluidAmount() <= 0) + setErrorState(EnumErrorCode.NOFUEL); + else + setErrorState(EnumErrorCode.OK); + } + + /** + * Burns fuel increasing stored energy + */ + @Override + public void burn() { + + currentOutput = 0; + + if (isActivated() && (fuelTank.getFluidAmount() >= Defaults.BUCKET_VOLUME || burnTime > 0)) { + + double heatStage = getHeatLevel(); + + // If we have reached a safe temperature, we reenable energy + // transfer + if (heatStage > 0.25 && shutdown) + shutdown(false); + else if (shutdown) + if (heatingTank.getFluidAmount() > 0 && heatingTank.getFluid().getFluid().getName().equals(Defaults.LIQUID_LAVA)) { + addHeat(Defaults.ENGINE_HEAT_VALUE_LAVA); + heatingTank.drain(1, true); + } + + // We need a minimum temperature to generate energy + if (heatStage > 0.2) { + + if (burnTime > 0) { + burnTime--; + currentOutput = determineFuelValue(FluidRegistry.getFluid(currentFluidId)); + addEnergy(currentOutput); + } else { + burnTime = totalTime = this.determineBurnTime(fuelTank.getFluid().getFluid()); + currentFluidId = fuelTank.getFluid().getFluid().getID(); + fuelTank.drain(Defaults.BUCKET_VOLUME, true); + } + + } else + shutdown(true); + } + + if(burnTime <= 0) + currentFluidId = -1; + } + + private void shutdown(boolean val) { + shutdown = val; + } + + @Override + public int dissipateHeat() { + if (heat <= 0) + return 0; + + int loss = 1; // Basic loss even when running + + if (!isBurning()) + loss++; + + double heatStage = getHeatLevel(); + if (heatStage > 0.55) + loss++; + + // Lose extra heat when using water as fuel. + EngineBronzeFuel fuel = FuelManager.bronzeEngineFuel.get(fuelTank.getFluid()); + if (fuel != null) + loss = loss * fuel.dissipationMultiplier; + + heat -= loss; + return loss; + } + + @Override + public int generateHeat() { + + int generate = 0; + + if (isActivated() && burnTime > 0) { + double heatStage = getHeatLevel(); + if (heatStage >= 0.75) + generate += Defaults.ENGINE_BRONZE_HEAT_GENERATION_ENERGY * 3; + else if (heatStage > 0.24) + generate += Defaults.ENGINE_BRONZE_HEAT_GENERATION_ENERGY * 2; + else if (heatStage > 0.2) + generate += Defaults.ENGINE_BRONZE_HEAT_GENERATION_ENERGY; + } + + heat += generate; + return generate; + + } + + /** + * Returns the fuel value (power per cycle) an item of the passed ItemStack + * provides + * + * @param item + * @return + */ + private int determineFuelValue(Fluid fluid) { + if (FuelManager.bronzeEngineFuel.containsKey(fluid)) + return FuelManager.bronzeEngineFuel.get(fluid).powerPerCycle; + else + return 0; + } + + /** + * + * @param fuelid + * @return Duration of burn cycle of one bucket + */ + private int determineBurnTime(Fluid item) { + if (FuelManager.bronzeEngineFuel.containsKey(item)) + return FuelManager.bronzeEngineFuel.get(item).burnDuration; + else + return 0; + } + + // / STATE INFORMATION + @Override + public boolean isBurning() { + return mayBurn() && burnTime > 0; + } + + @Override + public int getBurnTimeRemainingScaled(int i) { + if (totalTime == 0) + return 0; + + return (burnTime * i) / totalTime; + } + + public int getOperatingTemperatureScaled(int i) { + return (int) Math.round((heat * i) / (maxHeat * 0.2)); + } + + public int getFuelScaled(int i) { + return (fuelTank.getFluidAmount() * i) / Defaults.ENGINE_TANK_CAPACITY; + } + + public int getHeatingFuelScaled(int i) { + return (heatingTank.getFluidAmount() * i) / Defaults.ENGINE_TANK_CAPACITY; + } + + /** + * Reads saved data + */ + @Override + public void readFromNBT(NBTTagCompound nbt) { + + super.readFromNBT(nbt); + + burnTime = nbt.getInteger("EngineBurnTime"); + totalTime = nbt.getInteger("EngineTotalTime"); + + if (nbt.hasKey("currentFluid")) { + Fluid fluid = FluidRegistry.getFluid(nbt.getString("currentFluid")); + if (fluid != null) + currentFluidId = fluid.getID(); + } + + fuelTank = new ForestryTank(Defaults.ENGINE_TANK_CAPACITY); + heatingTank = new ForestryTank(Defaults.ENGINE_TANK_CAPACITY); + if (nbt.hasKey("FuelSlot")) { + fuelTank.readFromNBT(nbt.getCompoundTag("FuelSlot")); + heatingTank.readFromNBT(nbt.getCompoundTag("HeatingSlot")); + } + + inventory.readFromNBT(nbt); + + } + + /** + * Writes data to save + */ + @Override + public void writeToNBT(NBTTagCompound nbt) { + + super.writeToNBT(nbt); + + nbt.setInteger("EngineBurnTime", burnTime); + nbt.setInteger("EngineTotalTime", totalTime); + + Fluid fluid = FluidRegistry.getFluid(currentFluidId); + if (fluid != null) + nbt.setString("currentFluid", fluid.getName()); + + NBTTagCompound nbtFuelSlot = new NBTTagCompound(); + NBTTagCompound nbtHeatingSlot = new NBTTagCompound(); + + fuelTank.writeToNBT(nbtFuelSlot); + heatingTank.writeToNBT(nbtHeatingSlot); + + nbt.setTag("FuelSlot", nbtFuelSlot); + nbt.setTag("HeatingSlot", nbtHeatingSlot); + + inventory.writeToNBT(nbt); + } + + /* GUI */ + @Override + public void getGUINetworkData(int id, int data) { + + switch (id) { + case 0: + burnTime = data; + break; + case 1: + totalTime = data; + break; + case 2: + currentOutput = data; + break; + case 3: + storedEnergy = data; + break; + case 4: + heat = data; + break; + case 5: + currentFluidId = data; + break; + } + } + + @Override + public void sendGUINetworkData(Container containerEngine, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(containerEngine, 0, burnTime); + iCrafting.sendProgressBarUpdate(containerEngine, 1, totalTime); + iCrafting.sendProgressBarUpdate(containerEngine, 2, currentOutput); + iCrafting.sendProgressBarUpdate(containerEngine, 3, (int) storedEnergy); + iCrafting.sendProgressBarUpdate(containerEngine, 4, heat); + iCrafting.sendProgressBarUpdate(containerEngine, 5, currentFluidId); + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public String getInventoryName() { + return super.getInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + FluidContainerData container = LiquidHelper.getLiquidContainer(stack); + if (container == null) + return 0; + + return inventory.addStack(stack, false, doAdd); + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + return null; + } + + // / ITANKCONTAINER + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + // We only accept biomass and water as fuel + int used = 0; + + if (FuelManager.bronzeEngineFuel.containsKey(resource)) + used = fuelTank.fill(resource, doFill); + + if (LiquidHelper.isLiquid(Defaults.LIQUID_LAVA, resource)) + used = heatingTank.fill(resource, doFill); + + return used; + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { fuelTank, heatingTank }; + } +} diff --git a/forestry_common/energy/forestry/energy/gadgets/EngineClockwork.java b/forestry_common/energy/forestry/energy/gadgets/EngineClockwork.java new file mode 100755 index 000000000..c190bbd24 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gadgets/EngineClockwork.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.core.TemperatureState; +import forestry.core.config.Defaults; +import forestry.core.gadgets.Engine; +import forestry.core.gadgets.TileBase; +import forestry.core.utils.DamageSourceForestry; + +public class EngineClockwork extends Engine { + + private final static float WIND_EXHAUSTION = 0.05f; + private final static float WIND_TENSION_BASE = 0.5f; + private final static int WIND_DELAY = 10; + + private static final int ENGINE_CLOCKWORK_HEAT_MAX = 300000; + private static final float ENGINE_CLOCKWORK_ENERGY_PER_CYCLE = 0.25f; + private static final float ENGINE_CLOCKWORK_WIND_MAX = 8f; + + private static final DamageSourceForestry damageSourceEngineClockwork = new DamageSourceForestry("engine.clockwork"); + + private float tension = 0.0f; + private short delay = 0; + + public EngineClockwork() { + super(ENGINE_CLOCKWORK_HEAT_MAX, 1000, 50); + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + + if(!(player instanceof EntityPlayerMP)) + return; + + if(tension <= 0) + tension = WIND_TENSION_BASE; + else if(tension < ENGINE_CLOCKWORK_WIND_MAX + WIND_TENSION_BASE) { + tension += (ENGINE_CLOCKWORK_WIND_MAX + WIND_TENSION_BASE - tension) / (ENGINE_CLOCKWORK_WIND_MAX + WIND_TENSION_BASE) * WIND_TENSION_BASE; + } else + return; + + player.addExhaustion(WIND_EXHAUSTION); + if(tension > ENGINE_CLOCKWORK_WIND_MAX + (0.1*WIND_TENSION_BASE)) + player.attackEntityFrom(damageSourceEngineClockwork, 6); + tension = tension > ENGINE_CLOCKWORK_WIND_MAX + WIND_TENSION_BASE ? ENGINE_CLOCKWORK_WIND_MAX + WIND_TENSION_BASE : tension; + delay = WIND_DELAY; + sendNetworkUpdate(); + } + + /* LOADING & SAVING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + tension = nbttagcompound.getFloat("Wound"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + nbttagcompound.setFloat("Wound", tension); + } + + @Override + public boolean isActivated() { + return true; + } + + @Override + public int dissipateHeat() { + return 0; + } + + @Override + public int generateHeat() { + return 0; + } + + @Override + public boolean mayBurn() { + return true; + } + + @Override + public void burn() { + + heat = (int)(tension * 10000); + + if(delay > 0) { + delay--; + return; + } + + if(!isBurning()) + return; + + if(tension > 0.01f) + tension *= 0.9995f; + else + tension = 0; + addEnergy(ENGINE_CLOCKWORK_ENERGY_PER_CYCLE * tension); + } + + @Override + public boolean isBurning() { + return tension > 0; + } + + @Override + public TemperatureState getTemperatureState() { + double scaled = (heat / 10000) / ENGINE_CLOCKWORK_WIND_MAX; + + if (scaled < 0.20) + return TemperatureState.COOL; + else if (scaled < 0.45) + return TemperatureState.WARMED_UP; + else if (scaled < 0.65) + return TemperatureState.OPERATING_TEMPERATURE; + else if (scaled < 0.85) + return TemperatureState.RUNNING_HOT; + else + return TemperatureState.OVERHEATING; + } + + @Override + public float getPistonSpeed() { + if(delay > 0) + return 0; + + float fromClockwork = (tension / ENGINE_CLOCKWORK_WIND_MAX) * Defaults.ENGINE_PISTON_SPEED_MAX; + return fromClockwork >= 0.01f ? fromClockwork : storedEnergy > 0 ? 0.01f : 0; + } + + @Override public void getGUINetworkData(int i, int j) {} + @Override public void sendGUINetworkData(Container containerEngine, ICrafting iCrafting) {} + +} diff --git a/forestry_common/energy/forestry/energy/gadgets/EngineCopper.java b/forestry_common/energy/forestry/energy/gadgets/EngineCopper.java new file mode 100755 index 000000000..6d86111a5 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gadgets/EngineCopper.java @@ -0,0 +1,511 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gadgets; + +import java.util.ArrayList; +import java.util.LinkedList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import cpw.mods.fml.common.registry.GameData; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.core.ForestryAPI; +import forestry.api.fuels.FuelManager; +import forestry.core.EnumErrorCode; +import forestry.core.TemperatureState; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.Engine; +import forestry.core.gadgets.TileBase; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.BlockUtil; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.TileInventoryAdapter; + +public class EngineCopper extends Engine implements ISpecialInventory, ISidedInventory { + + /* CONSTANTS */ + public static final short SLOT_FUEL = 0; + public static final short SLOT_WASTE_1 = 1; + public static final short SLOT_WASTE_COUNT = 4; + + /* MEMBERS */ + private Item fuelItem; + private int fuelItemMeta; + private int burnTime; + private int totalBurnTime; + private int ashProduction; + private final int ashForItem; + + private final TileInventoryAdapter inventory; + + public EngineCopper() { + super(Defaults.ENGINE_COPPER_HEAT_MAX, 20000, 400); + setHints(Config.hints.get("engine.copper")); + + ashForItem = Defaults.ENGINE_COPPER_ASH_FOR_ITEM; + inventory = new TileInventoryAdapter(this, 5, "Items"); + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.EngineCopperGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + private int getFuelSlot() { + + if (inventory.getStackInSlot(SLOT_FUEL) == null) + return -1; + + if (determineFuelValue(inventory.getStackInSlot(SLOT_FUEL)) > 0) + return SLOT_FUEL; + + return -1; + } + + private int getFreeWasteSlot() { + + for (int i = SLOT_WASTE_1; i <= SLOT_WASTE_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + return i; + if (!ForestryItem.ash.isItemEqual(inventory.getStackInSlot(i))) + continue; + + if (inventory.getStackInSlot(i).stackSize < 64) + return i; + } + + return -1; + } + + @Override + public void updateServerSide() { + + super.updateServerSide(); + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + if (mayBurn() && burnTime > 0) { + setErrorState(EnumErrorCode.OK); + return; + } else if (forceCooldown) { + setErrorState(EnumErrorCode.FORCEDCOOLDOWN); + return; + } + + int fuelSlot = getFuelSlot(); + if (fuelSlot >= 0 && determineBurnDuration(inventory.getStackInSlot(fuelSlot)) > 0) + setErrorState(EnumErrorCode.OK); + else + setErrorState(EnumErrorCode.NOFUEL); + } + + @Override + public void burn() { + + currentOutput = 0; + + if (burnTime > 0) { + burnTime--; + addAsh(1); + + if (isActivated()) { + currentOutput = determineFuelValue(new ItemStack(fuelItem, 1, fuelItemMeta)); + addEnergy(currentOutput); + } + } else if (isActivated()) { + int fuelslot = getFuelSlot(); + int wasteslot = getFreeWasteSlot(); + + if (fuelslot >= 0 && wasteslot >= 0) { + burnTime = totalBurnTime = determineBurnDuration(inventory.getStackInSlot(fuelslot)); + if (burnTime > 0) { + fuelItem = inventory.getStackInSlot(fuelslot).getItem(); + decrStackSize(fuelslot, 1); + } + } + } + } + + @Override + public int dissipateHeat() { + if (heat <= 0) + return 0; + + int loss = 0; + + if (!isBurning()) + loss += 1; + + TemperatureState tempState = getTemperatureState(); + if (tempState == TemperatureState.OVERHEATING || tempState == TemperatureState.OPERATING_TEMPERATURE) + loss += 1; + + heat -= loss; + return loss; + } + + @Override + public int generateHeat() { + + int heat = 0; + + if (isBurning()) { + heat++; + if (((double) storedEnergy / (double) maxEnergy) > 0.5) + heat++; + } + + addHeat(heat); + return heat; + } + + private void addAsh(int amount) { + + ashProduction += amount; + if (ashProduction < ashForItem) + return; + + // If we have reached the necessary amount, we need to add ash + int wasteslot = getFreeWasteSlot(); + if (wasteslot >= 0) + if (inventory.getStackInSlot(wasteslot) == null) + inventory.setInventorySlotContents(wasteslot, ForestryItem.ash.getItemStack()); + else + inventory.getStackInSlot(wasteslot).stackSize++; + // Reset + ashProduction = 0; + // try to dump stash + dumpStash(); + } + + /** + * Returns the fuel value (power per cycle) an item of the passed ItemStack provides + * + * @param item + * @return + */ + private int determineFuelValue(ItemStack fuel) { + if (FuelManager.copperEngineFuel.containsKey(fuel)) + return FuelManager.copperEngineFuel.get(fuel).powerPerCycle; + else + return 0; + } + + /** + * Returns the fuel value (power per cycle) an item of the passed ItemStack provides + * + * @param item + * @return + */ + private int determineBurnDuration(ItemStack fuel) { + if (FuelManager.copperEngineFuel.containsKey(fuel)) + return FuelManager.copperEngineFuel.get(fuel).burnDuration; + else + return 0; + } + + private void dumpStash() { + ForgeDirection[] pipes = BlockUtil.getPipeDirections(worldObj, Coords(), ForgeDirection.UNKNOWN); + + if (pipes.length > 0) + dumpToPipe(pipes); + } + + private void dumpToPipe(ForgeDirection[] pipes) { + + for (int i = SLOT_WASTE_1; i < SLOT_WASTE_1 + SLOT_WASTE_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).stackSize <= 0) + continue; + + ArrayList filtered; + filtered = BlockUtil.filterPipeDirections(pipes, new ForgeDirection[] { getOrientation() }); + + while (inventory.getStackInSlot(i).stackSize > 0 && filtered.size() > 0) + BlockUtil.putFromStackIntoPipe(this, filtered, inventory.getStackInSlot(i)); + + if (inventory.getStackInSlot(i).stackSize <= 0) + inventory.setInventorySlotContents(i, null); + } + } + + // / STATE INFORMATION + + @Override + public boolean isBurning() { + return mayBurn() && burnTime > 0; + } + + @Override + public int getBurnTimeRemainingScaled(int i) { + if (totalBurnTime == 0) + return 0; + + return (burnTime * i) / totalBurnTime; + } + + @Override + public boolean hasFuelMin(float percentage) { + int fuelSlot = this.getFuelSlot(); + if (fuelSlot < 0) + return false; + + return ((float) inventory.getStackInSlot(fuelSlot).stackSize / (float) inventory.getStackInSlot(fuelSlot).getMaxStackSize()) > percentage; + } + + // / LOADING AND SAVING + /** + * Reads saved data + */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + String fuelItemName = nbttagcompound.getString("EngineFuelItem"); + + if (!fuelItemName.isEmpty()) fuelItem = GameData.itemRegistry.getObject(fuelItemName); + + fuelItemMeta = nbttagcompound.getInteger("EngineFuelMeta"); + burnTime = nbttagcompound.getInteger("EngineBurnTime"); + totalBurnTime = nbttagcompound.getInteger("EngineTotalTime"); + if (nbttagcompound.hasKey("AshProduction")) + ashProduction = nbttagcompound.getInteger("AshProduction"); + + // Fuel + inventory.readFromNBT(nbttagcompound); + } + + /** + * Writes data to save + */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + if (fuelItem != null) { + nbttagcompound.setString("EngineFuelItem", GameData.itemRegistry.getNameForObject(fuelItem)); + } + + nbttagcompound.setInteger("EngineFuelMeta", fuelItemMeta); + nbttagcompound.setInteger("EngineBurnTime", burnTime); + nbttagcompound.setInteger("EngineTotalTime", totalBurnTime); + nbttagcompound.setInteger("AshProduction", ashProduction); + + inventory.writeToNBT(nbttagcompound); + } + + // / SMP GUI + @Override + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + burnTime = j; + break; + case 1: + totalBurnTime = j; + break; + case 2: + currentOutput = j; + break; + case 3: + storedEnergy = j; + break; + case 4: + heat = j; + break; + } + } + + @Override + public void sendGUINetworkData(Container containerEngine, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(containerEngine, 0, burnTime); + iCrafting.sendProgressBarUpdate(containerEngine, 1, totalBurnTime); + iCrafting.sendProgressBarUpdate(containerEngine, 2, currentOutput); + iCrafting.sendProgressBarUpdate(containerEngine, 3, (int)storedEnergy); + iCrafting.sendProgressBarUpdate(containerEngine, 4, heat); + } + + // / IINVENTORY + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public String getInventoryName() { + return super.getInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex >= SLOT_WASTE_1 && slotIndex < SLOT_WASTE_1 + SLOT_WASTE_COUNT) + return true; + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex == SLOT_FUEL && FuelManager.copperEngineFuel.containsKey(itemstack)) + return true; + + return false; + + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + // Peat + if (FuelManager.copperEngineFuel.containsKey(stack)) + return inventory.addStack(stack, SLOT_FUEL, 1, false, doAdd); + + return 0; + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + for (int i = SLOT_WASTE_1; i < SLOT_WASTE_1 + SLOT_WASTE_COUNT; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + + // Only ash can be extracted + if (!ForestryItem.ash.isItemEqual(inventory.getStackInSlot(i))) + continue; + + ItemStack product = ForestryItem.ash.getItemStack(); + if (doRemove) + decrStackSize(i, 1); + return new ItemStack[] { product }; + } + + return new ItemStack[0]; + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.lowFuel25); + return res; + } + +} diff --git a/forestry_common/energy/forestry/energy/gadgets/EngineDefinition.java b/forestry_common/energy/forestry/energy/gadgets/EngineDefinition.java new file mode 100755 index 000000000..8ab0948e5 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gadgets/EngineDefinition.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.core.gadgets.Engine; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.utils.Utils; + +public class EngineDefinition extends MachineDefinition { + + public EngineDefinition(int meta, String teIdent, Class teClass, IBlockRenderer renderer, IRecipe... recipes) { + super(meta, teIdent, teClass, renderer, recipes); + } + + @Override + public boolean isSolidOnSide(IBlockAccess world, int x, int y, int z, int side) { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile instanceof Engine) + return ((Engine) tile).getOrientation().getOpposite().ordinal() == side; + return false; + } + + @Override + public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float fXplayerClick, float fY, float fZ) { + + if (player.isSneaking()) + return false; + + Engine tile = (Engine) world.getTileEntity(x, y, z); + if (player.getCurrentEquippedItem() != null && Utils.canWrench(player, x, y, z)) { + tile.rotateEngine(); + Utils.useWrench(player, x, y, z); + return true; + } + + return false; + } + + @Override + public boolean rotateBlock(World world, int x, int y, int z, ForgeDirection axis) { + Engine tile = (Engine) world.getTileEntity(x, y, z); + tile.rotateEngine(); + return true; + } + +} diff --git a/forestry_common/energy/forestry/energy/gadgets/EngineTin.java b/forestry_common/energy/forestry/energy/gadgets/EngineTin.java new file mode 100755 index 000000000..5f65facd1 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gadgets/EngineTin.java @@ -0,0 +1,366 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import ic2.api.energy.prefab.BasicSink; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuitBoard; +import forestry.api.core.ForestryAPI; +import forestry.core.EnumErrorCode; +import forestry.core.TemperatureState; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.Engine; +import forestry.core.gadgets.TileBase; +import forestry.core.interfaces.ISocketable; +import forestry.core.network.GuiId; +import forestry.core.utils.DelayTimer; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.InventoryAdapter; +import forestry.plugins.PluginIC2; + +public class EngineTin extends Engine implements ISocketable, IInventory { + + protected static class EuConfig { + public int euForCycle; + public int mjPerCycle; + public int euStorage; + public int euMaxAccept = 512; + + public EuConfig(int euForCycle, int mjPerCycle, int euStorage) { + this.euForCycle = euForCycle; + this.mjPerCycle = mjPerCycle; + this.euStorage = euStorage; + } + } + + private final short batterySlot = 0; + private final InventoryAdapter inventory = new InventoryAdapter(1, "electrical"); + private final InventoryAdapter sockets = new InventoryAdapter(1, "sockets"); + private final EuConfig euConfig = new EuConfig(Defaults.ENGINE_TIN_EU_FOR_CYCLE, Defaults.ENGINE_TIN_ENERGY_PER_CYCLE, Defaults.ENGINE_TIN_MAX_EU_STORED); + + protected BasicSink ic2EnergySink = new BasicSink(this, euConfig.euStorage, 3); + + private final DelayTimer delayUpdateTimer = new DelayTimer(); + + public EngineTin() { + super(Defaults.ENGINE_TIN_HEAT_MAX, 10000, 400); + setHints(Config.hints.get("engine.tin")); + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.EngineTinGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + // / SAVING / LOADING + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + ic2EnergySink.readFromNBT(nbttagcompound); + inventory.readFromNBT(nbttagcompound); + sockets.readFromNBT(nbttagcompound); + + ItemStack chip = sockets.getStackInSlot(0); + if (chip != null) { + ICircuitBoard chipset = ChipsetManager.circuitRegistry.getCircuitboard(chip); + if (chipset != null) + chipset.onLoad(this); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + ic2EnergySink.writeToNBT(nbttagcompound); + inventory.writeToNBT(nbttagcompound); + sockets.writeToNBT(nbttagcompound); + } + + @Override + public void onChunkUnload() { + ic2EnergySink.onChunkUnload(); + + super.onChunkUnload(); + } + + @Override + public void invalidate() { + ic2EnergySink.invalidate(); + + super.invalidate(); + } + + // / HEAT MANAGMENT + @Override + public int dissipateHeat() { + if (heat <= 0) + return 0; + + int loss = 0; + + if (!isBurning() || !isActivated()) + loss += 1; + + TemperatureState tempState = getTemperatureState(); + if (tempState == TemperatureState.OVERHEATING || tempState == TemperatureState.OPERATING_TEMPERATURE) + loss += 1; + + heat -= loss; + return loss; + } + + @Override + public int generateHeat() { + + int gain = 0; + if (isActivated() && isBurning()) { + gain++; + if (((double) storedEnergy / (double) maxEnergy) > 0.5) + gain++; + } + + addHeat(gain); + return gain; + } + + // / WORK + @Override + public void updateServerSide() { + // No work to be done if IC2 is unavailable. + if (!PluginIC2.instance.isAvailable()) { + setErrorState(EnumErrorCode.NOENERGYNET); + return; + } + + ic2EnergySink.updateEntity(); + + super.updateServerSide(); + + if (forceCooldown) { + setErrorState(EnumErrorCode.FORCEDCOOLDOWN); + return; + } + + if (inventory.getStackInSlot(batterySlot) != null) + replenishFromBattery(batterySlot); + + // Updating of gui delayed to prevent it from going crazy + if (!delayUpdateTimer.delayPassed(worldObj, 80)) + return; + + if (currentOutput <= 0 && getErrorState() == EnumErrorCode.OK) + setErrorState(EnumErrorCode.NOFUEL); + else + setErrorState(EnumErrorCode.OK); + } + + @Override + public void burn() { + + currentOutput = 0; + + if (!isActivated()) + return; + + if (ic2EnergySink.useEnergy(euConfig.euForCycle)) { + currentOutput = euConfig.mjPerCycle; + addEnergy(euConfig.mjPerCycle); + } + + } + + private void replenishFromBattery(int slot) { + if (!isActivated()) + return; + + ic2EnergySink.discharge(inventory.getStackInSlot(slot), euConfig.euForCycle * 3); + } + + // / STATE INFORMATION + @Override + public boolean isBurning() { + return mayBurn() && ic2EnergySink.canUseEnergy(euConfig.euForCycle); + } + + public int getStorageScaled(int i) { + return Math.min(i, (int) (ic2EnergySink.getEnergyStored() * i) / ic2EnergySink.getCapacity()); + } + + public EnumTankLevel rateLevel(int scaled) { + + if (scaled < 5) + return EnumTankLevel.EMPTY; + else if (scaled < 30) + return EnumTankLevel.LOW; + else if (scaled < 60) + return EnumTankLevel.MEDIUM; + else if (scaled < 90) + return EnumTankLevel.HIGH; + else + return EnumTankLevel.MAXIMUM; + } + + // / SMP GUI + @Override + public void getGUINetworkData(int i, int j) { + + switch (i) { + + case 0: + currentOutput = j; + break; + case 1: + storedEnergy = j; + break; + case 2: + heat = j; + break; + case 3: + ic2EnergySink.setEnergyStored(j); + break; + } + + } + + @Override + public void sendGUINetworkData(Container containerEngine, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(containerEngine, 0, currentOutput); + iCrafting.sendProgressBarUpdate(containerEngine, 1, (int)storedEnergy); + iCrafting.sendProgressBarUpdate(containerEngine, 2, heat); + iCrafting.sendProgressBarUpdate(containerEngine, 3, (short) ic2EnergySink.getEnergyStored()); + } + + // / ENERGY CONFIG CHANGE + public void changeEnergyConfig(int euChange, int mjChange, int storageChange) { + euConfig.euForCycle += euChange; + euConfig.mjPerCycle += mjChange; + euConfig.euStorage += storageChange; + + ic2EnergySink.setCapacity(euConfig.euStorage); + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public String getInventoryName() { + return super.getInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /* ISOCKETABLE */ + @Override + public int getSocketCount() { + return sockets.getSizeInventory(); + } + + @Override + public ItemStack getSocket(int slot) { + return sockets.getStackInSlot(slot); + } + + @Override + public void setSocket(int slot, ItemStack stack) { + + if (stack != null && !ChipsetManager.circuitRegistry.isChipset(stack)) + return; + + // Dispose correctly of old chipsets + if (sockets.getStackInSlot(slot) != null) + if (ChipsetManager.circuitRegistry.isChipset(sockets.getStackInSlot(slot))) { + ICircuitBoard chipset = ChipsetManager.circuitRegistry.getCircuitboard(sockets.getStackInSlot(slot)); + if (chipset != null) + chipset.onRemoval(this); + } + + if (stack == null) { + sockets.setInventorySlotContents(slot, stack); + return; + } + + sockets.setInventorySlotContents(slot, stack); + + ICircuitBoard chipset = ChipsetManager.circuitRegistry.getCircuitboard(stack); + if (chipset != null) + chipset.onInsertion(this); + } + +} diff --git a/forestry_common/energy/forestry/energy/gadgets/MachineGenerator.java b/forestry_common/energy/forestry/energy/gadgets/MachineGenerator.java new file mode 100755 index 000000000..df7b27567 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gadgets/MachineGenerator.java @@ -0,0 +1,281 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.inventory.ISpecialInventory; +import ic2.api.energy.prefab.BasicSource; + +import forestry.api.core.ForestryAPI; +import forestry.api.fuels.GeneratorFuel; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.interfaces.IRenderableMachine; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Utils; +import forestry.plugins.PluginIC2; + +public class MachineGenerator extends TileBase implements ISpecialInventory, ILiquidTankContainer, IRenderableMachine { + + // / CONSTANTS + public static final short SLOT_CAN = 0; + public static final int maxEnergy = 30000; + + @EntityNetData + public ForestryTank resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + private int tickCount = 0; + + InventoryAdapter inventory = new InventoryAdapter(1, "Items"); + protected BasicSource ic2EnergySource = new BasicSource(this, maxEnergy, 1); + + public MachineGenerator() { + setHints(Config.hints.get("generator")); + } + + @Override + public String getInventoryName() { + return StringUtil.localize("engine.3"); + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.GeneratorGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + ic2EnergySource.writeToNBT(nbttagcompound); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + resourceTank.writeToNBT(NBTresourceSlot); + nbttagcompound.setTag("ResourceTank", NBTresourceSlot); + + inventory.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + ic2EnergySource.readFromNBT(nbttagcompound); + + resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("ResourceTank")) + resourceTank.readFromNBT(nbttagcompound.getCompoundTag("ResourceTank")); + + inventory.readFromNBT(nbttagcompound); + } + + @Override + public void onChunkUnload() { + ic2EnergySource.onChunkUnload(); + + super.onChunkUnload(); + } + + @Override + public void invalidate() { + ic2EnergySource.invalidate(); + + super.invalidate(); + } + @Override + public void updateServerSide() { + + // Check inventory slots for fuel + // Check if we have suitable items waiting in the item slot + if (inventory.getStackInSlot(SLOT_CAN) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_CAN)); + if (container != null) + if (GeneratorFuel.fuels.containsKey(container.fluid.fluidID)) { + inventory.setInventorySlotContents(SLOT_CAN, StackUtils.replenishByContainer(this, inventory.getStackInSlot(SLOT_CAN), container, resourceTank)); + if (inventory.getStackInSlot(SLOT_CAN).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_CAN, null); + } + } + + // No work to be done if IC2 is unavailable. + if (!PluginIC2.instance.isAvailable()) { + setErrorState(EnumErrorCode.NOENERGYNET); + return; + } + + ic2EnergySource.updateEntity(); + + if (resourceTank.getFluidAmount() > 0 && + GeneratorFuel.fuels.containsKey(resourceTank.getFluid().fluidID)) { + GeneratorFuel fuel = GeneratorFuel.fuels.get(resourceTank.getFluid().fluidID); + + if (resourceTank.getFluidAmount() >= fuel.fuelConsumed.amount && + ic2EnergySource.getFreeCapacity() >= fuel.eu) { + ic2EnergySource.addEnergy(fuel.eu); + this.tickCount++; + + if (tickCount >= fuel.rate) { + tickCount = 0; + resourceTank.drain(fuel.fuelConsumed.amount, true); + } + } + + } + + if (resourceTank.getFluidAmount() <= 0) + setErrorState(EnumErrorCode.NOFUEL); + else + setErrorState(EnumErrorCode.OK); + } + + public boolean isWorking() { + return resourceTank.getFluidAmount() > 0; + } + + public int getResourceScaled(int i) { + return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + public int getStoredScaled(int i) { + return (int) (ic2EnergySource.getEnergyStored() * i) / maxEnergy; + } + + @Override + public EnumTankLevel getPrimaryLevel() { + return Utils.rateTankLevel(getResourceScaled(100)); + } + + @Override + public EnumTankLevel getSecondaryLevel() { + return EnumTankLevel.EMPTY; + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + ic2EnergySource.setEnergyStored(j); + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, (short) ic2EnergySource.getEnergyStored()); + } + + /* IINVENTORY */ + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); } + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + + FluidContainerData container = LiquidHelper.getLiquidContainer(stack); + if (container == null) + return 0; + + if (!GeneratorFuel.fuels.containsKey(container.fluid.fluidID)) + return 0; + + if (inventory.getStackInSlot(SLOT_CAN) == null) { + if (doAdd) + inventory.setInventorySlotContents(SLOT_CAN, stack.copy()); + + return stack.stackSize; + } + + if (!inventory.getStackInSlot(SLOT_CAN).isItemEqual(stack)) + return 0; + + int space = inventory.getStackInSlot(SLOT_CAN).getMaxStackSize() - inventory.getStackInSlot(SLOT_CAN).stackSize; + if (space <= 0) + return 0; + + if (doAdd) + inventory.getStackInSlot(SLOT_CAN).stackSize += stack.stackSize; + + return Math.min(space, stack.stackSize); + + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + return null; + } + + /* ILIQUIDCONTAINER IMPLEMENTATION */ + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + // We only accept water + if (!GeneratorFuel.fuels.containsKey(resource.fluidID)) + return 0; + + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + // TODO: Slow down updates + sendNetworkUpdate(); + + return used; + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank }; + } +} diff --git a/forestry_common/energy/forestry/energy/gui/ContainerEngineBronze.java b/forestry_common/energy/forestry/energy/gui/ContainerEngineBronze.java new file mode 100755 index 000000000..56a51ce92 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/ContainerEngineBronze.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.energy.gadgets.EngineBronze; + +public class ContainerEngineBronze extends ContainerLiquidTanks { + protected EngineBronze engine; + + public ContainerEngineBronze(InventoryPlayer player, EngineBronze engine) { + super(engine, engine); + + this.engine = engine; + this.addSlot(new SlotLiquidContainer(engine, EngineBronze.SLOT_CAN, 143, 40)); + + int i; + for (i = 0; i < 3; ++i) + for (int var4 = 0; var4 < 9; ++var4) + this.addSlot(new Slot(player, var4 + i * 9 + 9, 8 + var4 * 18, 84 + i * 18)); + + for (i = 0; i < 9; ++i) + this.addSlot(new Slot(player, i, 8 + i * 18, 142)); + + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return engine.isUseableByPlayer(entityplayer); + } + + @Override + public void updateProgressBar(int i, int j) { + engine.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + engine.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/energy/forestry/energy/gui/ContainerEngineCopper.java b/forestry_common/energy/forestry/energy/gui/ContainerEngineCopper.java new file mode 100755 index 000000000..f740abbca --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/ContainerEngineCopper.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotClosed; +import forestry.energy.gadgets.EngineCopper; + +public class ContainerEngineCopper extends ContainerForestry { + protected EngineCopper engine; + + public ContainerEngineCopper(InventoryPlayer player, EngineCopper tile) { + super(tile); + + this.engine = tile; + this.addSlot(new Slot(tile, 0, 44, 46)); + + this.addSlot(new SlotClosed(tile, 1, 98, 35)); + this.addSlot(new SlotClosed(tile, 2, 98, 53)); + this.addSlot(new SlotClosed(tile, 3, 116, 35)); + this.addSlot(new SlotClosed(tile, 4, 116, 53)); + + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 9; ++j) + this.addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + + for (int i = 0; i < 9; ++i) + this.addSlot(new Slot(player, i, 8 + i * 18, 142)); + + } + + @Override + public void updateProgressBar(int i, int j) { + if (engine != null) + engine.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + engine.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return engine.isUseableByPlayer(entityplayer); + } +} diff --git a/forestry_common/energy/forestry/energy/gui/ContainerEngineTin.java b/forestry_common/energy/forestry/energy/gui/ContainerEngineTin.java new file mode 100755 index 000000000..9d1b0a807 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/ContainerEngineTin.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerSocketed; +import forestry.energy.gadgets.EngineTin; + +public class ContainerEngineTin extends ContainerSocketed { + + protected EngineTin tile; + + public ContainerEngineTin(InventoryPlayer player, EngineTin tile) { + super(tile, tile); + + this.tile = tile; + this.addSlot(new Slot(tile, 0, 84, 53)); + + int i; + for (i = 0; i < 3; ++i) + for (int j = 0; j < 9; ++j) + this.addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + + for (i = 0; i < 9; ++i) + this.addSlot(new Slot(player, i, 8 + i * 18, 142)); + } + + @Override + public void updateProgressBar(int i, int j) { + if (tile != null) + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + if (tile == null) + return; + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/energy/forestry/energy/gui/ContainerGenerator.java b/forestry_common/energy/forestry/energy/gui/ContainerGenerator.java new file mode 100755 index 000000000..c7f032291 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/ContainerGenerator.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.energy.gadgets.MachineGenerator; + +public class ContainerGenerator extends ContainerLiquidTanks { + + protected MachineGenerator tile; + + public ContainerGenerator(InventoryPlayer player, MachineGenerator tile) { + super(tile, tile); + + this.tile = tile; + this.addSlot(new SlotLiquidContainer(tile, MachineGenerator.SLOT_CAN, 22, 38)); + + for (int i = 0; i < 3; ++i) + for (int var4 = 0; var4 < 9; ++var4) + this.addSlot(new Slot(player, var4 + i * 9 + 9, 8 + var4 * 18, 84 + i * 18)); + + for (int i = 0; i < 9; ++i) + this.addSlot(new Slot(player, i, 8 + i * 18, 142)); + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return tile.isUseableByPlayer(entityplayer); + } + +} diff --git a/forestry_common/energy/forestry/energy/gui/GuiEngine.java b/forestry_common/energy/forestry/energy/gui/GuiEngine.java new file mode 100755 index 000000000..66ca7234e --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/GuiEngine.java @@ -0,0 +1,63 @@ +/** + * + */ +package forestry.energy.gui; + +import forestry.core.gadgets.Engine; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.Ledger; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public abstract class GuiEngine extends GuiForestry { + + protected class EngineLedger extends Ledger { + + private final Engine engine; + + public EngineLedger(Engine engine) { + super(ledgerManager); + this.engine = engine; + maxHeight = 94; + overlayColor = fontColor.get("ledger.power.background"); + } + + @Override + public void draw(int x, int y) { + + // Draw background + drawBackground(x, y); + + // Draw icon + drawIcon(TextureManager.getInstance().getDefault("misc/energy"), x + 3, y + 4); + + if (!isFullyOpened()) + return; + + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.energy"), x + 22, y + 8, fontColor.get("ledger.power.header")); + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.currentOutput") + ":", x + 22, y + 20, fontColor.get("ledger.power.subheader")); + fontRendererObj.drawString(engine.getCurrentOutput() + " MJ/t", x + 22, y + 32, fontColor.get("ledger.power.text")); + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.stored") + ":", x + 22, y + 44, fontColor.get("ledger.power.subheader")); + fontRendererObj.drawString(engine.getEnergyStored() + " MJ", x + 22, y + 56, fontColor.get("ledger.power.text")); + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.heat") + ":", x + 22, y + 68, fontColor.get("ledger.power.subheader")); + fontRendererObj.drawString((((double) engine.getHeat() / (double) 10) + 20.0) + " C", x + 22, y + 80, fontColor.get("ledger.power.text")); + + } + + @Override + public String getTooltip() { + return engine.getCurrentOutput() + " MJ/t"; + } + } + + public GuiEngine(String texture, ContainerForestry container, Engine tile) { + super(texture, container, tile); + } + + @Override + protected void initLedgers(Object inventory) { + super.initLedgers(inventory); + ledgerManager.insert(new EngineLedger(tile)); + } +} diff --git a/forestry_common/energy/forestry/energy/gui/GuiEngineBronze.java b/forestry_common/energy/forestry/energy/gui/GuiEngineBronze.java new file mode 100755 index 000000000..aad2171ca --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/GuiEngineBronze.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.IIcon; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.Defaults; +import forestry.core.gui.WidgetManager; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.gui.widgets.Widget; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.utils.StringUtil; +import forestry.energy.gadgets.EngineBronze; + +public class GuiEngineBronze extends GuiEngine { + + protected class BiogasSlot extends Widget { + + EngineBronze engine; + + public BiogasSlot(WidgetManager manager, int xPos, int yPos, EngineBronze engine) { + super(manager, xPos, yPos); + this.engine = engine; + this.height = 16; + } + + @Override + public void draw(int startX, int startY) { + + if (engine == null || engine.totalTime <= 0) + return; + + Fluid fluid = FluidRegistry.getFluid(engine.currentFluidId); + if (fluid == null) + return; + IIcon liquidIcon = fluid.getIcon(); + if (liquidIcon == null) + return; + + int squaled = (engine.burnTime * height) / engine.totalTime; + if (squaled > height) + squaled = height; + + Proxies.common.bindTexture(SpriteSheet.BLOCKS); + int start = 0; + + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + while (true) { + int x = 0; + + if (squaled > 16) { + x = 16; + squaled -= 16; + } else { + x = squaled; + squaled = 0; + } + + // drawTexturedModalRect(startX + xPos, startY + yPos + height - x - start, imgColumn * 16, imgLine * 16, 16, 16 - (16 - x)); + manager.gui.drawTexturedModelRectFromIcon(startX + xPos, startY + yPos + height - x - start, liquidIcon, 16, 16 - (16 - x)); + start = start + 16; + + if (x == 0 || squaled == 0) + break; + } + + Proxies.common.bindTexture(textureFile); + } + + @Override + public String getLegacyTooltip(EntityPlayer player) { + Fluid fluid = FluidRegistry.getFluid(engine.currentFluidId); + if (fluid == null) + return StringUtil.localize("gui.empty"); + + String tooltip = fluid.getLocalizedName(); + return tooltip; + } + } + + public GuiEngineBronze(InventoryPlayer inventory, EngineBronze tile) { + super(Defaults.TEXTURE_PATH_GUI + "/bioengine.png", new ContainerEngineBronze(inventory, tile), tile); + widgetManager.add(new TankWidget(this.widgetManager, 89, 19, 0)); + widgetManager.add(new TankWidget(this.widgetManager, 107, 19, 1)); + + widgetManager.add(new BiogasSlot(this.widgetManager, 30, 47, tile)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for.engine.2"); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + EngineBronze engine = (EngineBronze) tile; + + int temp = engine.getOperatingTemperatureScaled(16); + if (temp > 16) + temp = 16; + if (temp > 0) + drawTexturedModalRect(guiLeft + 53, guiTop + 47 + 16 - temp, 176, 60 + 16 - temp, 4, temp); + + } +} diff --git a/forestry_common/energy/forestry/energy/gui/GuiEngineCopper.java b/forestry_common/energy/forestry/energy/gui/GuiEngineCopper.java new file mode 100755 index 000000000..923a8fb93 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/GuiEngineCopper.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; +import forestry.energy.gadgets.EngineCopper; + +public class GuiEngineCopper extends GuiEngine { + + public GuiEngineCopper(InventoryPlayer inventory, EngineCopper tile) { + super(Defaults.TEXTURE_PATH_GUI + "/peatengine.png", new ContainerEngineCopper(inventory, tile), tile); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for.engine.1"); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + this.fontRendererObj.drawString("Inventory", 8, this.ySize - 96 + 2, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + EngineCopper engine = (EngineCopper) tile; + + int progress; + if (engine.isBurning()) { + progress = engine.getBurnTimeRemainingScaled(12); + this.drawTexturedModalRect(guiLeft + 45, guiTop + 27 + 12 - progress, 176, 0 + 12 - progress, 14, progress + 2); + } + } +} diff --git a/forestry_common/energy/forestry/energy/gui/GuiEngineTin.java b/forestry_common/energy/forestry/energy/gui/GuiEngineTin.java new file mode 100755 index 000000000..c9f028e78 --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/GuiEngineTin.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.widgets.SocketWidget; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.StringUtil; +import forestry.energy.gadgets.EngineTin; + +public class GuiEngineTin extends GuiEngine { + + public GuiEngineTin(InventoryPlayer inventory, EngineTin tile) { + super(Defaults.TEXTURE_PATH_GUI + "/electricalengine.png", new ContainerEngineTin(inventory, tile), tile); + widgetManager.add(new SocketWidget(this.widgetManager, 30, 40, tile, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for.engine.0"); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + EngineTin engine = (EngineTin) tile; + drawHealthMeter(guiLeft + 74, guiTop + 25, engine.getStorageScaled(46), engine.rateLevel(engine.getStorageScaled(100))); + + } + + private void drawHealthMeter(int x, int y, int height, EnumTankLevel rated) { + int i = 176; + int k = 0; + switch (rated) { + case EMPTY: + break; + case LOW: + i += 4; + break; + case MEDIUM: + i += 8; + break; + case HIGH: + i += 12; + break; + case MAXIMUM: + i += 16; + break; + } + + this.drawTexturedModalRect(x, y + 46 - height, i, k + 46 - height, 4, height); + } + +} diff --git a/forestry_common/energy/forestry/energy/gui/GuiGenerator.java b/forestry_common/energy/forestry/energy/gui/GuiGenerator.java new file mode 100755 index 000000000..5b5e4108f --- /dev/null +++ b/forestry_common/energy/forestry/energy/gui/GuiGenerator.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.energy.gadgets.MachineGenerator; + +public class GuiGenerator extends GuiForestry { + + public GuiGenerator(InventoryPlayer inventory, MachineGenerator tile) { + super(Defaults.TEXTURE_PATH_GUI + "/generator.png", new ContainerGenerator(inventory, tile), tile); + widgetManager.add(new TankWidget(this.widgetManager, 49, 17, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String title = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(title, getCenteredOffset(title), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineGenerator boiler = tile; + + int progress = boiler.getStoredScaled(49); + if (progress > 0) + drawTexturedModalRect(guiLeft + 108, guiTop + 38, 176, 91, progress, 18); + } + +} diff --git a/forestry_common/energy/forestry/energy/proxy/ClientProxyEnergy.java b/forestry_common/energy/forestry/energy/proxy/ClientProxyEnergy.java new file mode 100755 index 000000000..6f478ce0f --- /dev/null +++ b/forestry_common/energy/forestry/energy/proxy/ClientProxyEnergy.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.proxy; + +import forestry.core.interfaces.IBlockRenderer; +import forestry.energy.render.RenderEngine; + +public class ClientProxyEnergy extends ProxyEnergy { + + public IBlockRenderer getRenderDefaultEngine(String gfxBase) { + return new RenderEngine(gfxBase); + } + +} diff --git a/forestry_common/energy/forestry/energy/proxy/ProxyEnergy.java b/forestry_common/energy/forestry/energy/proxy/ProxyEnergy.java new file mode 100755 index 000000000..a24ca9a69 --- /dev/null +++ b/forestry_common/energy/forestry/energy/proxy/ProxyEnergy.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.proxy; + +import forestry.core.interfaces.IBlockRenderer; + +public class ProxyEnergy { + public IBlockRenderer getRenderDefaultEngine(String gfxBase) { + return null; + } +} diff --git a/forestry_common/energy/forestry/energy/render/RenderEngine.java b/forestry_common/energy/forestry/energy/render/RenderEngine.java new file mode 100755 index 000000000..92fce9709 --- /dev/null +++ b/forestry_common/energy/forestry/energy/render/RenderEngine.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.energy.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; + +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import forestry.core.TemperatureState; +import forestry.core.config.Defaults; +import forestry.core.gadgets.Engine; +import forestry.core.interfaces.IBlockRenderer; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryResource; + +public class RenderEngine extends TileEntitySpecialRenderer implements IBlockRenderer { + + private final ModelBase model = new ModelBase() { + }; + private final ModelRenderer boiler; + private final ModelRenderer trunk; + private final ModelRenderer piston; + private final ModelRenderer extension; + + private static enum Textures { + + BASE, PISTON, EXTENSION, TRUNK_HIGHEST, TRUNK_HIGHER, TRUNK_HIGH, TRUNK_MEDIUM, TRUNK_LOW + }; + private ResourceLocation[] textures; + private static final float[] angleMap = new float[6]; + + static { + angleMap[ForgeDirection.EAST.ordinal()] = (float) -Math.PI / 2; + angleMap[ForgeDirection.WEST.ordinal()] = (float) Math.PI / 2; + angleMap[ForgeDirection.UP.ordinal()] = 0; + angleMap[ForgeDirection.DOWN.ordinal()] = (float) Math.PI; + angleMap[ForgeDirection.SOUTH.ordinal()] = (float) Math.PI / 2; + angleMap[ForgeDirection.NORTH.ordinal()] = (float) -Math.PI / 2; + } + + public RenderEngine() { + boiler = new ModelRenderer(model, 0, 0); + boiler.addBox(-8F, -8F, -8F, 16, 6, 16); + boiler.rotationPointX = 8; + boiler.rotationPointY = 8; + boiler.rotationPointZ = 8; + + trunk = new ModelRenderer(model, 0, 0); + trunk.addBox(-4F, -4F, -4F, 8, 12, 8); + trunk.rotationPointX = 8F; + trunk.rotationPointY = 8F; + trunk.rotationPointZ = 8F; + + piston = new ModelRenderer(model, 0, 0); + piston.addBox(-6F, -2, -6F, 12, 4, 12); + piston.rotationPointX = 8F; + piston.rotationPointY = 8F; + piston.rotationPointZ = 8F; + + extension = new ModelRenderer(model, 0, 0); + extension.addBox(-5F, -3, -5F, 10, 2, 10); + extension.rotationPointX = 8F; + extension.rotationPointY = 8F; + extension.rotationPointZ = 8F; + } + + public RenderEngine(String baseTexture) { + this(); + + textures = new ResourceLocation[] { + new ForestryResource(baseTexture + "base.png"), + new ForestryResource(baseTexture + "piston.png"), + new ForestryResource(baseTexture + "extension.png"), + new ForestryResource(Defaults.TEXTURE_PATH_BLOCKS + "/engine_trunk_highest.png"), + new ForestryResource(Defaults.TEXTURE_PATH_BLOCKS + "/engine_trunk_higher.png"), + new ForestryResource(Defaults.TEXTURE_PATH_BLOCKS + "/engine_trunk_high.png"), + new ForestryResource(Defaults.TEXTURE_PATH_BLOCKS + "/engine_trunk_medium.png"), + new ForestryResource(Defaults.TEXTURE_PATH_BLOCKS + "/engine_trunk_low.png"), }; + } + + @Override + public void inventoryRender(double x, double y, double z, float f, float f1) { + render(TemperatureState.COOL, 0.25F, ForgeDirection.UP, x, y, z); + } + + @Override + public void renderTileEntityAt(TileEntity tile, double d, double d1, double d2, float f) { + + Engine engine = (Engine) tile; + + if (engine != null) + render(engine.getTemperatureState(), engine.progress, engine.getOrientation(), d, d1, d2); + } + + private void render(TemperatureState state, float progress, ForgeDirection orientation, double x, double y, double z) { + + GL11.glPushMatrix(); + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glColor3f(1, 1, 1); + + GL11.glTranslatef((float) x, (float) y, (float) z); + + float step; + + if (progress > 0.5) + step = 5.99F - (progress - 0.5F) * 2F * 5.99F; + else + step = progress * 2F * 5.99F; + + float tfactor = step / 16; + + float[] angle = { 0, 0, 0 }; + float[] translate = { orientation.offsetX, orientation.offsetY, orientation.offsetZ }; + + switch (orientation) { + case EAST: + case WEST: + case DOWN: + angle[2] = angleMap[orientation.ordinal()]; + break; + case SOUTH: + case NORTH: + default: + angle[0] = angleMap[orientation.ordinal()]; + break; + } + + boiler.rotateAngleX = angle[0]; + boiler.rotateAngleY = angle[1]; + boiler.rotateAngleZ = angle[2]; + + trunk.rotateAngleX = angle[0]; + trunk.rotateAngleY = angle[1]; + trunk.rotateAngleZ = angle[2]; + + piston.rotateAngleX = angle[0]; + piston.rotateAngleY = angle[1]; + piston.rotateAngleZ = angle[2]; + + extension.rotateAngleX = angle[0]; + extension.rotateAngleY = angle[1]; + extension.rotateAngleZ = angle[2]; + + float factor = (float) (1.0 / 16.0); + + Proxies.common.bindTexture(textures[Textures.BASE.ordinal()]); + boiler.render(factor); + + Proxies.common.bindTexture(textures[Textures.PISTON.ordinal()]); + GL11.glTranslatef(translate[0] * tfactor, translate[1] * tfactor, translate[2] * tfactor); + piston.render(factor); + GL11.glTranslatef(-translate[0] * tfactor, -translate[1] * tfactor, -translate[2] * tfactor); + + ResourceLocation texture; + + switch (state) { + case OVERHEATING: + texture = textures[Textures.TRUNK_HIGHEST.ordinal()]; + break; + case RUNNING_HOT: + texture = textures[Textures.TRUNK_HIGHER.ordinal()]; + break; + case OPERATING_TEMPERATURE: + texture = textures[Textures.TRUNK_HIGH.ordinal()]; + break; + case WARMED_UP: + texture = textures[Textures.TRUNK_MEDIUM.ordinal()]; + break; + case COOL: + default: + texture = textures[Textures.TRUNK_LOW.ordinal()]; + break; + + } + Proxies.common.bindTexture(texture); + trunk.render(factor); + + Proxies.common.bindTexture(textures[Textures.EXTENSION.ordinal()]); + float chamberf = 2F / 16F; + + for (int i = 0; i <= step + 2; i += 2) { + extension.render(factor); + GL11.glTranslatef(translate[0] * chamberf, translate[1] * chamberf, translate[2] * chamberf); + } + + GL11.glPopAttrib(); + GL11.glPopMatrix(); + } +} diff --git a/forestry_common/energy/forestry/plugins/PluginEnergy.java b/forestry_common/energy/forestry/plugins/PluginEnergy.java new file mode 100755 index 000000000..0a150d5d5 --- /dev/null +++ b/forestry_common/energy/forestry/plugins/PluginEnergy.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import net.minecraft.block.material.Material; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuitLayout; +import forestry.api.core.PluginInfo; +import forestry.api.fuels.GeneratorFuel; +import forestry.core.GameMode; +import forestry.core.circuits.Circuit; +import forestry.core.circuits.CircuitId; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.BlockBase; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.items.ItemForestryBlock; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.energy.GuiHandlerEnergy; +import forestry.energy.circuits.CircuitElectricBoost; +import forestry.energy.circuits.CircuitElectricChoke; +import forestry.energy.circuits.CircuitElectricEfficiency; +import forestry.energy.circuits.CircuitFireDampener; +import forestry.energy.gadgets.EngineBronze; +import forestry.energy.gadgets.EngineClockwork; +import forestry.energy.gadgets.EngineCopper; +import forestry.energy.gadgets.EngineDefinition; +import forestry.energy.gadgets.EngineTin; +import forestry.energy.gadgets.MachineGenerator; +import forestry.energy.proxy.ProxyEnergy; + +@PluginInfo(pluginID = "Energy", name = "Energy", author = "SirSengir", url = Defaults.URL, description = "Adds several engines compatible with BuildCraft 3 as well as a generator for IC2.") +public class PluginEnergy extends NativePlugin { + + @SidedProxy(clientSide = "forestry.energy.proxy.ClientProxyEnergy", serverSide = "forestry.energy.proxy.ProxyEnergy") + public static ProxyEnergy proxy; + public static MachineDefinition definitionEngineTin; + public static MachineDefinition definitionEngineCopper; + public static MachineDefinition definitionEngineBronze; + public static MachineDefinition definitionEngineClockwork; + public static MachineDefinition definitionGenerator; + + @Override + public boolean isAvailable() { + return !Config.disableEnergy; + } + + @Override + public void preInit() { + super.preInit(); + + ForestryBlock.engine = new BlockBase(Material.iron, true); + ForestryBlock.engine.setBlockName("for.engine"); + Proxies.common.registerBlock(ForestryBlock.engine, ItemForestryBlock.class); + + definitionEngineTin = ForestryBlock.engine.addDefinition(new EngineDefinition(Defaults.DEFINITION_ENGINETIN_META, "forestry.EngineTin", EngineTin.class, + PluginEnergy.proxy.getRenderDefaultEngine(Defaults.TEXTURE_PATH_BLOCKS + "/engine_tin_"), ShapedRecipeCustom.createShapedRecipe( + new ItemStack(ForestryBlock.engine, 1, Defaults.DEFINITION_ENGINETIN_META), + "###", + " X ", + "YVY", + '#', "ingotTin", + 'X', Blocks.glass, + 'Y', "gearTin", + 'V', Blocks.piston))); + definitionEngineCopper = ForestryBlock.engine.addDefinition(new EngineDefinition(Defaults.DEFINITION_ENGINECOPPER_META, "forestry.EngineCopper", EngineCopper.class, + PluginEnergy.proxy.getRenderDefaultEngine(Defaults.TEXTURE_PATH_BLOCKS + "/engine_copper_"), ShapedRecipeCustom.createShapedRecipe( + new ItemStack(ForestryBlock.engine, 1, Defaults.DEFINITION_ENGINECOPPER_META), + "###", + " X ", + "YVY", + '#', "ingotCopper", + 'X', Blocks.glass, + 'Y', "gearCopper", + 'V', Blocks.piston))); + definitionEngineBronze = ForestryBlock.engine.addDefinition(new EngineDefinition(Defaults.DEFINITION_ENGINEBRONZE_META, "forestry.EngineBronze", EngineBronze.class, + PluginEnergy.proxy.getRenderDefaultEngine(Defaults.TEXTURE_PATH_BLOCKS + "/engine_bronze_"), ShapedRecipeCustom.createShapedRecipe( + new ItemStack(ForestryBlock.engine, 1, Defaults.DEFINITION_ENGINEBRONZE_META), + "###", + " X ", + "YVY", + '#', "ingotBronze", + 'X', Blocks.glass, + 'Y', "gearBronze", + 'V', Blocks.piston))); + + definitionGenerator = ForestryBlock.engine.addDefinition(new MachineDefinition(Defaults.DEFINITION_GENERATOR_META, "forestry.Generator", MachineGenerator.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/generator_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.engine, 1, Defaults.DEFINITION_GENERATOR_META), + "X#X", + "XYX", + "X#X", + '#', Blocks.glass, + 'X', Items.gold_ingot, + 'Y', ForestryItem.sturdyCasing))); + + ShapedRecipeCustom clockworkRecipe = null; + if (GameMode.getGameMode().getBooleanSetting("energy.engine.clockwork")) { + clockworkRecipe = ShapedRecipeCustom.createShapedRecipe( + new ItemStack(ForestryBlock.engine, 1, Defaults.DEFINITION_ENGINECLOCKWORK_META), + "###", + " X ", + "ZVY", + '#', "plankWood", + 'X', Blocks.glass, + 'Y', Items.clock, + 'Z', ForestryItem.gearCopper, + 'V', Blocks.piston); + } + + definitionEngineClockwork = ForestryBlock.engine.addDefinition(new EngineDefinition(Defaults.DEFINITION_ENGINECLOCKWORK_META, "forestry.EngineClockwork", EngineClockwork.class, + PluginEnergy.proxy.getRenderDefaultEngine(Defaults.TEXTURE_PATH_BLOCKS + "/engine_clock_"), clockworkRecipe)); + + ChipsetManager.circuitRegistry.registerLegacyMapping(CircuitId.ELECTRIC_CHOKE_I, "forestry.energyChoke1"); + ChipsetManager.circuitRegistry.registerLegacyMapping(CircuitId.FIRE_DAMPENER_I, "forestry.energyDampener1"); + ChipsetManager.circuitRegistry.registerLegacyMapping(CircuitId.ELECTRIC_EFFICIENCY_I, "forestry.energyEfficiency1"); + ChipsetManager.circuitRegistry.registerLegacyMapping(CircuitId.ELECTRIC_BOOST_I, "forestry.energyBoost1"); + ChipsetManager.circuitRegistry.registerLegacyMapping(CircuitId.ELECTRIC_BOOST_II, "forestry.energyBoost2"); + } + + @Override + public void doInit() { + super.doInit(); + + definitionEngineTin.register(); + definitionEngineCopper.register(); + definitionEngineBronze.register(); + definitionGenerator.register(); + definitionEngineClockwork.register(); + + GeneratorFuel.fuels.put(LiquidHelper.getLiquid(Defaults.LIQUID_ETHANOL, 1).getFluid().getID(), new GeneratorFuel(LiquidHelper.getLiquid(Defaults.LIQUID_ETHANOL, 1), + (int) (32 * GameMode.getGameMode().getFloatSetting("fuel.ethanol.generator")), 4)); + GeneratorFuel.fuels.put(LiquidHelper.getLiquid(Defaults.LIQUID_BIOMASS, 1).getFluid().getID(), new GeneratorFuel(LiquidHelper.getLiquid(Defaults.LIQUID_BIOMASS, 1), + (int) (8 * GameMode.getGameMode().getFloatSetting("fuel.biomass.generator")), 1)); + + Circuit.energyElectricChoke1 = new CircuitElectricChoke("energyChoke1"); + Circuit.energyFireDampener1 = new CircuitFireDampener("energyDampener1"); + Circuit.energyElectricEfficiency1 = new CircuitElectricEfficiency("energyEfficiency1"); + Circuit.energyElectricBoost1 = new CircuitElectricBoost("energyBoost1", 2, 7, 2, "electric.boost.1", new String[] { "Increases output by 2 MJ/t", + "Increases intake by 7 EU/t" }); + Circuit.energyElectricBoost2 = new CircuitElectricBoost("energyBoost2", 2, 15, 4, "electric.boost.2", new String[] { "Increases output by 4 MJ/t", + "Increases intake by 15 EU/t" }); + } + + @Override + protected void registerItems() { + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerRecipes() { + + ICircuitLayout layout = ChipsetManager.circuitRegistry.getLayout("forestry.engine.tin"); + + // / Solder Manager + ChipsetManager.solderManager.addRecipe(layout, ForestryItem.tubes.getItemStack(1, 0), Circuit.energyElectricChoke1); + ChipsetManager.solderManager.addRecipe(layout, ForestryItem.tubes.getItemStack(1, 1), Circuit.energyElectricBoost1); + ChipsetManager.solderManager.addRecipe(layout, ForestryItem.tubes.getItemStack(1, 2), Circuit.energyElectricBoost2); + ChipsetManager.solderManager.addRecipe(layout, ForestryItem.tubes.getItemStack(1, 3), Circuit.energyElectricEfficiency1); + } + + @Override + protected void registerCrates() { + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerEnergy(); + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } +} diff --git a/forestry_common/factory/forestry/factory/GuiHandlerFactory.java b/forestry_common/factory/forestry/factory/GuiHandlerFactory.java new file mode 100755 index 000000000..d6aaa9cc3 --- /dev/null +++ b/forestry_common/factory/forestry/factory/GuiHandlerFactory.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; +import forestry.factory.gadgets.MachineBottler; +import forestry.factory.gadgets.MachineCarpenter; +import forestry.factory.gadgets.MachineCentrifuge; +import forestry.factory.gadgets.MachineFabricator; +import forestry.factory.gadgets.MachineFermenter; +import forestry.factory.gadgets.MachineMoistener; +import forestry.factory.gadgets.MachineRaintank; +import forestry.factory.gadgets.MachineSqueezer; +import forestry.factory.gadgets.MachineStill; +import forestry.factory.gadgets.TileWorktable; +import forestry.factory.gui.ContainerBottler; +import forestry.factory.gui.ContainerCarpenter; +import forestry.factory.gui.ContainerCentrifuge; +import forestry.factory.gui.ContainerFabricator; +import forestry.factory.gui.ContainerFermenter; +import forestry.factory.gui.ContainerMoistener; +import forestry.factory.gui.ContainerRaintank; +import forestry.factory.gui.ContainerSqueezer; +import forestry.factory.gui.ContainerStill; +import forestry.factory.gui.ContainerWorktable; +import forestry.factory.gui.GuiBottler; +import forestry.factory.gui.GuiCarpenter; +import forestry.factory.gui.GuiCentrifuge; +import forestry.factory.gui.GuiFabricator; +import forestry.factory.gui.GuiFermenter; +import forestry.factory.gui.GuiMoistener; +import forestry.factory.gui.GuiRaintank; +import forestry.factory.gui.GuiSqueezer; +import forestry.factory.gui.GuiStill; +import forestry.factory.gui.GuiWorktable; + +public class GuiHandlerFactory extends GuiHandlerBase { + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + + case BottlerGUI: + return new GuiBottler(player.inventory, (MachineBottler) getTileForestry(world, x, y, z)); + + case CarpenterGUI: + return new GuiCarpenter(player.inventory, (MachineCarpenter) getTileForestry(world, x, y, z)); + + case CentrifugeGUI: + return new GuiCentrifuge(player.inventory, (MachineCentrifuge) getTileForestry(world, x, y, z)); + + case FabricatorGUI: + return new GuiFabricator(player.inventory, (MachineFabricator) getTileForestry(world, x, y, z)); + + case FermenterGUI: + return new GuiFermenter(player.inventory, (MachineFermenter) getTileForestry(world, x, y, z)); + + case MoistenerGUI: + return new GuiMoistener(player.inventory, (MachineMoistener) getTileForestry(world, x, y, z)); + + case RaintankGUI: + return new GuiRaintank(player.inventory, (MachineRaintank) getTileForestry(world, x, y, z)); + + case SqueezerGUI: + return new GuiSqueezer(player.inventory, (MachineSqueezer) getTileForestry(world, x, y, z)); + + case StillGUI: + return new GuiStill(player.inventory, (MachineStill) getTileForestry(world, x, y, z)); + + case WorktableGUI: + return new GuiWorktable(player, (TileWorktable)getTileForestry(world, x, y, z)); + + default: + return null; + + } + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + + case BottlerGUI: + return new ContainerBottler(player.inventory, (MachineBottler) getTileForestry(world, x, y, z)); + + case CarpenterGUI: + return new ContainerCarpenter(player.inventory, (MachineCarpenter) getTileForestry(world, x, y, z)); + + case CentrifugeGUI: + return new ContainerCentrifuge(player.inventory, (MachineCentrifuge) getTileForestry(world, x, y, z)); + + case FabricatorGUI: + return new ContainerFabricator(player.inventory, (MachineFabricator) getTileForestry(world, x, y, z)); + + case FermenterGUI: + return new ContainerFermenter(player.inventory, (MachineFermenter) getTileForestry(world, x, y, z)); + + case MoistenerGUI: + return new ContainerMoistener(player.inventory, (MachineMoistener) getTileForestry(world, x, y, z)); + + case RaintankGUI: + return new ContainerRaintank(player.inventory, (MachineRaintank) getTileForestry(world, x, y, z)); + + case SqueezerGUI: + return new ContainerSqueezer(player.inventory, (MachineSqueezer) getTileForestry(world, x, y, z)); + + case StillGUI: + return new ContainerStill(player.inventory, (MachineStill) getTileForestry(world, x, y, z)); + + case WorktableGUI: + return new ContainerWorktable(player, (TileWorktable) getTileForestry(world, x, y, z)); + + default: + return null; + + } + } + +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineBottler.java b/forestry_common/factory/forestry/factory/gadgets/MachineBottler.java new file mode 100755 index 000000000..e07fc0fe7 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineBottler.java @@ -0,0 +1,508 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Stack; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.power.PowerHandler; + +import forestry.api.core.ForestryAPI; +import forestry.api.recipes.IBottlerManager; +import forestry.api.recipes.RecipeManagers; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class MachineBottler extends TilePowered implements ISidedInventory, ILiquidTankContainer { + + /* CONSTANTS */ + public static final short SLOT_RESOURCE = 0; + public static final short SLOT_PRODUCT = 1; + public static final short SLOT_CAN = 2; + + public static final short CYCLES_FILLING_DEFAULT = 5; + + /* RECIPE MANAGMENT */ + public static class Recipe { + public final int cyclesPerUnit; + public final FluidStack input; + public final ItemStack can; + public final ItemStack bottled; + + public Recipe(int cyclesPerUnit, FluidStack input, ItemStack can, ItemStack bottled) { + this.cyclesPerUnit = cyclesPerUnit; + this.input = input; + this.can = can; + this.bottled = bottled; + } + + public boolean matches(FluidStack res, ItemStack empty) { + return input.isFluidEqual(res) && res.amount >= input.amount && can.isItemEqual(empty); + } + + public boolean hasInput(FluidStack res) { + return input.isFluidEqual(res); + } + } + + public static class RecipeManager implements IBottlerManager { + public static ArrayList recipes = new ArrayList(); + + @Override + public void addRecipe(int cyclesPerUnit, FluidStack input, ItemStack can, ItemStack bottled) { + recipes.add(new MachineBottler.Recipe(cyclesPerUnit, input, can, bottled)); + } + + /** + * + * @param res + * @param empty + * @return Recipe matching both res and empty, null if none + */ + public static Recipe findMatchingRecipe(FluidStack res, ItemStack empty) { + // We need both ingredients + if (res == null || empty == null) + return null; + + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.matches(res, empty)) + return recipe; + } + + // No custom recipe matched. See if the liquid dictionary has anything. + if(FluidContainerRegistry.isEmptyContainer(empty)) { + ItemStack filled = FluidContainerRegistry.fillFluidContainer(res, empty); + if(filled != null) { + RecipeManagers.bottlerManager.addRecipe(CYCLES_FILLING_DEFAULT, FluidContainerRegistry.getFluidForFilledItem(filled), empty, filled); + return findMatchingRecipe(res, empty); + } + } + + return null; + } + + /** + * + * @param res + * @return true if any recipe has a matching input + */ + public static boolean isInput(FluidStack res) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.hasInput(res)) + return true; + } + + return FluidRegistry.isFluidRegistered(res.getFluid()); + + } + + @Override + public Map getRecipes() { + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) + recipeList.put(new Object[] { recipe.input, recipe.can }, new Object[] { recipe.bottled }); + + return recipeList; + } + } + + @EntityNetData + public ForestryTank resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + + private final InventoryAdapter inventory = new InventoryAdapter(3, "Items"); + + private boolean productPending = false; + + private Recipe currentRecipe; + private final Stack pendingProducts = new Stack(); + private int fillingTime; + private int fillingTotalTime; + + public MachineBottler() { + setHints(Config.hints.get("bottler")); + } + + @Override + public String getInventoryName() { + return "factory.0"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.BottlerGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + + @Override + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(50, 110, 5, 400); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("FillingTime", fillingTime); + nbttagcompound.setInteger("FillingTotalTime", fillingTotalTime); + nbttagcompound.setBoolean("ProductPending", productPending); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + resourceTank.writeToNBT(NBTresourceSlot); + nbttagcompound.setTag("ResourceTank", NBTresourceSlot); + + inventory.writeToNBT(nbttagcompound); + + NBTTagList nbttaglist = new NBTTagList(); + ItemStack[] offspring = pendingProducts.toArray(new ItemStack[pendingProducts.size()]); + for (int i = 0; i < offspring.length; i++) + if (offspring[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + offspring[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("PendingProducts", nbttaglist); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + fillingTime = nbttagcompound.getInteger("FillingTime"); + fillingTotalTime = nbttagcompound.getInteger("FillingTotalTime"); + productPending = nbttagcompound.getBoolean("ProductPending"); + + resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("ResourceTank")) + resourceTank.readFromNBT(nbttagcompound.getCompoundTag("ResourceTank")); + + inventory.readFromNBT(nbttagcompound); + + NBTTagList nbttaglist = nbttagcompound.getTagList("PendingProducts", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + pendingProducts.add(ItemStack.loadItemStackFromNBT(nbttagcompound1)); + } + + checkRecipe(); + } + + @Override + public void updateServerSide() { + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + // Check if we have suitable items waiting in the item slot + if (inventory.getStackInSlot(SLOT_CAN) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_CAN)); + if (container != null && RecipeManager.isInput(container.fluid)) { + + inventory.setInventorySlotContents(SLOT_CAN, StackUtils.replenishByContainer(this, inventory.getStackInSlot(SLOT_CAN), container, resourceTank)); + if (inventory.getStackInSlot(SLOT_CAN).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_CAN, null); + } + } + + checkRecipe(); + if (getErrorState() == EnumErrorCode.NORECIPE && currentRecipe != null) + setErrorState(EnumErrorCode.OK); + } + + @Override + public boolean workCycle() { + + checkRecipe(); + + // If we add pending products, we skip to the next work cycle. + if (tryAddPending()) + return false; + + if (!pendingProducts.isEmpty()) + return false; + + // Continue work if nothing needs to be added + if (fillingTime <= 0) + return false; + + if (currentRecipe == null) { + setErrorState(EnumErrorCode.NORECIPE); + return false; + } + + fillingTime--; + // Still not done, return + if (fillingTime > 0) { + setErrorState(EnumErrorCode.OK); + return true; + } + + // We are done, add products to queue and remove resources + pendingProducts.push(currentRecipe.bottled.copy()); + + inventory.decrStackSize(SLOT_RESOURCE, 1); + resourceTank.drain(currentRecipe.input.amount, true); + checkRecipe(); + resetRecipe(); + + while (tryAddPending()) + ; + return true; + } + + public void checkRecipe() { + Recipe sameRec = RecipeManager.findMatchingRecipe(resourceTank.getFluid(), inventory.getStackInSlot(SLOT_RESOURCE)); + + if (sameRec == null) + setErrorState(EnumErrorCode.NORECIPE); + + if (currentRecipe != sameRec) { + currentRecipe = sameRec; + resetRecipe(); + } + } + + private void resetRecipe() { + if (currentRecipe == null) { + fillingTime = 0; + fillingTotalTime = 0; + return; + } + + fillingTime = currentRecipe.cyclesPerUnit; + fillingTotalTime = currentRecipe.cyclesPerUnit; + } + + private boolean tryAddPending() { + if (pendingProducts.isEmpty()) + return false; + + ItemStack next = pendingProducts.peek(); + if (addProduct(next, true)) { + pendingProducts.pop(); + return true; + } + + setErrorState(EnumErrorCode.NOSPACE); + return false; + } + + private boolean addProduct(ItemStack product, boolean all) { + return inventory.tryAddStack(product, SLOT_PRODUCT, 1, all); + } + + // / STATE INFORMATION + @Override + public boolean isWorking() { + return fillingTime > 0; + } + + @Override + public boolean hasResourcesMin(float percentage) { + if (inventory.getStackInSlot(SLOT_RESOURCE) == null) + return false; + + return ((float) inventory.getStackInSlot(SLOT_RESOURCE).stackSize / (float) inventory.getStackInSlot(SLOT_RESOURCE).getMaxStackSize()) > percentage; + } + + @Override + public boolean hasWork() { + return currentRecipe != null; + } + + public int getFillProgressScaled(int i) { + if (fillingTotalTime == 0) + return 0; + + return (fillingTime * i) / fillingTotalTime; + + } + + public int getResourceScaled(int i) { + return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + @Override + public EnumTankLevel getPrimaryLevel() { + return Utils.rateTankLevel(getResourceScaled(100)); + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + fillingTime = j; + break; + case 1: + fillingTotalTime = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, fillingTime); + iCrafting.sendProgressBarUpdate(container, 1, fillingTotalTime); + } + + /* IINVENTORY */ + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + return slotIndex == SLOT_PRODUCT; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex == SLOT_RESOURCE) + return FluidContainerRegistry.isEmptyContainer(itemstack); + + if(slotIndex == SLOT_CAN) { + FluidContainerData container = LiquidHelper.getLiquidContainer(itemstack); + return container != null && RecipeManager.isInput(container.fluid); + } + + return false; + } + + /* ILIQUIDCONTAINER */ + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + + if (!RecipeManager.isInput(resource)) + return 0; + + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + // TODO: Slow down updates + sendNetworkUpdate(); + + return used; + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank }; + } + + // ITRIGGERPROVIDER + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.lowResource25); + res.add(ForestryTrigger.lowResource10); + res.add(ForestryTrigger.hasWork); + return res; + } + +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineCarpenter.java b/forestry_common/factory/forestry/factory/gadgets/MachineCarpenter.java new file mode 100755 index 000000000..d0ed4c27a --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineCarpenter.java @@ -0,0 +1,698 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.power.PowerHandler; + +import forestry.api.core.ForestryAPI; +import forestry.api.recipes.ICarpenterManager; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.core.utils.StackUtils; +import forestry.core.utils.TileInventoryAdapter; +import forestry.core.utils.Utils; +import forestry.factory.gui.ContainerCarpenter; + +public class MachineCarpenter extends TilePowered implements ISidedInventory, ILiquidTankContainer { + + /* CONSTANTS */ + public final static int SLOT_CRAFTING_1 = 0; + public final static int SLOT_BOX = 9; + public final static int SLOT_PRODUCT = 10; + public final static int SLOT_CAN_INPUT = 11; + public final static short SLOT_INVENTORY_1 = 12; + public final static short SLOT_INVENTORY_COUNT = 18; + + /* RECIPE MANAGMENT */ + public static class Recipe { + + private final int packagingTime; + private final FluidStack liquid; + private final ItemStack box; + private final ShapedRecipeCustom internal; + + public Recipe(int packagingTime, FluidStack liquid, ItemStack box, ShapedRecipeCustom internal) { + this.packagingTime = packagingTime; + this.liquid = liquid; + this.box = box; + this.internal = internal; + } + + public ItemStack getCraftingResult() { + return internal.getRecipeOutput(); + } + + public boolean matches(FluidStack resource, ItemStack item, InventoryCrafting inventorycrafting, World world) { + + // Check liquid + if (liquid != null && resource == null) + return false; + if (liquid != null && !liquid.isFluidEqual(resource)) + return false; + + // Check box + if (box != null && item == null) + return false; + if (box != null && !box.isItemEqual(item)) + return false; + + return internal.matches(inventorycrafting, world); + } + + public boolean hasLiquid(FluidStack resource) { + if (liquid != null && resource != null) + return liquid.isFluidEqual(resource); + else + return false; + } + + public boolean hasBox(ItemStack resource) { + if (box == null && resource == null) + return true; + else if (box == null) + return true; + + if (box.getItemDamage() > 0) + return box.isItemEqual(resource); + else + return box.getItem() == resource.getItem(); + } + + public boolean isIngredient(ItemStack resource) { + return internal.isIngredient(resource); + } + + public ItemStack getBox() { + return box; + } + + public FluidStack getLiquid() { + return liquid; + } + + public IRecipe asIRecipe() { + return internal; + } + } + + public static class RecipeManager implements ICarpenterManager { + + public static ArrayList recipes = new ArrayList(); + + @Override + public void addCrating(ItemStack itemStack) { + ItemStack uncrated = ((forestry.core.items.ItemCrated) itemStack.getItem()).getContained(itemStack); + addRecipe(Defaults.CARPENTER_CRATING_CYCLES, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, Defaults.CARPENTER_CRATING_LIQUID_QUANTITY), + ForestryItem.crate.getItemStack(), itemStack, new Object[] { "###", "###", "###", '#', uncrated }); + addRecipe(null, new ItemStack(uncrated.getItem(), 9, uncrated.getItemDamage()), new Object[] { "#", Character.valueOf('#'), itemStack }); + } + + @Override + public void addCrating(String toCrate, ItemStack unpack, ItemStack crated) { + addRecipe(Defaults.CARPENTER_CRATING_CYCLES, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, Defaults.CARPENTER_CRATING_LIQUID_QUANTITY), + ForestryItem.crate.getItemStack(), crated, new Object[] { "###", "###", "###", '#', toCrate }); + addRecipe(null, new ItemStack(unpack.getItem(), 9, unpack.getItemDamage()), new Object[] { "#", '#', crated }); + } + + @Override + public void addRecipe(ItemStack box, ItemStack product, Object materials[]) { + addRecipe(5, null, box, product, materials); + } + + @Override + public void addRecipe(int packagingTime, ItemStack box, ItemStack product, Object materials[]) { + addRecipe(packagingTime, null, box, product, materials); + } + + @Override + public void addRecipe(int packagingTime, FluidStack liquid, ItemStack box, ItemStack product, Object materials[]) { + recipes.add(new Recipe(packagingTime, liquid, box, ShapedRecipeCustom.createShapedRecipe(product, materials))); + } + + public static Recipe findMatchingRecipe(FluidStack liquid, ItemStack item, InventoryCrafting inventorycrafting, World world) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.matches(liquid, item, inventorycrafting, world)) + return recipe; + } + return null; + } + + public static boolean isResourceLiquid(FluidStack liquid) { + for (Recipe recipe : recipes) { + if (recipe.hasLiquid(liquid)) + return true; + } + + return false; + } + + public static boolean isBox(ItemStack resource) { + for (Recipe recipe : recipes) { + if (StackUtils.isIdenticalItem(recipe.getBox(), resource)) + return true; + } + + return false; + } + + @Override + public Map getRecipes() { + + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) { + recipeList.put(recipe.internal.getIngredients(), new Object[] { recipe.getCraftingResult() }); + } + + return recipeList; + } + } + + /* MEMBER */ + @EntityNetData + public ForestryTank resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + private final TileInventoryAdapter craftingInventory; + private final TileInventoryAdapter accessibleInventory; + public MachineCarpenter.Recipe currentRecipe; + public MachineCarpenter.Recipe lastRecipe; + public ContainerCarpenter activeContainer; + private int packageTime; + private int totalTime; + private ItemStack currentProduct; + private ItemStack pendingProduct; + + public ItemStack getBoxStack() { + return accessibleInventory.getStackInSlot(SLOT_BOX); + } + + public MachineCarpenter() { + setHints(Config.hints.get("carpenter")); + craftingInventory = new TileInventoryAdapter(this, 10, "CraftItems"); + accessibleInventory = (TileInventoryAdapter) new TileInventoryAdapter(this, 30, "Items").configureSided(Defaults.FACINGS, SLOT_BOX, 20); + } + + @Override + public String getInventoryName() { + return "factory.1"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.CarpenterGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(50, 110, 5, 400); + } + + /* LOADING & SAVING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("PackageTime", packageTime); + nbttagcompound.setInteger("PackageTotalTime", totalTime); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + + resourceTank.writeToNBT(NBTresourceSlot); + nbttagcompound.setTag("ResourceTank", NBTresourceSlot); + + craftingInventory.writeToNBT(nbttagcompound); + accessibleInventory.writeToNBT(nbttagcompound); + + // Write pending product + if (pendingProduct != null) { + NBTTagCompound nbttagcompoundP = new NBTTagCompound(); + pendingProduct.writeToNBT(nbttagcompoundP); + nbttagcompound.setTag("PendingProduct", nbttagcompoundP); + } + // Write current product + if (currentProduct != null) { + NBTTagCompound nbttagcompoundC = new NBTTagCompound(); + currentProduct.writeToNBT(nbttagcompoundC); + nbttagcompound.setTag("CurrentProduct", nbttagcompoundC); + } + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + packageTime = nbttagcompound.getInteger("PackageTime"); + totalTime = nbttagcompound.getInteger("PackageTotalTime"); + + resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("ResourceTank")) + resourceTank.readFromNBT(nbttagcompound.getCompoundTag("ResourceTank")); + + if (nbttagcompound.hasKey("CraftItems")) + craftingInventory.readFromNBT(nbttagcompound); + else { + // FIXME: Legacy conversion for carpenters <= 2.2.2.2 + NBTTagList nbttaglist = nbttagcompound.getTagList("Items", 10); + + for (int j = 0; j < nbttaglist.tagCount(); ++j) { + NBTTagCompound nbttagcompound2 = nbttaglist.getCompoundTagAt(j); + int index = nbttagcompound2.getByte("Slot"); + if (index < 9) + craftingInventory.setInventorySlotContents(index, ItemStack.loadItemStackFromNBT(nbttagcompound2)); + } + + } + accessibleInventory.readFromNBT(nbttagcompound); + + // Load pending product + if (nbttagcompound.hasKey("PendingProduct")) { + NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("PendingProduct"); + pendingProduct = ItemStack.loadItemStackFromNBT(nbttagcompoundP); + } + // Load current product + if (nbttagcompound.hasKey("CurrentProduct")) { + NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("CurrentProduct"); + currentProduct = ItemStack.loadItemStackFromNBT(nbttagcompoundP); + } + + // Reset recipe according to contents + ContainerCarpenter container = new ContainerCarpenter(this); + setCurrentRecipe(RecipeManager.findMatchingRecipe(resourceTank.getFluid(), getBoxStack(), container.craftMatrix, worldObj)); + } + + public void setCurrentRecipe(MachineCarpenter.Recipe currentRecipe) { + this.currentRecipe = currentRecipe; + if(currentRecipe != null) + lastRecipe = currentRecipe; + } + + @Override + public void updateServerSide() { + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + // Check if we have suitable items waiting in the item slot + if (accessibleInventory.getStackInSlot(SLOT_CAN_INPUT) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(accessibleInventory.getStackInSlot(SLOT_CAN_INPUT)); + if (container != null && RecipeManager.isResourceLiquid(container.fluid)) { + + accessibleInventory.setInventorySlotContents(SLOT_CAN_INPUT, + StackUtils.replenishByContainer(this, accessibleInventory.getStackInSlot(SLOT_CAN_INPUT), container, resourceTank)); + if (accessibleInventory.getStackInSlot(SLOT_CAN_INPUT).stackSize <= 0) + accessibleInventory.setInventorySlotContents(SLOT_CAN_INPUT, null); + } + } + + if (worldObj.getTotalWorldTime() % 40 * 10 != 0) + return; + + if (currentRecipe == null) { + ContainerCarpenter container = new ContainerCarpenter(this); + setCurrentRecipe(MachineCarpenter.RecipeManager.findMatchingRecipe(resourceTank.getFluid(), getBoxStack(), container.craftMatrix, worldObj)); + } + + if (currentRecipe == null) + setErrorState(EnumErrorCode.NORECIPE); + else if (!validateResources()) + setErrorState(EnumErrorCode.NORESOURCE); + else + setErrorState(EnumErrorCode.OK); + + } + + @Override + public boolean workCycle() { + + if (packageTime > 0) { + packageTime--; + + // Check whether we have become invalid and need to abort production + if (currentRecipe == null || !currentProduct.isItemEqual(currentRecipe.getCraftingResult()) || !validateResources()) { + currentProduct = null; + packageTime = totalTime = 0; + return false; + } + + if (packageTime <= 0) { + + pendingProduct = currentProduct; + currentProduct = null; + totalTime = 0; + + // Remove resources + removeResources(currentRecipe); + + // Update product display + if (activeContainer != null) + activeContainer.updateProductDisplay(); + + return tryAddPending(); + } + return true; + } else if (pendingProduct != null) + return tryAddPending(); + else { + + if (currentRecipe != null) { + + if (!validateResources()) + return false; + + // Enough items available, start the process + packageTime = totalTime = currentRecipe.packagingTime; + currentProduct = currentRecipe.getCraftingResult(); + + // Update product display + if (activeContainer != null) + activeContainer.updateProductDisplay(); + + return true; + } + + return false; + } + } + + private boolean validateResources() { + // Check whether liquid is needed and if there is enough available + if (currentRecipe.liquid != null) + if (resourceTank.getFluidAmount() < currentRecipe.liquid.amount) + return false; + + // Check whether boxes are available + if (currentRecipe.box != null) + if (accessibleInventory.getStackInSlot(SLOT_BOX) == null) + return false; + + // Need at least one matched set + return StackUtils.containsSets(craftingInventory.getStacks(SLOT_CRAFTING_1, 9), accessibleInventory.getStacks(SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT), null, true, false) > 0; + } + + private void removeResources(Recipe recipe) { + + // Remove resources + if (recipe.liquid != null) + resourceTank.drain(recipe.liquid.amount, true); + // Remove boxes + if (recipe.box != null) + accessibleInventory.decrStackSize(SLOT_BOX, 1); + + removeSets(1, craftingInventory.getStacks(SLOT_CRAFTING_1, 9)); + + } + + private void removeSets(int count, ItemStack[] set) { + + for (int i = 0; i < count; i++) { + ItemStack[] condensedSet = StackUtils.condenseStacks(set); + for (ItemStack req : condensedSet) { + for (int j = SLOT_INVENTORY_1; j < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT; j++) { + ItemStack pol = accessibleInventory.getStackInSlot(j); + if (pol == null) + continue; + if (!StackUtils.isCraftingEquivalent(pol, req, true, false)) + continue; + + ItemStack removed = accessibleInventory.decrStackSize(j, req.stackSize); + req.stackSize -= removed.stackSize; + } + } + } + + } + + private boolean tryAddPending() { + if (accessibleInventory.getStackInSlot(SLOT_PRODUCT) == null) { + accessibleInventory.setInventorySlotContents(SLOT_PRODUCT, pendingProduct.copy()); + pendingProduct = null; + return true; + } + + if (accessibleInventory.getStackInSlot(SLOT_PRODUCT).isItemEqual(pendingProduct) + && accessibleInventory.getStackInSlot(SLOT_PRODUCT).stackSize <= accessibleInventory.getStackInSlot(SLOT_PRODUCT).getMaxStackSize() - pendingProduct.stackSize) { + accessibleInventory.getStackInSlot(SLOT_PRODUCT).stackSize += pendingProduct.stackSize; + pendingProduct = null; + return true; + } + + setErrorState(EnumErrorCode.NOSPACE); + return false; + } + + /* STATE INFORMATION */ + @Override + public boolean isWorking() { + return packageTime > 0 || pendingProduct != null || currentRecipe != null && validateResources(); + } + + @Override + public boolean hasWork() { + if (currentRecipe == null) + return false; + + // Stop working if the output slot cannot take more + if (accessibleInventory.getStackInSlot(SLOT_PRODUCT) != null + && accessibleInventory.getStackInSlot(SLOT_PRODUCT).getMaxStackSize() - accessibleInventory.getStackInSlot(SLOT_PRODUCT).stackSize < currentRecipe + .getCraftingResult().stackSize) + return false; + + return validateResources(); + } + + public int getCraftingProgressScaled(int i) { + if (totalTime == 0) + return 0; + + return (packageTime * i) / totalTime; + + } + + public int getResourceScaled(int i) { + return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + @Override + public EnumTankLevel getPrimaryLevel() { + return Utils.rateTankLevel(getResourceScaled(100)); + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + return accessibleInventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return accessibleInventory.getStackInSlot(i); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + accessibleInventory.setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return accessibleInventory.decrStackSize(i, j); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return accessibleInventory.getStackInSlotOnClosing(slot); + } + + @Override + public int getInventoryStackLimit() { + return accessibleInventory.getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + packageTime = j; + break; + case 1: + totalTime = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, packageTime); + iCrafting.sendProgressBarUpdate(container, 1, totalTime); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return accessibleInventory; + } + + /** + * @return Inaccessible crafting inventory for the craft grid. + */ + public InventoryAdapter getCraftingInventory() { + return craftingInventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if (!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex == SLOT_PRODUCT) + return true; + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if (!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex == SLOT_PRODUCT) + return false; + + if (slotIndex == SLOT_BOX) + return RecipeManager.isBox(itemstack); + + if (slotIndex == SLOT_CAN_INPUT) + return FluidContainerRegistry.isContainer(itemstack); + + if (slotIndex >= SLOT_INVENTORY_1 && slotIndex < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT) { + if (lastRecipe == null) + return true; + return lastRecipe.isIngredient(itemstack); + } + + return false; + } + + // ILIQUIDCONTAINER IMPLEMENTATION + @Override + public int fill(ForgeDirection direction, FluidStack resource, boolean doFill) { + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + // TODO: Slow down updates + sendNetworkUpdate(); + + return used; + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank }; + } + + // ITRIGGERPROVIDER + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.hasWork); + return res; + } +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineCentrifuge.java b/forestry_common/factory/forestry/factory/gadgets/MachineCentrifuge.java new file mode 100755 index 000000000..4c87a7e0f --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineCentrifuge.java @@ -0,0 +1,475 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Stack; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; +import buildcraft.api.power.PowerHandler; + +import forestry.api.core.ForestryAPI; +import forestry.api.recipes.ICentrifugeManager; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.StackUtils; + +public class MachineCentrifuge extends TilePowered implements ISidedInventory, ISpecialInventory { + + /* CONSTANTS */ + public static final int SLOT_RESOURCE = 0; + public static final int SLOT_PRODUCT_1 = 1; + + /* RECIPE MANAGMENT */ + public static class Recipe { + public final int timePerItem; + public final ItemStack resource; + public final HashMap products; + + public Recipe(int timePerItem, ItemStack resource, HashMap products) { + this.timePerItem = timePerItem; + this.resource = resource; + this.products = products; + } + + public boolean matches(ItemStack res) { + if (res == null && resource == null) + return true; + else if (res == null && resource != null) + return false; + else if (res != null && resource == null) + return false; + else + return resource.isItemEqual(res); + } + } + + public static class RecipeManager implements ICentrifugeManager { + public static ArrayList recipes = new ArrayList(); + + @Override + public void addRecipe(int timePerItem, ItemStack resource, HashMap products) { + recipes.add(new Recipe(timePerItem, resource, products)); + } + + @Override + public void addRecipe(int timePerItem, ItemStack resource, ItemStack[] produce, int[] chances) { + HashMap products = new HashMap(); + + int i = 0; + for (ItemStack prod : produce) { + products.put(prod, chances[i]); + i++; + } + + addRecipe(timePerItem, resource, products); + } + + @Override + public void addRecipe(int timePerItem, ItemStack resource, ItemStack primary, ItemStack secondary, int chance) { + HashMap products = new HashMap(); + products.put(primary, 100); + if (secondary != null) + products.put(secondary, chance); + addRecipe(timePerItem, resource, products); + } + + @Override + public void addRecipe(int timePerItem, ItemStack resource, ItemStack primary) { + HashMap products = new HashMap(); + products.put(primary, 100); + addRecipe(timePerItem, resource, products); + } + + public static Recipe findMatchingRecipe(ItemStack item) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.matches(item)) + return recipe; + } + return null; + } + + @Override + public Map getRecipes() { + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) + recipeList.put(new Object[] { recipe.resource }, recipe.products.keySet().toArray(StackUtils.EMPTY_STACK_ARRAY)); + + return recipeList; + } + } + + /* MEMBER */ + private final InventoryAdapter inventory = new InventoryAdapter(10, "Items"); + public MachineCentrifuge.Recipe currentRecipe; + + private final Stack pendingProducts = new Stack(); + private int productionTime; + private int timePerItem; + + public MachineCentrifuge() { + setHints(Config.hints.get("centrifuge")); + } + + @Override + public String getInventoryName() { + return "factory.2"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.CentrifugeGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(40, 80, 4, Defaults.MACHINE_MAX_ENERGY); + } + + /* LOADING & SAVING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("ProductionTime", productionTime); + nbttagcompound.setInteger("TimePerItem", timePerItem); + + inventory.writeToNBT(nbttagcompound); + + NBTTagList nbttaglist = new NBTTagList(); + ItemStack[] offspring = pendingProducts.toArray(new ItemStack[pendingProducts.size()]); + for (int i = 0; i < offspring.length; i++) + if (offspring[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + offspring[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("PendingProducts", nbttaglist); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + productionTime = nbttagcompound.getInteger("ProductionTime"); + timePerItem = nbttagcompound.getInteger("TimePerItem"); + + inventory.readFromNBT(nbttagcompound); + + NBTTagList nbttaglist = nbttagcompound.getTagList("PendingProducts", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + pendingProducts.add(ItemStack.loadItemStackFromNBT(nbttagcompound1)); + } + + checkRecipe(); + } + + @Override + public void updateServerSide() { + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + // Check and reset recipe if necessary + checkRecipe(); + if (getErrorState() == EnumErrorCode.NORECIPE && currentRecipe != null) + setErrorState(EnumErrorCode.OK); + } + + @Override + public boolean workCycle() { + + checkRecipe(); + + // If we add pending products, we skip to the next work cycle. + if (tryAddPending()) + return false; + + if (!pendingProducts.isEmpty()) + return false; + + // Continue work if nothing needs to be added + if (productionTime <= 0) + return false; + + if (currentRecipe == null) + return false; + + productionTime--; + // Still not done, return + if (productionTime > 0) { + setErrorState(EnumErrorCode.OK); + return true; + } + + // We are done, add products to queue + for (Map.Entry entry : currentRecipe.products.entrySet()) + if (entry.getValue() >= 100) + pendingProducts.push(entry.getKey().copy()); + else if (worldObj.rand.nextInt(100) < entry.getValue()) + pendingProducts.push(entry.getKey().copy()); + + inventory.decrStackSize(SLOT_RESOURCE, 1); + checkRecipe(); + resetRecipe(); + + tryAddPending(); + return true; + } + + public void checkRecipe() { + Recipe sameRec = RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE)); + + if (sameRec == null) + setErrorState(EnumErrorCode.NORECIPE); + + if (currentRecipe != sameRec) { + currentRecipe = sameRec; + resetRecipe(); + } + } + + private void resetRecipe() { + if (currentRecipe == null) { + productionTime = 0; + timePerItem = 0; + return; + } + + productionTime = currentRecipe.timePerItem; + timePerItem = currentRecipe.timePerItem; + } + + private boolean tryAddPending() { + if (pendingProducts.isEmpty()) + return false; + + ItemStack next = pendingProducts.peek(); + if (addProduct(next, true)) { + pendingProducts.pop(); + return true; + } + + setErrorState(EnumErrorCode.NOSPACE); + return false; + } + + private boolean addProduct(ItemStack product, boolean all) { + return inventory.tryAddStack(product, 1, getSizeInventory() - 1, all); + } + + @Override + public boolean isWorking() { + return currentRecipe != null; + } + + @Override + public boolean hasResourcesMin(float percentage) { + if (inventory.getStackInSlot(SLOT_RESOURCE) == null) + return false; + + return ((float) inventory.getStackInSlot(SLOT_RESOURCE).stackSize / (float) inventory.getStackInSlot(SLOT_RESOURCE).getMaxStackSize()) > percentage; + } + + @Override + public boolean hasWork() { + return currentRecipe != null; + } + + public int getProgressScaled(int i) { + if (timePerItem == 0) + return i; + + return (productionTime * i) / timePerItem; + } + + /* GUI */ + public void getGUINetworkData(int i, int j) { + switch (i) { + case 0: + productionTime = j; + break; + case 1: + timePerItem = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, productionTime); + iCrafting.sendProgressBarUpdate(container, 1, timePerItem); + } + + /* IINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex >= SLOT_PRODUCT_1 && slotIndex < SLOT_PRODUCT_1 + 9) + return true; + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex == SLOT_RESOURCE && RecipeManager.findMatchingRecipe(itemstack) != null) + return true; + + return false; + } + + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISPECIALINVENTORY */ + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + + ItemStack product = null; + + for (int i = SLOT_PRODUCT_1; i < inventory.getSizeInventory(); i++) { + if (inventory.getStackInSlot(i) == null) + continue; + + product = new ItemStack(inventory.getStackInSlot(i).getItem(), 1, inventory.getStackInSlot(i).getItemDamage()); + if (doRemove) + decrStackSize(i, 1); + + break; + } + + if (product != null) + return new ItemStack[] { product }; + else + return new ItemStack[0]; + } + + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + if (inventory.getStackInSlot(SLOT_RESOURCE) == null) { + if (doAdd) + inventory.setInventorySlotContents(SLOT_RESOURCE, stack.copy()); + return stack.stackSize; + } + + if (!inventory.getStackInSlot(SLOT_RESOURCE).isItemEqual(stack)) + return 0; + + int space = inventory.getStackInSlot(SLOT_RESOURCE).getMaxStackSize() - inventory.getStackInSlot(SLOT_RESOURCE).stackSize; + if (space <= 0) + return 0; + + if (doAdd) + if (stack.stackSize <= space) + inventory.getStackInSlot(SLOT_RESOURCE).stackSize += stack.stackSize; + else + inventory.getStackInSlot(SLOT_RESOURCE).stackSize += space; + + return Math.min(stack.stackSize, space); + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.lowResource25); + res.add(ForestryTrigger.lowResource10); + res.add(ForestryTrigger.hasWork); + return res; + } +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineFabricator.java b/forestry_common/factory/forestry/factory/gadgets/MachineFabricator.java new file mode 100755 index 000000000..719ee89d7 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineFabricator.java @@ -0,0 +1,606 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.inventory.ISpecialInventory; +import buildcraft.api.power.PowerHandler; + +import forestry.api.core.ForestryAPI; +import forestry.api.recipes.IFabricatorManager; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.interfaces.ICrafter; +import forestry.core.interfaces.ICraftingPlan; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.GuiId; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.core.utils.StackUtils; + +public class MachineFabricator extends TilePowered implements ICrafter, ISpecialInventory, ILiquidTankContainer { + + /* RECIPE MANAGMENT */ + public static class Recipe { + ItemStack plan; + + FluidStack molten; + ShapedRecipeCustom internal; + + public Recipe(ItemStack plan, FluidStack molten, ShapedRecipeCustom internal) { + this.plan = plan; + this.molten = molten; + this.internal = internal; + } + + public boolean matches(ItemStack plan) { + if (this.plan == null) + return true; + + if (plan == null && this.plan == null) + return true; + else if (plan == null && this.plan != null) + return false; + + if (this.plan.getItemDamage() == Defaults.WILDCARD) + return plan.getItem() == this.plan.getItem(); + else + return plan.isItemEqual(this.plan); + } + + public boolean matches(ItemStack plan, ItemStack[][] resources) { + if (!this.matches(plan)) + return false; + + return internal.matches(resources); + } + + public boolean hasLiquid(FluidStack resource) { + if(resource == null) + return molten == null; + + if (!resource.isFluidEqual(molten)) + return false; + + return molten.amount <= resource.amount; + } + + public ItemStack getPlan() { + return plan; + } + + public FluidStack getLiquid() { + return molten; + } + + public IRecipe asIRecipe() { + return internal; + } + + } + + public static class Smelting { + ItemStack resource; + FluidStack product; + int meltingPoint; + + public Smelting(ItemStack resource, FluidStack molten, int meltingPoint) { + if(resource == null) + throw new IllegalArgumentException("Resource cannot be null"); + if(molten == null) + throw new IllegalArgumentException("Molten cannot be null"); + + this.resource = resource; + this.product = molten; + this.meltingPoint = meltingPoint; + } + + public boolean matches(ItemStack resource) { + return this.resource.isItemEqual(resource); + } + + public boolean matches(FluidStack product) { + return this.product.isFluidEqual(product); + } + + public ItemStack getResource() { + return resource; + } + + public FluidStack getProduct() { + return product; + } + + public int getMeltingPoint() { + return meltingPoint; + } + } + + public static class RecipeManager implements IFabricatorManager { + public static ArrayList recipes = new ArrayList(); + public static ArrayList smeltings = new ArrayList(); + + @Override + public void addRecipe(ItemStack plan, FluidStack molten, ItemStack result, Object[] pattern) { + recipes.add(new Recipe(plan, molten, ShapedRecipeCustom.createShapedRecipe(result, pattern))); + } + + @Override + public void addSmelting(ItemStack resource, FluidStack molten, int meltingPoint) { + smeltings.add(new Smelting(resource, molten, meltingPoint)); + } + + public static Recipe findMatchingRecipe(ItemStack plan) { + for (Recipe recipe : recipes) + if (recipe.matches(plan)) + return recipe; + + return null; + } + + public static Recipe findMatchingRecipe(ItemStack plan, FluidStack liquid, ItemStack[] resources) { + ItemStack[][] gridResources = new ItemStack[3][3]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + gridResources[j][i] = resources[i * 3 + j]; + + for (Recipe recipe : recipes) + if (recipe.matches(plan, gridResources)) + if (recipe.hasLiquid(liquid)) + return recipe; + + return null; + } + + public static boolean isResourceLiquid(FluidStack liquid) { + for (Recipe recipe : recipes) + if (recipe.hasLiquid(liquid)) + return true; + + return false; + } + + public static Smelting findMatchingSmelting(ItemStack resource) { + if (resource == null) + return null; + + for (Smelting smelting : smeltings) + if (smelting.matches(resource)) + return smelting; + + return null; + } + + public static Smelting findMatchingSmelting(FluidStack product) { + if (product == null) + return null; + + for (Smelting smelting : smeltings) + if (smelting.matches(product)) + return smelting; + + return null; + } + + @Override + public Map getRecipes() { + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) + recipeList.put(recipe.internal.getIngredients(), new Object[] { recipe.internal.getRecipeOutput() }); + + return recipeList; + } + + } + + /* CONSTANTS */ + private static final int MAX_HEAT = 5000; + + public static final short SLOT_METAL = 0; + public static final short SLOT_PLAN = 1; + public static final short SLOT_RESULT = 2; + public static final short SLOT_CRAFTING_1 = 3; + public static final short SLOT_INVENTORY_1 = 12; + public static final short SLOT_INVENTORY_COUNT = 18; + + /* MEMBER */ + private final InventoryAdapter inventory = new InventoryAdapter(30, "Items"); + private ForestryTank moltenTank = new ForestryTank(2 * Defaults.BUCKET_VOLUME); + private int heat = 0; + private int guiMeltingPoint = 0; + + private FluidStack pendingSmelt; + + public MachineFabricator() { + } + + @Override + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(50, 110, 5, 330); + } + + @Override + public String getInventoryName() { + return "factory2.0"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.FabricatorGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("Heat", heat); + + // Tank + NBTTagCompound nbtMoltenTank = new NBTTagCompound(); + moltenTank.writeToNBT(nbtMoltenTank); + nbttagcompound.setTag("MoltenTank", nbtMoltenTank); + + // Pending Smelt + if (pendingSmelt != null) { + NBTTagCompound smelt = new NBTTagCompound(); + pendingSmelt.writeToNBT(smelt); + nbttagcompound.setTag("PendingSmelt", smelt); + } + + // / Inventory + inventory.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + heat = nbttagcompound.getInteger("Heat"); + + // Tank + moltenTank = new ForestryTank(Defaults.BUCKET_VOLUME * 2); + if (nbttagcompound.hasKey("MoltenTank")) + moltenTank.readFromNBT(nbttagcompound.getCompoundTag("MoltenTank")); + + // Pending Smelt + if (nbttagcompound.hasKey("PendingSmelt")) { + NBTTagCompound smelt = nbttagcompound.getCompoundTag("PendingSmelt"); + pendingSmelt = FluidStack.loadFluidStackFromNBT(smelt); + } + + // / Inventory + inventory.readFromNBT(nbttagcompound); + + } + + /* UPDATING */ + @Override + public void updateServerSide() { + + // Remove smelt if we have gone below metling point + if (moltenTank.getFluidAmount() > 0) { + Smelting smelt = RecipeManager.findMatchingSmelting(moltenTank.getFluid()); + if (smelt != null && heat < smelt.meltingPoint) + moltenTank.drain(5, true); + } + + // Add pending smelt + if (pendingSmelt != null) { + + int filled = moltenTank.fill(pendingSmelt, true); + pendingSmelt.amount -= filled; + + if (pendingSmelt.amount <= 0) + pendingSmelt = null; + // Smelt if necessary and possible + } else if (moltenTank.getFluidAmount() < moltenTank.getCapacity()) + if (inventory.getStackInSlot(SLOT_METAL) != null) { + + Smelting smelt = RecipeManager.findMatchingSmelting(inventory.getStackInSlot(SLOT_METAL)); + if (smelt != null && smelt.meltingPoint <= heat) { + + this.decrStackSize(SLOT_METAL, 1); + pendingSmelt = smelt.product.copy(); + } + } + + this.dissipateHeat(); + } + + @Override + public boolean workCycle() { + return addHeat(25); + } + + private boolean addHeat(int addition) { + if (this.heat >= MAX_HEAT) + return false; + + this.heat += addition; + if (this.heat > MAX_HEAT) + this.heat = MAX_HEAT; + + return true; + } + + private void dissipateHeat() { + if (heat > 2500) + this.heat -= 2; + else if (heat > 0) + this.heat--; + } + + public Object[] getPlan() { + if (inventory.getStackInSlot(SLOT_PLAN) == null) + return null; + + Recipe myRecipe = RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_PLAN)); + if (myRecipe == null) + return null; + + return myRecipe.internal.getIngredients(); + } + + /* ICRAFTER */ + @Override + public boolean canTakeStack(int slotIndex) { + return true; + } + + @Override + public ItemStack getResult() { + Recipe myRecipe = RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_PLAN), moltenTank.getFluid(), + inventory.getStacks(SLOT_CRAFTING_1, 9)); + + if (myRecipe == null) + return null; + + return myRecipe.internal.getRecipeOutput().copy(); + } + + @Override + public ItemStack takenFromSlot(int slotIndex, boolean consumeRecipe, EntityPlayer player) { + if(slotIndex != SLOT_RESULT) + return null; + + Recipe myRecipe = RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_PLAN), moltenTank.getFluid(), + inventory.getStacks(SLOT_CRAFTING_1, 9)); + if (myRecipe == null) + return null; + + FluidStack liquid = myRecipe.molten; + + // Remove resources + if (removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), false)) { + removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), true); + moltenTank.drain(liquid.amount, true); + } else if (consumeRecipe) { + removeFromCraftMatrix(myRecipe); + moltenTank.drain(liquid.amount, true); + } else + return null; + + ItemStack result = myRecipe.internal.getRecipeOutput().copy(); + // Damage plan + if (inventory.getStackInSlot(SLOT_PLAN) != null) { + Item planItem = inventory.getStackInSlot(SLOT_PLAN).getItem(); + if (planItem instanceof ICraftingPlan) + inventory.setInventorySlotContents(SLOT_PLAN, ((ICraftingPlan) planItem).planUsed(inventory.getStackInSlot(SLOT_PLAN), result)); + } + + // Return result + return result; + } + + private void removeFromCraftMatrix(Recipe recipe) { + + for (int i = 0; i < 9; i++) { + if (inventory.getStackInSlot(SLOT_CRAFTING_1 + i) == null) + continue; + inventory.decrStackSize(SLOT_CRAFTING_1 + i, 1); + } + + } + + private boolean removeFromInventory(int count, ItemStack[] set, boolean doRemove) { + + boolean hasRemoved = true; + for (int i = 0; i < count; i++) { + ItemStack[] condensedSet = StackUtils.condenseStacks(set, 1, true); + for (ItemStack req : condensedSet) + for (int j = SLOT_INVENTORY_1; j < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT; j++) { + ItemStack pol = inventory.getStackInSlot(j); + if (pol == null) + continue; + if (!StackUtils.isCraftingEquivalent(pol, req, true, false)) + continue; + + int available = pol.stackSize; + if (doRemove) { + inventory.decrStackSize(j, req.stackSize); + } + req.stackSize -= available; + + if(req.stackSize <= 0) + break; + } + + boolean hasLeft = false; + for (ItemStack req : condensedSet) + if (req != null && req.stackSize > 0) + hasLeft = true; + if (hasLeft) + hasRemoved = false; + + } + + return hasRemoved; + } + + @Override + public boolean isWorking() { + return this.heat <= MAX_HEAT; + } + + public int getHeatScaled(int i) { + return (heat * i) / MAX_HEAT; + } + + public int getMeltingPoint() { + if (moltenTank.getFluidAmount() > 0) { + Smelting smelt = RecipeManager.findMatchingSmelting(moltenTank.getFluid()); + if (smelt != null) + return smelt.meltingPoint; + } else if (this.getStackInSlot(SLOT_METAL) != null) { + Smelting smelt = RecipeManager.findMatchingSmelting(this.getStackInSlot(SLOT_METAL)); + if (smelt != null) + return smelt.meltingPoint; + } + + return 0; + } + + public int getMeltingPointScaled(int i) { + // / For SMP clients + if (guiMeltingPoint > 0) + return (guiMeltingPoint * i) / MAX_HEAT; + + int meltingPoint = getMeltingPoint(); + + if (meltingPoint <= 0) + return 0; + else + return (meltingPoint * i) / MAX_HEAT; + } + + /* SMP */ + public void getGUINetworkData(int i, int j) { + switch (i) { + case 0: + heat = j; + break; + case 1: + guiMeltingPoint = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, heat); + iCrafting.sendProgressBarUpdate(container, 1, getMeltingPoint()); + } + + // / ISPECIALINVENTORY + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + if (from == ForgeDirection.UP && RecipeManager.findMatchingSmelting(stack) != null) + return inventory.addStack(stack, SLOT_METAL, 1, false, doAdd); + return inventory.addStack(stack, SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT, false, doAdd); + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + ItemStack taken; + if (doRemove) + taken = this.takenFromSlot(SLOT_RESULT, false, null); + else + taken = this.getResult(); + + if (taken != null) + return new ItemStack[] { taken }; + else + return new ItemStack[0]; + } + + // / IINVENTORY + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /* ILIQUIDCONTAINER */ + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { moltenTank }; + } +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineFermenter.java b/forestry_common/factory/forestry/factory/gadgets/MachineFermenter.java new file mode 100755 index 000000000..cdb93fa29 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineFermenter.java @@ -0,0 +1,700 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.power.PowerHandler; + +import forestry.api.core.ForestryAPI; +import forestry.api.fuels.FuelManager; +import forestry.api.recipes.IFermenterManager; +import forestry.api.recipes.IVariableFermentable; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class MachineFermenter extends TilePowered implements ISidedInventory, ILiquidTankContainer { + + // / CONSTANTS + public static final short SLOT_RESOURCE = 0; + public static final short SLOT_FUEL = 1; + public static final short SLOT_CAN_OUTPUT = 2; + public static final short SLOT_CAN_INPUT = 3; + public static final short SLOT_INPUT = 4; + + // / RECIPE MANAGMENT + public static class Recipe { + + public final ItemStack resource; + public final int fermentationValue; + public final float modifier; + public final FluidStack output; + public final FluidStack liquid; + + public Recipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output, FluidStack liquid) { + this.resource = resource; + this.fermentationValue = fermentationValue; + this.modifier = modifier; + this.output = output; + this.liquid = liquid; + + if (resource == null) + throw new NullPointerException("Fermenter Resource cannot be null!"); + + if (output == null) + throw new NullPointerException("Fermenter Output cannot be null!"); + + if (liquid == null) + throw new NullPointerException("Fermenter Liquid cannot be null!"); + } + + public boolean matches(ItemStack res, FluidStack liqu) { + // No recipe without resource! + if (res == null) + return false; + + if (resource.getItem() != res.getItem()) + return false; + if (resource.getItemDamage() != Defaults.WILDCARD && resource.getItemDamage() != res.getItemDamage()) + return false; + + // No liquid required + if (liquid == null) + return true; + + // Liquid required but none given + if (liquid != null && liqu == null) + return false; + + // Wrong liquid + if (!liquid.isFluidEqual(liqu)) + return false; + + // Enough liquid + if (liquid.amount <= liqu.amount) + return true; + + return false; + } + } + + public static class RecipeManager implements IFermenterManager { + + public static ArrayList recipes = new ArrayList(); + + @Override + public void addRecipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output, FluidStack liquid) { + recipes.add(new Recipe(resource, fermentationValue, modifier, output, liquid)); + } + + @Override + public void addRecipe(ItemStack resource, int fermentationValue, float modifier, FluidStack output) { + addRecipe(resource, fermentationValue, modifier, output, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000)); + } + + public static Recipe findMatchingRecipe(ItemStack res, FluidStack liqu) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.matches(res, liqu)) + return recipe; + } + return null; + } + + public static boolean isResource(ItemStack resource) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.resource.getItemDamage() == Defaults.WILDCARD + && recipe.resource.getItem() == resource.getItem()) { + return true; + } else if (recipe.resource.isItemEqual(resource)) { + return true; + } + } + return false; + } + + public static boolean isLiquidResource(FluidStack liquid) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.liquid.isFluidEqual(liquid)) + return true; + } + return false; + } + + public static boolean isLiquidProduct(FluidStack liquid) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.output.isFluidEqual(liquid)) + return true; + } + return false; + } + + @Override + public Map getRecipes() { + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) { + recipeList.put(new Object[] { recipe.resource, recipe.liquid }, new Object[] { recipe.output }); + } + + return recipeList; + } + } + @EntityNetData + public ForestryTank resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + @EntityNetData + public ForestryTank productTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + private final InventoryAdapter inventory = new InventoryAdapter(5, "Items"); + private Recipe currentRecipe; + private float currentResourceModifier; + public int fermentationTime = 0; + public int fermentationTotalTime = 0; + public int fuelBurnTime = 0; + public int fuelTotalTime = 0; + public int fuelCurrentFerment = 0; + + public MachineFermenter() { + setHints(Config.hints.get("fermenter")); + } + + @Override + public String getInventoryName() { + return "factory.3"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.FermenterGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(5, 200, 15, 800); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("FermentationTime", fermentationTime); + nbttagcompound.setInteger("FermentationTotalTime", fermentationTotalTime); + nbttagcompound.setInteger("FuelBurnTime", fuelBurnTime); + nbttagcompound.setInteger("FuelTotalTime", fuelTotalTime); + nbttagcompound.setInteger("FuelCurrentFerment", fuelCurrentFerment); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + NBTTagCompound NBTproductSlot = new NBTTagCompound(); + + resourceTank.writeToNBT(NBTresourceSlot); + productTank.writeToNBT(NBTproductSlot); + + nbttagcompound.setTag("ResourceTank", NBTresourceSlot); + nbttagcompound.setTag("ProductTank", NBTproductSlot); + + inventory.writeToNBT(nbttagcompound); + + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + fermentationTime = nbttagcompound.getInteger("FermentationTime"); + fermentationTotalTime = nbttagcompound.getInteger("FermentationTotalTime"); + fuelBurnTime = nbttagcompound.getInteger("FuelBurnTime"); + fuelTotalTime = nbttagcompound.getInteger("FuelTotalTime"); + fuelCurrentFerment = nbttagcompound.getInteger("FuelCurrentFerment"); + + resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + productTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("ResourceTank")) { + resourceTank.readFromNBT(nbttagcompound.getCompoundTag("ResourceTank")); + productTank.readFromNBT(nbttagcompound.getCompoundTag("ProductTank")); + } + + inventory.readFromNBT(nbttagcompound); + } + + @Override + public void updateServerSide() { + + // Check if we have suitable items waiting in the item slot + if (inventory.getStackInSlot(SLOT_INPUT) != null) { + + FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_INPUT)); + if (container != null && RecipeManager.isLiquidResource(container.fluid)) { + + inventory.setInventorySlotContents(SLOT_INPUT, StackUtils.replenishByContainer(this, inventory.getStackInSlot(SLOT_INPUT), container, resourceTank)); + if (inventory.getStackInSlot(SLOT_INPUT).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_INPUT, null); + + } + } + // Can/capsule input/output needs to be handled here. + if (inventory.getStackInSlot(SLOT_CAN_INPUT) != null) { + FluidContainerData container = LiquidHelper.getEmptyContainer(inventory.getStackInSlot(SLOT_CAN_INPUT), productTank.getFluid()); + + if (container != null) { + inventory.setInventorySlotContents(SLOT_CAN_OUTPUT, bottleIntoContainer(inventory.getStackInSlot(SLOT_CAN_INPUT), inventory.getStackInSlot(SLOT_CAN_OUTPUT), container, + productTank)); + if (inventory.getStackInSlot(SLOT_CAN_INPUT).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_CAN_INPUT, null); + } + } + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + if (RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) != null) + setErrorState(EnumErrorCode.OK); + else if (inventory.getStackInSlot(SLOT_FUEL) == null && fuelBurnTime <= 0) + setErrorState(EnumErrorCode.NOFUEL); + else + setErrorState(EnumErrorCode.NORECIPE); + } + + @Override + public boolean workCycle() { + + if (currentRecipe == null) { + checkRecipe(); + resetRecipe(); + + if (currentRecipe != null) { + currentResourceModifier = determineResourceMod(inventory.getStackInSlot(SLOT_RESOURCE)); + decrStackSize(SLOT_RESOURCE, 1); + return true; + } else + return false; + + // If we have burnTime left, just decrease it. + } else if (fuelBurnTime > 0) { + if (currentRecipe == null) { + /* there was a fail-safe check for this before, but it can + never happen due to the 1st if clause unless there's some + thread unsafe accessing going on which has to fixed otherwise. */ + throw new NullPointerException("currentRecipe is null"); + } + + if (resourceTank.getFluidAmount() < fuelCurrentFerment) + return false; + + // Nothing to do, return + if (fermentationTime <= 0) + return false; + + int fermented = Math.min(fermentationTime, this.fuelCurrentFerment); + + // input are checked, add output if possible + if (!addProduct(new FluidStack(currentRecipe.output, + Math.round(fermented * currentRecipe.modifier * currentResourceModifier)))) { + return false; // the output tank is too full, TODO: check/add error code? + } + + fuelBurnTime--; + resourceTank.drain(fuelCurrentFerment, true); + fermentationTime -= this.fuelCurrentFerment; + + // Not done yet + if (fermentationTime > 0) + return true; + + currentRecipe = null; + return true; + + } else { // out of fuel + + // Use only fuel that provides value + fuelBurnTime = fuelTotalTime = determineFuelValue(getFuelStack()); + if (fuelBurnTime > 0) { + this.fuelCurrentFerment = determineFermentPerCycle(getFuelStack()); + decrStackSize(1, 1); + return true; + } else { + this.fuelCurrentFerment = 0; + return false; + } + } + } + + private boolean addProduct(FluidStack output) { + int amount = productTank.fill(output, false); + + if (amount == output.amount) { + productTank.fill(output, true); + + return true; + } else { + return false; + } + } + + private void checkRecipe() { + Recipe sameRec = RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()); + + if (currentRecipe != sameRec) + currentRecipe = sameRec; + } + + private void resetRecipe() { + if (currentRecipe == null) { + fermentationTime = 0; + fermentationTotalTime = 0; + return; + } + + fermentationTime = currentRecipe.fermentationValue; + fermentationTotalTime = currentRecipe.fermentationValue; + } + + /** + * Returns the burnTime an item of the passed ItemStack provides + * + * @param item + * @return + */ + private int determineFuelValue(ItemStack item) { + if (item == null) + return 0; + + if (FuelManager.fermenterFuel.containsKey(item)) + return FuelManager.fermenterFuel.get(item).burnDuration; + else + return 0; + } + + private int determineFermentPerCycle(ItemStack item) { + if (item == null) + return 0; + + if (FuelManager.fermenterFuel.containsKey(item)) + return FuelManager.fermenterFuel.get(item).fermentPerCycle; + else + return 0; + } + + private float determineResourceMod(ItemStack itemstack) { + if (!(itemstack.getItem() instanceof IVariableFermentable)) + return 1.0f; + + return ((IVariableFermentable) itemstack.getItem()).getFermentationModifier(itemstack); + } + + @Override + public boolean isWorking() { + if (currentRecipe == null + && RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) == null) + return false; + if (fuelBurnTime > 0) + return resourceTank.getFluidAmount() > 0 && productTank.getFluidAmount() < Defaults.PROCESSOR_TANK_CAPACITY; + else + return determineFuelValue(getFuelStack()) > 0; + } + + @Override + public boolean hasResourcesMin(float percentage) { + if (this.getFermentationStack() == null) + return false; + + return ((float) getFermentationStack().stackSize / (float) getFermentationStack().getMaxStackSize()) > percentage; + } + + @Override + public boolean hasFuelMin(float percentage) { + if (this.getFuelStack() == null) + return false; + + return ((float) getFuelStack().stackSize / (float) getFuelStack().getMaxStackSize()) > percentage; + } + + @Override + public boolean hasWork() { + if (this.getFuelStack() == null && fuelBurnTime <= 0) + return false; + else if (fuelBurnTime <= 0) + if (RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) == null) + return false; + + if (this.getFermentationStack() == null && fermentationTime <= 0) + return false; + else if (fermentationTime <= 0) + if (RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE), resourceTank.getFluid()) == null) + return false; + + if (resourceTank.getFluidAmount() <= 0) + return false; + + if (productTank.getFluidAmount() >= productTank.getCapacity()) + return false; + + return true; + } + + public int getBurnTimeRemainingScaled(int i) { + if (fuelTotalTime == 0) + return 0; + + return (fuelBurnTime * i) / fuelTotalTime; + } + + public int getFermentationProgressScaled(int i) { + if (fermentationTotalTime == 0) + return 0; + + return (fermentationTime * i) / fermentationTotalTime; + } + + public int getResourceScaled(int i) { + return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + public int getProductScaled(int i) { + return (productTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + @Override + public EnumTankLevel getPrimaryLevel() { + return Utils.rateTankLevel(getResourceScaled(100)); + } + + @Override + public EnumTankLevel getSecondaryLevel() { + return Utils.rateTankLevel(getProductScaled(100)); + } + + public ItemStack getFermentationStack() { + return inventory.getStackInSlot(SLOT_RESOURCE); + } + + public ItemStack getFuelStack() { + return inventory.getStackInSlot(SLOT_FUEL); + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + fuelBurnTime = j; + break; + case 1: + fuelTotalTime = j; + break; + case 2: + fermentationTime = j; + break; + case 3: + fermentationTotalTime = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, fuelBurnTime); + iCrafting.sendProgressBarUpdate(container, 1, fuelTotalTime); + iCrafting.sendProgressBarUpdate(container, 2, fermentationTime); + iCrafting.sendProgressBarUpdate(container, 3, fermentationTotalTime); + } + + /* INVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if (!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex == SLOT_CAN_OUTPUT) + return true; + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if (!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex == SLOT_RESOURCE && RecipeManager.isResource(itemstack)) + return true; + + + if (slotIndex == SLOT_INPUT) { + FluidContainerData container = LiquidHelper.getLiquidContainer(itemstack); + return container != null && RecipeManager.isLiquidResource(container.fluid); + } + + if (slotIndex == SLOT_CAN_INPUT && LiquidHelper.isEmptyContainer(itemstack)) { + return true; + } + if (slotIndex == SLOT_FUEL && FuelManager.fermenterFuel.containsKey(itemstack)) + return true; + + return false; + } + + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + // ILIQUIDCONTAINER IMPLEMENTATION + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + + if (!RecipeManager.isLiquidResource(resource)) + return 0; + + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + // updateNetworkTime.markTime(worldObj); + sendNetworkUpdate(); + + return used; + } + + @Override + public FluidStack drain(ForgeDirection from, int quantityMax, boolean doEmpty) { + return productTank.drain(quantityMax, doEmpty); + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank, productTank }; + } + + // ITRIGGERPROVIDER + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.lowFuel25); + res.add(ForestryTrigger.lowFuel10); + res.add(ForestryTrigger.lowResource25); + res.add(ForestryTrigger.lowResource10); + res.add(ForestryTrigger.hasWork); + return res; + } +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineMoistener.java b/forestry_common/factory/forestry/factory/gadgets/MachineMoistener.java new file mode 100755 index 000000000..f1341499b --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineMoistener.java @@ -0,0 +1,728 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.core.ForestryAPI; +import forestry.api.fuels.FuelManager; +import forestry.api.fuels.MoistenerFuel; +import forestry.api.recipes.IMoistenerManager; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class MachineMoistener extends TilePowered implements ISpecialInventory, ISidedInventory, ILiquidTankContainer { + + /* CONSTANTS */ + private static final short SLOT_STASH_1 = 0; + private static final short SLOT_RESERVOIR_1 = 6; + private static final short SLOT_WORKING = 9; + private static final short SLOT_PRODUCT = 10; + private static final short SLOT_RESOURCE = 11; + private static final short SLOTS_COUNT_RESERVOIR = 3; + private static final short SLOTS_COUNT_STASH = 6; + + private static final FluidStack STACK_WATER = LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1); + + /* RECIPE MANAGMENT */ + public static class Recipe { + public int timePerItem; + public ItemStack resource; + public ItemStack product; + + public Recipe(ItemStack resource, ItemStack product, int timePerItem) { + this.timePerItem = timePerItem; + this.resource = resource; + this.product = product; + } + + public boolean matches(ItemStack res) { + if (res == null && resource == null) + return true; + else if (res == null && resource != null) + return false; + else if (res != null && resource == null) + return false; + else + return resource.isItemEqual(res); + } + } + + public static class RecipeManager implements IMoistenerManager { + public static ArrayList recipes = new ArrayList(); + + @Override + public void addRecipe(ItemStack resource, ItemStack product, int timePerItem) { + recipes.add(new MachineMoistener.Recipe(resource, product, timePerItem)); + } + + public static boolean isResource(ItemStack resource) { + if(resource == null) + return false; + + for(Recipe rec : recipes) { + if(StackUtils.isIdenticalItem(resource, rec.resource)) + return true; + } + + return false; + } + + public static Recipe findMatchingRecipe(ItemStack item) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.matches(item)) + return recipe; + } + return null; + } + + @Override + public Map getRecipes() { + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) + recipeList.put(new ItemStack[] { recipe.resource }, new ItemStack[] { recipe.product }); + + return recipeList; + } + } + + @EntityNetData + public ForestryTank resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + private final InventoryAdapter inventory = new InventoryAdapter(12, "Items"); + //private ItemStack[] inventoryStacks = new ItemStack[12]; + public MachineMoistener.Recipe currentRecipe; + + public int burnTime = 0; + public int totalTime = 0; + public int productionTime = 0; + private int timePerItem = 0; + private ItemStack currentProduct; + private ItemStack pendingProduct; + + public MachineMoistener() { + setHints(Config.hints.get("moistener")); + } + + @Override + public String getInventoryName() { + return "factory.4"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.MoistenerGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + /* LOADING & SAVING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("BurnTime", burnTime); + nbttagcompound.setInteger("TotalTime", totalTime); + nbttagcompound.setInteger("ProductionTime", productionTime); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + + resourceTank.writeToNBT(NBTresourceSlot); + nbttagcompound.setTag("ResourceTank", NBTresourceSlot); + + inventory.writeToNBT(nbttagcompound); + + // Write pending product + if (pendingProduct != null) { + NBTTagCompound nbttagcompoundP = new NBTTagCompound(); + pendingProduct.writeToNBT(nbttagcompoundP); + nbttagcompound.setTag("PendingProduct", nbttagcompoundP); + } + if (currentProduct != null) { + NBTTagCompound nbttagcompoundP = new NBTTagCompound(); + currentProduct.writeToNBT(nbttagcompoundP); + nbttagcompound.setTag("CurrentProduct", nbttagcompoundP); + } + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + burnTime = nbttagcompound.getInteger("BurnTime"); + totalTime = nbttagcompound.getInteger("TotalTime"); + productionTime = nbttagcompound.getInteger("ProductionTime"); + + resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("ResourceTank")) + resourceTank.readFromNBT(nbttagcompound.getCompoundTag("ResourceTank")); + + inventory.readFromNBT(nbttagcompound); + + // Load pending product + if (nbttagcompound.hasKey("PendingProduct")) { + NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("PendingProduct"); + pendingProduct = ItemStack.loadItemStackFromNBT(nbttagcompoundP); + } + if (nbttagcompound.hasKey("CurrentProduct")) { + NBTTagCompound nbttagcompoundP = nbttagcompound.getCompoundTag("CurrentProduct"); + currentProduct = ItemStack.loadItemStackFromNBT(nbttagcompoundP); + } + + checkRecipe(); + } + + @Override + public void updateServerSide() { + + // Check if we have suitable water container waiting in the item slot + if (inventory.getStackInSlot(SLOT_PRODUCT) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_PRODUCT)); + if (container != null && container.fluid.isFluidEqual(STACK_WATER)) { + + inventory.setInventorySlotContents(SLOT_PRODUCT, StackUtils.replenishByContainer(this, inventory.getStackInSlot(SLOT_PRODUCT), container, resourceTank)); + if (inventory.getStackInSlot(SLOT_PRODUCT).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_PRODUCT, null); + } + } + + // Let's get to work + int lightvalue = worldObj.getBlockLightValue(xCoord, yCoord + 1, zCoord); + + // Not working in broad daylight + if (lightvalue > 11) { + setErrorState(EnumErrorCode.NOTGLOOMY); + return; + } + + // The darker, the better + int speed; + if (lightvalue >= 9) + speed = 1; + else if (lightvalue >= 7) + speed = 2; + else if (lightvalue >= 5) + speed = 3; + else + speed = 4; + + // Already running + if (burnTime > 0 && pendingProduct == null) { + // Not working if there is no water available. + if (resourceTank.getFluidAmount() <= 0) + return; + + checkRecipe(); + + if (currentRecipe == null) + return; + + resourceTank.drain(1, true); + burnTime -= speed; + productionTime -= speed; + + if (productionTime <= 0) { + pendingProduct = currentProduct; + decrStackSize(SLOT_RESOURCE, 1); + resetRecipe(); + tryAddPending(); + } + + } else if (pendingProduct != null) + tryAddPending(); + // Try to start process + else // Make sure we have a new item in the working slot. + if (rotateWorkingSlot()) { + checkRecipe(); + + // Let's see if we have a valid resource in the working slot + if (inventory.getStackInSlot(SLOT_WORKING) == null) + return; + + if (FuelManager.moistenerResource.containsKey(inventory.getStackInSlot(SLOT_WORKING))) { + MoistenerFuel res = FuelManager.moistenerResource.get(inventory.getStackInSlot(SLOT_WORKING)); + burnTime = totalTime = res.moistenerValue; + } + } else + rotateReservoir(); + + if (currentRecipe != null) + setErrorState(EnumErrorCode.OK); + else + setErrorState(EnumErrorCode.NORECIPE); + } + + private boolean tryAddPending() { + if (pendingProduct == null) + return false; + + if(inventory.tryAddStack(pendingProduct, SLOT_PRODUCT, 1, true)) { + pendingProduct = null; + return true; + } + + return false; + } + + public void checkRecipe() { + Recipe sameRec = RecipeManager.findMatchingRecipe(inventory.getStackInSlot(SLOT_RESOURCE)); + if (currentRecipe != sameRec) { + currentRecipe = sameRec; + resetRecipe(); + } + } + + private void resetRecipe() { + if (currentRecipe == null) { + currentProduct = null; + productionTime = 0; + timePerItem = 0; + setErrorState(EnumErrorCode.NORECIPE); + return; + } + + currentProduct = currentRecipe.product; + productionTime = currentRecipe.timePerItem; + timePerItem = currentRecipe.timePerItem; + } + + private int getFreeSlot(ItemStack deposit, int startSlot, int endSlot, boolean emptyOnly) { + int slot = -1; + + for (int i = startSlot; i < endSlot; i++) { + ItemStack slotStack = inventory.getStackInSlot(i); + // Empty slots are okay. + if (slotStack == null) { + if (slot < 0) + slot = i; + continue; + } + + if (emptyOnly) + continue; + + // Wrong item or full + if (!slotStack.isItemEqual(deposit) || slotStack.stackSize >= slotStack.getMaxStackSize()) + continue; + + slot = i; + } + + return slot; + } + + private int getFreeStashSlot(ItemStack deposit, boolean emptyOnly) { + return getFreeSlot(deposit, 0, SLOT_RESERVOIR_1, emptyOnly); + } + + private int getFreeReservoirSlot(ItemStack deposit) { + return getFreeSlot(deposit, SLOT_RESERVOIR_1, SLOT_RESERVOIR_1 + SLOTS_COUNT_RESERVOIR, false); + + } + + private int getNextResourceSlot(int startSlot, int endSlot) { + // Let's look for a new resource to put into the working slot. + int stage = -1; + int resourceSlot = -1; + + for (int i = startSlot; i < endSlot; i++) { + ItemStack slotStack = inventory.getStackInSlot(i); + if (slotStack == null) + continue; + + if (!FuelManager.moistenerResource.containsKey(slotStack)) + continue; + + MoistenerFuel res = FuelManager.moistenerResource.get(slotStack); + if (stage < 0 || res.stage < stage) { + stage = res.stage; + resourceSlot = i; + } + } + + return resourceSlot; + } + + private boolean rotateWorkingSlot() { + // Put working slot contents into inventory if space is available + if (inventory.getStackInSlot(SLOT_WORKING) != null) { + // Get the result of the consumed item in the working slot + ItemStack deposit; + if (FuelManager.moistenerResource.containsKey(inventory.getStackInSlot(SLOT_WORKING))) { + MoistenerFuel res = FuelManager.moistenerResource.get(inventory.getStackInSlot(SLOT_WORKING)); + deposit = res.product.copy(); + } else + deposit = inventory.getStackInSlot(SLOT_WORKING).copy(); + + int targetSlot = getFreeReservoirSlot(deposit); + // We stop the whole thing, if we don't have any room anymore. + if (targetSlot < 0) + return false; + + if (inventory.getStackInSlot(targetSlot) == null) + inventory.setInventorySlotContents(targetSlot, deposit); + else + inventory.getStackInSlot(targetSlot).stackSize++; + + decrStackSize(SLOT_WORKING, 1); + } + + if (inventory.getStackInSlot(SLOT_WORKING) != null) + return true; + + // Let's look for a new resource to put into the working slot. + int resourceSlot = getNextResourceSlot(SLOT_RESERVOIR_1, SLOT_RESERVOIR_1 + SLOTS_COUNT_RESERVOIR); + // Nothing found, stop. + if (resourceSlot < 0) + return false; + + inventory.setInventorySlotContents(SLOT_WORKING, inventory.decrStackSize(resourceSlot, 1)); + return true; + } + + private void rotateReservoir() { + ArrayList slotsToShift = new ArrayList(); + + for (int i = SLOT_RESERVOIR_1; i < SLOT_RESERVOIR_1 + SLOTS_COUNT_RESERVOIR; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + + if (!FuelManager.moistenerResource.containsKey(inventory.getStackInSlot(i))) + slotsToShift.add(i); + } + + // Move consumed items back to stash + int shiftedSlots = 0; + for (int slot : slotsToShift) { + ItemStack slotStack = inventory.getStackInSlot(slot); + int targetSlot = getFreeStashSlot(slotStack, true); + if (targetSlot < 0) + continue; + + inventory.setInventorySlotContents(targetSlot, slotStack); + inventory.setInventorySlotContents(slot, null); + shiftedSlots++; + } + + // Grab new items from stash + for (int i = 0; i < (slotsToShift.size() > 0 ? shiftedSlots : 2); i++) { + int resourceSlot = getNextResourceSlot(0, SLOT_RESERVOIR_1); + // Stop if no resources are available + if (resourceSlot < 0) + break; + int targetSlot = getFreeReservoirSlot(inventory.getStackInSlot(resourceSlot)); + // No free target slot, stop + if (targetSlot < 0) + break; + // Else shift + if (inventory.getStackInSlot(targetSlot) == null) { + inventory.setInventorySlotContents(targetSlot, inventory.getStackInSlot(resourceSlot)); + inventory.setInventorySlotContents(resourceSlot, null); + } else { + StackUtils.mergeStacks(inventory.getStackInSlot(resourceSlot), inventory.getStackInSlot(targetSlot)); + if (inventory.getStackInSlot(resourceSlot) != null && inventory.getStackInSlot(resourceSlot).stackSize <= 0) + inventory.setInventorySlotContents(resourceSlot, null); + } + } + } + + @Override + public boolean workCycle() { + return false; + } + + @Override + public boolean isWorking() { + return burnTime > 0 && resourceTank.getFluidAmount() > 0; + } + + @Override + public boolean hasFuelMin(float percentage) { + int max = 0; + int avail = 0; + + for (int i = SLOT_STASH_1; i < SLOT_RESERVOIR_1; i++) { + if (inventory.getStackInSlot(i) == null) { + max += 64; + continue; + } + if (FuelManager.moistenerResource.containsKey(inventory.getStackInSlot(i))) { + MoistenerFuel res = FuelManager.moistenerResource.get(inventory.getStackInSlot(i)); + if (res.item.isItemEqual(inventory.getStackInSlot(i))) { + max += 64; + avail += inventory.getStackInSlot(i).stackSize; + } + } + } + + return ((float) avail / (float) max) > percentage; + } + + @Override + public boolean hasResourcesMin(float percentage) { + if (inventory.getStackInSlot(SLOT_RESOURCE) == null) + return false; + + return ((float) inventory.getStackInSlot(SLOT_RESOURCE).stackSize / (float) inventory.getStackInSlot(SLOT_RESOURCE).getMaxStackSize()) > percentage; + } + + public boolean isProducing() { + return productionTime > 0; + } + + public int getProductionProgressScaled(int i) { + if (timePerItem == 0) + return 0; + + return (productionTime * i) / timePerItem; + + } + + public int getConsumptionProgressScaled(int i) { + if (totalTime == 0) + return 0; + + return (burnTime * i) / totalTime; + + } + + public int getResourceScaled(int i) { + return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + @Override + public EnumTankLevel getPrimaryLevel() { + return Utils.rateTankLevel(getResourceScaled(100)); + } + + /* IINVENTORY */ + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex == SLOT_PRODUCT) + return true; + + if(slotIndex >= SLOT_STASH_1 && slotIndex < SLOT_STASH_1 + SLOTS_COUNT_STASH) { + return !FuelManager.moistenerResource.containsKey(itemstack); + } + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex == SLOT_RESOURCE) + return RecipeManager.isResource(itemstack); + + if(slotIndex >= SLOT_STASH_1 && slotIndex < SLOT_STASH_1 + SLOTS_COUNT_STASH - 2) { + return FuelManager.moistenerResource.containsKey(itemstack); + } + + return false; + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + + FluidContainerData container = LiquidHelper.getLiquidContainer(stack); + if (container != null && container.fluid.isFluidEqual(STACK_WATER)) { + return inventory.addStack(stack, SLOT_PRODUCT, 1, false, doAdd); + } + + // Try to add to resource slot if input is from top or bottom. + if (from == ForgeDirection.UP || from == ForgeDirection.DOWN) { + return inventory.addStack(stack, SLOT_RESOURCE, 1, false, doAdd); + } + + return inventory.addStack(stack, SLOT_STASH_1, SLOTS_COUNT_STASH - 2, false, doAdd); + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + ItemStack product; + + ItemStack slotStack = inventory.getStackInSlot(SLOT_PRODUCT); + if (slotStack != null && slotStack.stackSize > 0) { + + product = new ItemStack(slotStack.getItem(), 1, slotStack.getItemDamage()); + if (doRemove) { + inventory.decrStackSize(SLOT_PRODUCT, 1); + } + return new ItemStack[] { product }; + } else + for (int i = 0; i < SLOT_RESERVOIR_1; i++) { + slotStack = inventory.getStackInSlot(i); + if (slotStack == null) + continue; + + if (!FuelManager.moistenerResource.containsKey(slotStack)) { + product = new ItemStack(slotStack.getItem(), 1, slotStack.getItemDamage()); + if (doRemove) { + inventory.decrStackSize(i, 1); + } + return new ItemStack[] { product }; + } + } + + return StackUtils.EMPTY_STACK_ARRAY; + } + + /* ILIQUIDCONTAINER */ + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + sendNetworkUpdate(); + + return used; + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank }; + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + burnTime = j; + break; + case 1: + totalTime = j; + break; + case 2: + productionTime = j; + break; + case 3: + timePerItem = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, burnTime); + iCrafting.sendProgressBarUpdate(container, 1, totalTime); + iCrafting.sendProgressBarUpdate(container, 2, productionTime); + iCrafting.sendProgressBarUpdate(container, 3, timePerItem); + } + + // ITRIGGERPROVIDER + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.lowFuel25); + res.add(ForestryTrigger.lowFuel10); + res.add(ForestryTrigger.lowResource25); + res.add(ForestryTrigger.lowResource10); + return res; + } + +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineRaintank.java b/forestry_common/factory/forestry/factory/gadgets/MachineRaintank.java new file mode 100755 index 000000000..bf29abc78 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineRaintank.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.LinkedList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.gates.ITrigger; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.ForestryAPI; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.Fluids; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class MachineRaintank extends TileBase implements ISidedInventory, ILiquidTankContainer { + + /* CONSTANTS */ + public static final short SLOT_RESOURCE = 0; + public static final short SLOT_PRODUCT = 1; + private static final FluidStack STACK_WATER = LiquidHelper.getLiquid(Defaults.LIQUID_WATER, Defaults.RAINTANK_AMOUNT_PER_UPDATE); + + /* MEMBER */ + public ForestryTank resourceTank = new ForestryTank(Defaults.RAINTANK_TANK_CAPACITY); + private final InventoryAdapter inventory = new InventoryAdapter(3, "Items"); + private boolean isValidBiome = true; + private int fillingTime; + private ItemStack usedEmpty; + + public MachineRaintank() { + setHints(Config.hints.get("raintank")); + + // Raintanks in desert and snow biomes are useless + if (worldObj != null) { + BiomeGenBase biome = Utils.getBiomeAt(worldObj, xCoord, zCoord); + if (EnumHumidity.getFromValue(biome.rainfall) == EnumHumidity.ARID) { + setErrorState(EnumErrorCode.INVALIDBIOME); + isValidBiome = false; + } + } + } + + @Override + public String getInventoryName() { + return "factory2.1"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.RaintankGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setBoolean("IsValidBiome", isValidBiome); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + resourceTank.writeToNBT(NBTresourceSlot); + nbttagcompound.setTag("ResourceTank", NBTresourceSlot); + + inventory.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + isValidBiome = nbttagcompound.getBoolean("IsValidBiome"); + + resourceTank = new ForestryTank(Defaults.RAINTANK_TANK_CAPACITY); + if (nbttagcompound.hasKey("ResourceTank")) + resourceTank.readFromNBT(nbttagcompound.getCompoundTag("ResourceTank")); + + inventory.readFromNBT(nbttagcompound); + } + + @Override + public void updateServerSide() { + if (!isValidBiome) + setErrorState(EnumErrorCode.INVALIDBIOME); + else if (!worldObj.canBlockSeeTheSky(xCoord, yCoord + 1, zCoord)) + setErrorState(EnumErrorCode.NOSKY); + else if (!worldObj.isRaining()) + setErrorState(EnumErrorCode.NOTRAINING); + else { + resourceTank.fill(STACK_WATER, true); + setErrorState(EnumErrorCode.OK); + } + + if (worldObj.getTotalWorldTime() % 16 != 0) + return; + + if (!StackUtils.isIdenticalItem(usedEmpty, inventory.getStackInSlot(SLOT_RESOURCE))) { + fillingTime = 0; + usedEmpty = null; + } + + if (usedEmpty == null) + usedEmpty = inventory.getStackInSlot(SLOT_RESOURCE); + + if (!isFilling()) + tryToStartFillling(); + else { + fillingTime--; + if (fillingTime <= 0 && LiquidHelper.fillContainers(this, inventory, SLOT_RESOURCE, SLOT_PRODUCT, Fluids.WATER.get())) + fillingTime = 0; + } + } + + public boolean isFilling() { + return fillingTime > 0; + } + + private void tryToStartFillling() { + // Nothing to do if no empty cans are available + if (!LiquidHelper.fillContainers(this, inventory, SLOT_RESOURCE, SLOT_PRODUCT, Fluids.WATER.get(), false)) + return; + + fillingTime = Defaults.RAINTANK_FILLING_TIME; + } + + public int getFillProgressScaled(int i) { + return (fillingTime * i) / Defaults.RAINTANK_FILLING_TIME; + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if (!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + return slotIndex == SLOT_PRODUCT; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if (!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex != SLOT_RESOURCE) + return false; + + return LiquidHelper.getEmptyContainer(itemstack, STACK_WATER) != null; + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + switch (i) { + case 0: + fillingTime = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, fillingTime); + } + + // / ILIQUIDCONTAINER IMPLEMENTATION + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + // We only accept water + if (!resource.isFluidEqual(STACK_WATER)) + return 0; + + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + // updateNetworkTime.markTime(worldObj); + sendNetworkUpdate(); + + return used; + } + + @Override + public FluidStack drain(ForgeDirection from, int quantityMax, boolean doEmpty) { + return resourceTank.drain(quantityMax, doEmpty); + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank }; + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.lowResource25); + res.add(ForestryTrigger.lowResource10); + res.add(ForestryTrigger.hasWork); + return res; + } +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineSqueezer.java b/forestry_common/factory/forestry/factory/gadgets/MachineSqueezer.java new file mode 100755 index 000000000..d52cc908c --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineSqueezer.java @@ -0,0 +1,558 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Stack; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; +import buildcraft.api.power.PowerHandler; + +import forestry.api.core.ForestryAPI; +import forestry.api.recipes.ISqueezerManager; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class MachineSqueezer extends TilePowered implements ISpecialInventory, ISidedInventory, ILiquidTankContainer { + + /* CONSTANTS */ + private static final short SLOT_RESOURCE_1 = 0; + private static final short SLOTS_RESOURCE_COUNT = 9; + private static final short SLOT_REMNANT = 9; + private static final short SLOT_CAN_INPUT = 10; + private static final short SLOT_CAN_OUTPUT = 11; + + /* RECIPE MANAGMENT */ + public static class Recipe { + public final int timePerItem; + public final ItemStack[] resources; + public final FluidStack liquid; + public final ItemStack remnants; + public final int chance; + + public Recipe(int timePerItem, ItemStack[] resources, FluidStack liquid, ItemStack remnants, int chance) { + this.timePerItem = timePerItem; + this.resources = resources; + this.liquid = liquid; + this.remnants = remnants; + this.chance = chance; + } + + public boolean matches(ItemStack[] res) { + // No recipe without resource! + if (res == null || res.length <= 0) + return false; + + boolean matchedAll = true; + + for (ItemStack stack : resources) { + boolean matched = false; + for (ItemStack matchStack : res) { + if (matchStack == null) + continue; + + // If the item matches, we need enough items + if (matchStack.isItemEqual(stack)) + if (matchStack.stackSize >= stack.stackSize) { + matched = true; + break; + } + } + if (!matched) + matchedAll = false; + } + return matchedAll; + } + } + + public static class RecipeManager implements ISqueezerManager { + public static ArrayList recipes = new ArrayList(); + + @Override + public void addRecipe(int timePerItem, ItemStack[] resources, FluidStack liquid, ItemStack remnants, int chance) { + recipes.add(new MachineSqueezer.Recipe(timePerItem, resources, liquid, remnants, chance)); + } + + @Override + public void addRecipe(int timePerItem, ItemStack[] resources, FluidStack liquid) { + addRecipe(timePerItem, resources, liquid, null, 0); + } + + public static Recipe findMatchingRecipe(ItemStack[] items) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.matches(items)) + return recipe; + } + + return null; + } + + @Override + public Map getRecipes() { + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) + recipeList.put(recipe.resources, new Object[] { recipe.remnants, recipe.liquid }); + + return recipeList; + } + } + + /* MEMBER */ + @EntityNetData + public ForestryTank productTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + + private final InventoryAdapter inventory = new InventoryAdapter(12, "Items"); + private Recipe currentRecipe; + + private final Stack pendingLiquids = new Stack(); + private final Stack pendingRemnants = new Stack(); + private int productionTime; + private int timePerItem; + + public MachineSqueezer() { + setHints(Config.hints.get("squeezer")); + } + + @Override + public String getInventoryName() { + return "factory.5"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.SqueezerGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(50, 110, 5, 400); + } + + /* LOADING & SAVING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("ProductionTime", productionTime); + nbttagcompound.setInteger("TimePerItem", timePerItem); + + // Inventory + inventory.writeToNBT(nbttagcompound); + + // Pending remnants + NBTTagList nbttaglist = new NBTTagList(); + ItemStack[] remnants = pendingRemnants.toArray(new ItemStack[pendingRemnants.size()]); + for (int i = 0; i < remnants.length; i++) + if (remnants[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + remnants[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("PendingRemnants", nbttaglist); + + // Pending liquids + nbttaglist = new NBTTagList(); + FluidStack[] liquids = pendingLiquids.toArray(new FluidStack[pendingLiquids.size()]); + for (int i = 0; i < liquids.length; i++) + if (liquids[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + liquids[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("PendingLiquids", nbttaglist); + + // ProductTank + NBTTagCompound NBTproductSlot = new NBTTagCompound(); + productTank.writeToNBT(NBTproductSlot); + nbttagcompound.setTag("ProductTank", NBTproductSlot); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + productionTime = nbttagcompound.getInteger("ProductionTime"); + timePerItem = nbttagcompound.getInteger("TimePerItem"); + + // Inventory + inventory.readFromNBT(nbttagcompound); + + // Pending remnants + NBTTagList nbttaglist = nbttagcompound.getTagList("PendingRemnants", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + pendingRemnants.add(ItemStack.loadItemStackFromNBT(nbttagcompound1)); + } + + // Pending liquids + nbttaglist = nbttagcompound.getTagList("PendingLiquids", 10); + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + pendingLiquids.add(FluidStack.loadFluidStackFromNBT(nbttagcompound1)); + } + + // Product tank + productTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("ProductTank")) + productTank.readFromNBT(nbttagcompound.getCompoundTag("ProductTank")); + + checkRecipe(); + } + + // / WORKING + @Override + public void updateServerSide() { + + // Can/capsule input/output needs to be handled here. + if (inventory.getStackInSlot(SLOT_CAN_INPUT) != null) { + + FluidContainerData container = LiquidHelper.getEmptyContainer(inventory.getStackInSlot(SLOT_CAN_INPUT), productTank.getFluid()); + if (container != null) { + inventory.setInventorySlotContents(SLOT_CAN_OUTPUT, bottleIntoContainer(inventory.getStackInSlot(SLOT_CAN_INPUT), inventory.getStackInSlot(SLOT_CAN_OUTPUT), container, productTank)); + if (inventory.getStackInSlot(SLOT_CAN_INPUT).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_CAN_INPUT, null); + } + + } + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + checkRecipe(); + if (getErrorState() == EnumErrorCode.NORECIPE && currentRecipe != null) + setErrorState(EnumErrorCode.OK); + + } + + @Override + public boolean workCycle() { + + checkRecipe(); + + // If we add pending products, we skip to the next work cycle. + tryAddPending(); + + if (!pendingLiquids.isEmpty() || !pendingRemnants.isEmpty()) + return false; + + // Continue work if nothing needs to be added + if (productionTime <= 0) + return false; + + if (currentRecipe == null) + return false; + + productionTime--; + // Still not done, return + if (productionTime > 0) { + setErrorState(EnumErrorCode.OK); + return true; + } + + // We are done, add products to queue + pendingLiquids.push(currentRecipe.liquid.copy()); + if (currentRecipe.remnants != null && worldObj.rand.nextInt(100) < currentRecipe.chance) + pendingRemnants.push(currentRecipe.remnants.copy()); + + removeResources(currentRecipe.resources); + + checkRecipe(); + resetRecipe(); + + tryAddPending(); + setErrorState(EnumErrorCode.OK); + + return true; + } + + private void checkRecipe() { + Recipe sameRec = RecipeManager.findMatchingRecipe(inventory.getStacks(SLOT_RESOURCE_1, 9)); + + if (sameRec == null) + setErrorState(EnumErrorCode.NORECIPE); + + if (currentRecipe != sameRec) { + currentRecipe = sameRec; + resetRecipe(); + } + } + + private void resetRecipe() { + if (currentRecipe == null) { + productionTime = 0; + timePerItem = 0; + return; + } + + productionTime = currentRecipe.timePerItem; + timePerItem = currentRecipe.timePerItem; + } + + private boolean tryAddPending() { + + if (!pendingLiquids.isEmpty()) { + FluidStack next = pendingLiquids.peek(); + if (addProduct(next)) { + pendingLiquids.pop(); + return true; + } + } + + if (!pendingRemnants.isEmpty()) { + ItemStack next = pendingRemnants.peek(); + if (addRemnant(next)) { + pendingRemnants.pop(); + return true; + } + } + + if (!pendingLiquids.isEmpty() || !pendingRemnants.isEmpty()) + setErrorState(EnumErrorCode.NOSPACE); + return false; + } + + private boolean addProduct(FluidStack stack) { + stack.amount -= productTank.fill(stack, true); + + if (stack.amount <= 0) + return true; + else + return false; + } + + private boolean addRemnant(ItemStack stack) { + return inventory.tryAddStack(stack, SLOT_REMNANT, 1, true); + } + + private void removeResources(ItemStack[] stacks) { + inventory.removeResources(stacks, SLOT_RESOURCE_1, SLOTS_RESOURCE_COUNT); + } + + @Override + public boolean isWorking() { + return currentRecipe != null && productTank.getFluidAmount() < productTank.getCapacity(); + } + + @Override + public boolean hasWork() { + return currentRecipe != null && productTank.getFluidAmount() < productTank.getCapacity(); + } + + public int getProgressScaled(int i) { + if (timePerItem == 0) + return i; + + return (productionTime * i) / timePerItem; + } + + public int getResourceScaled(int i) { + return (productTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + @Override + public EnumTankLevel getSecondaryLevel() { + return Utils.rateTankLevel(getResourceScaled(100)); + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + switch (i) { + case 0: + productionTime = j; + break; + case 1: + timePerItem = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, productionTime); + iCrafting.sendProgressBarUpdate(container, 1, timePerItem); + } + + /* IINVENTORY */ + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + return slotIndex == SLOT_REMNANT || slotIndex == SLOT_CAN_OUTPUT; + } + + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex == SLOT_CAN_INPUT) { + return LiquidHelper.isEmptyContainer(itemstack); + } + + if(slotIndex >= SLOT_RESOURCE_1 && slotIndex < SLOT_RESOURCE_1 + SLOTS_RESOURCE_COUNT) { + return !LiquidHelper.isEmptyContainer(itemstack); + } + + return false; + } + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + + // Try to add to can slot if input is from top or bottom. + if (LiquidHelper.isEmptyContainer(stack)) { + return inventory.addStack(stack, SLOT_CAN_INPUT, 1, false, doAdd); + } else { + return inventory.addStack(stack, SLOT_RESOURCE_1, SLOTS_RESOURCE_COUNT, false, doAdd); + } + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + ItemStack product; + + if (inventory.getStackInSlot(SLOT_CAN_OUTPUT) != null) { + + product = new ItemStack(inventory.getStackInSlot(SLOT_CAN_OUTPUT).getItem(), 1, inventory.getStackInSlot(SLOT_CAN_OUTPUT).getItemDamage()); + if (doRemove) { + inventory.decrStackSize(SLOT_CAN_OUTPUT, 1); + } + return new ItemStack[] { product }; + } else { + + if (inventory.getStackInSlot(SLOT_REMNANT) == null) + return StackUtils.EMPTY_STACK_ARRAY; + + product = new ItemStack(inventory.getStackInSlot(SLOT_REMNANT).getItem(), 1, inventory.getStackInSlot(SLOT_REMNANT).getItemDamage()); + if (doRemove) { + inventory.decrStackSize(SLOT_REMNANT, 1); + } + return new ItemStack[] { product }; + } + + } + + /* ILIQUIDCONTAINER IMPLEMENTATION */ + @Override + public FluidStack drain(ForgeDirection from, int quantityMax, boolean doEmpty) { + return productTank.drain(quantityMax, doEmpty); + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { productTank }; + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.hasWork); + return res; + } + +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MachineStill.java b/forestry_common/factory/forestry/factory/gadgets/MachineStill.java new file mode 100755 index 000000000..00b9d33bd --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MachineStill.java @@ -0,0 +1,495 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; +import buildcraft.api.power.PowerHandler; + +import forestry.api.core.ForestryAPI; +import forestry.api.recipes.IStillManager; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileBase; +import forestry.core.gadgets.TilePowered; +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.triggers.ForestryTrigger; +import forestry.core.utils.EnumTankLevel; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; + +public class MachineStill extends TilePowered implements ISpecialInventory, ISidedInventory, ILiquidTankContainer { + + /* CONSTANTS */ + public static final short SLOT_PRODUCT = 0; + public static final short SLOT_RESOURCE = 1; + public static final short SLOT_CAN = 2; + + public static class Recipe { + public final int timePerUnit; + public final FluidStack input; + public final FluidStack output; + + public Recipe(int timePerUnit, FluidStack input, FluidStack output) { + this.timePerUnit = timePerUnit; + if(input == null) + throw new IllegalArgumentException("Still recipes need an input. Input was null."); + if(output == null) + throw new IllegalArgumentException("Still recipes need an output. Output was null."); + this.input = input; + this.output = output; + } + + public boolean matches(FluidStack res) { + if (res == null && input == null) + return true; + else if (res == null && input != null) + return false; + else if (res != null && input == null) + return false; + else + return input.isFluidEqual(res); + } + } + + public static class RecipeManager implements IStillManager { + public static ArrayList recipes = new ArrayList(); + + @Override + public void addRecipe(int timePerUnit, FluidStack input, FluidStack output) { + recipes.add(new MachineStill.Recipe(timePerUnit, input, output)); + } + + public static Recipe findMatchingRecipe(FluidStack item) { + for (int i = 0; i < recipes.size(); i++) { + Recipe recipe = recipes.get(i); + if (recipe.matches(item)) + return recipe; + } + return null; + } + + public static boolean isInput(FluidStack res) { + return findMatchingRecipe(res) != null; + } + + @Override + public Map getRecipes() { + HashMap recipeList = new HashMap(); + + for (Recipe recipe : recipes) + recipeList.put(new Object[] { recipe.input }, new Object[] { recipe.output }); + + return recipeList; + } + } + + /* MEMBER */ + @EntityNetData + public ForestryTank resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + @EntityNetData + public ForestryTank productTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + + private final InventoryAdapter inventory = new InventoryAdapter(3, "Items"); + + private Recipe currentRecipe; + private FluidStack bufferedLiquid; + public int distillationTime = 0; + public int distillationTotalTime = 0; + + public MachineStill() { + setHints(Config.hints.get("still")); + } + + @Override + public String getInventoryName() { + return "factory.6"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.StillGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + @Override + protected void configurePowerProvider(PowerHandler provider) { + provider.configure(50, 110, 5, 800); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("DistillationTime", distillationTime); + nbttagcompound.setInteger("DistillationTotalTime", distillationTotalTime); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + NBTTagCompound NBTproductSlot = new NBTTagCompound(); + + resourceTank.writeToNBT(NBTresourceSlot); + productTank.writeToNBT(NBTproductSlot); + + nbttagcompound.setTag("ResourceTank", NBTresourceSlot); + nbttagcompound.setTag("ProductTank", NBTproductSlot); + + inventory.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + distillationTime = nbttagcompound.getInteger("DistillationTime"); + distillationTotalTime = nbttagcompound.getInteger("DistillationTotalTime"); + + resourceTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + productTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("ResourceTank")) { + resourceTank.readFromNBT(nbttagcompound.getCompoundTag("ResourceTank")); + productTank.readFromNBT(nbttagcompound.getCompoundTag("ProductTank")); + } + + inventory.readFromNBT(nbttagcompound); + + checkRecipe(); + } + + @Override + public void updateServerSide() { + + // Check if we have suitable items waiting in the item slot + if (inventory.getStackInSlot(SLOT_CAN) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_CAN)); + + if (container != null && RecipeManager.isInput(container.fluid)) { + + inventory.setInventorySlotContents(SLOT_CAN, StackUtils.replenishByContainer(this, inventory.getStackInSlot(SLOT_CAN), container, resourceTank)); + if (inventory.getStackInSlot(SLOT_CAN).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_CAN, null); + + } + } + + // Can product liquid if possible + if (inventory.getStackInSlot(SLOT_RESOURCE) != null) { + FluidContainerData container = LiquidHelper.getEmptyContainer(inventory.getStackInSlot(SLOT_RESOURCE), productTank.getFluid()); + if (container != null) { + inventory.setInventorySlotContents(SLOT_PRODUCT, bottleIntoContainer(inventory.getStackInSlot(SLOT_RESOURCE), inventory.getStackInSlot(SLOT_PRODUCT), container, productTank)); + if (inventory.getStackInSlot(SLOT_RESOURCE).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_RESOURCE, null); + } + } + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + checkRecipe(); + if (getErrorState() == EnumErrorCode.NORECIPE && currentRecipe != null) + setErrorState(EnumErrorCode.OK); + + } + + @Override + public boolean workCycle() { + + checkRecipe(); + + // Ongoing process + if (distillationTime > 0 && currentRecipe != null) { + + distillationTime -= currentRecipe.input.amount; + addProduct(currentRecipe.output.fluidID, currentRecipe.output.amount); + + setErrorState(EnumErrorCode.OK); + return true; + + } else if (currentRecipe != null && productTank.getFluidAmount() + currentRecipe.output.amount <= Defaults.PROCESSOR_TANK_CAPACITY) { + + int resReq = currentRecipe.timePerUnit * currentRecipe.input.amount; + // Start next cycle if enough bio mass is available + if (resourceTank.getFluidAmount() >= resReq) { + + distillationTime = distillationTotalTime = resReq; + resourceTank.drain(resReq, true); + bufferedLiquid = new FluidStack(currentRecipe.input.fluidID, resReq); + + setErrorState(EnumErrorCode.OK); + return true; + + } else + setErrorState(EnumErrorCode.NORESOURCE); + + } + + bufferedLiquid = null; + return false; + } + + private void addProduct(int id, int amount) { + + productTank.fill(new FluidStack(id, amount), true); + } + + public void checkRecipe() { + Recipe sameRec = RecipeManager.findMatchingRecipe(resourceTank.getFluid()); + + if (sameRec == null && bufferedLiquid != null && distillationTime > 0) + sameRec = RecipeManager.findMatchingRecipe(new FluidStack(bufferedLiquid.fluidID, distillationTime)); + + if (sameRec == null) + setErrorState(EnumErrorCode.NORECIPE); + + if (currentRecipe != sameRec) { + currentRecipe = sameRec; + resetRecipe(); + } + } + + private void resetRecipe() { + } + + @Override + public boolean isWorking() { + return distillationTime > 0 || currentRecipe != null && productTank.getFluidAmount() + currentRecipe.output.amount <= Defaults.PROCESSOR_TANK_CAPACITY; + } + + @Override + public boolean hasWork() { + if (currentRecipe == null) + return false; + + return (distillationTime > 0 || resourceTank.getFluidAmount() >= currentRecipe.timePerUnit * currentRecipe.input.amount) + && productTank.getFluidAmount() <= productTank.getCapacity() - currentRecipe.output.amount; + } + + public int getDistillationProgressScaled(int i) { + if (distillationTotalTime == 0) + return i; + + return (distillationTime * i) / distillationTotalTime; + } + + public int getResourceScaled(int i) { + return (resourceTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + public int getProductScaled(int i) { + return (productTank.getFluidAmount() * i) / Defaults.PROCESSOR_TANK_CAPACITY; + } + + @Override + public EnumTankLevel getPrimaryLevel() { + return Utils.rateTankLevel(getResourceScaled(100)); + } + + @Override + public EnumTankLevel getSecondaryLevel() { + return Utils.rateTankLevel(getProductScaled(100)); + } + + /* SMP GUI */ + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + distillationTime = j; + break; + case 1: + distillationTotalTime = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, distillationTime); + iCrafting.sendProgressBarUpdate(container, 1, distillationTotalTime); + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + int inventorySlot; + + FluidContainerData container = LiquidHelper.getLiquidContainer(stack); + if (container != null && RecipeManager.isInput(container.fluid)) + inventorySlot = SLOT_CAN; + else if (LiquidHelper.isEmptyContainer(stack)) + inventorySlot = SLOT_RESOURCE; + else + return 0; + + return inventory.addStack(stack, inventorySlot, 1, false, doAdd); + } + + /** + * Transport pipes cannot extract items from the still. + */ + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + ItemStack product = null; + + if (inventory.getStackInSlot(SLOT_PRODUCT) != null) { + + product = new ItemStack(inventory.getStackInSlot(SLOT_PRODUCT).getItem(), 1, inventory.getStackInSlot(SLOT_PRODUCT).getItemDamage()); + if (doRemove) { + inventory.decrStackSize(SLOT_PRODUCT, 1); + } + } + + if (product != null) + return new ItemStack[] { product }; + else + return StackUtils.EMPTY_STACK_ARRAY; + } + + /* IINVENTORY */ + @Override public int getSizeInventory() { return inventory.getSizeInventory(); } + @Override public ItemStack getStackInSlot(int i) { return inventory.getStackInSlot(i); } + @Override public ItemStack decrStackSize(int i, int j) { return inventory.decrStackSize(i, j); } + @Override public void setInventorySlotContents(int i, ItemStack itemstack) { inventory.setInventorySlotContents(i, itemstack); } + @Override public ItemStack getStackInSlotOnClosing(int slot) { return inventory.getStackInSlotOnClosing(slot); } + @Override public int getInventoryStackLimit() { return inventory.getInventoryStackLimit(); } + @Override public void openInventory() {} + @Override public void closeInventory() {} + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ISIDEDINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return inventory; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + return slotIndex == SLOT_PRODUCT; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex == SLOT_RESOURCE) + return LiquidHelper.isEmptyContainer(itemstack); + + if(slotIndex == SLOT_CAN) { + FluidContainerData container = LiquidHelper.getLiquidContainer(itemstack); + return container != null && RecipeManager.isInput(container.fluid); + } + + return false; + } + + /* ILIQUIDCONTAINER */ + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + + if (!MachineStill.RecipeManager.isInput(resource)) + return 0; + + int used = resourceTank.fill(resource, doFill); + + if (doFill && used > 0) + sendNetworkUpdate(); + + return used; + } + + @Override + public FluidStack drain(ForgeDirection from, int quantityMax, boolean doEmpty) { + return productTank.drain(quantityMax, doEmpty); + } + + @Override + public ForestryTank[] getTanks() { + return new ForestryTank[] { resourceTank, productTank }; + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(ForestryTrigger.hasWork); + return res; + } + +} diff --git a/forestry_common/factory/forestry/factory/gadgets/MillRainmaker.java b/forestry_common/factory/forestry/factory/gadgets/MillRainmaker.java new file mode 100755 index 000000000..39469dddd --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/MillRainmaker.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.fuels.FuelManager; +import forestry.api.fuels.RainSubstrate; +import forestry.core.gadgets.Mill; +import forestry.core.gadgets.TileBase; +import forestry.core.proxy.Proxies; + +public class MillRainmaker extends Mill implements ISpecialInventory { + + private int duration; + private boolean reverse; + + public MillRainmaker() { + speed = 0.01f; + } + + @Override + public String getInventoryName() { + return "Rainmaker"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + if (!Proxies.common.isSimulating(player.worldObj)) + return; + + if (player.inventory.getCurrentItem() == null) + return; + + // We don't have a gui, but we can be activated + if (FuelManager.rainSubstrate.containsKey(player.inventory.getCurrentItem()) && charge == 0) { + RainSubstrate substrate = FuelManager.rainSubstrate.get(player.inventory.getCurrentItem()); + if (substrate.item.isItemEqual(player.inventory.getCurrentItem())) { + addCharge(substrate); + player.inventory.getCurrentItem().stackSize--; + } + } + sendNetworkUpdate(); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + charge = nbttagcompound.getInteger("Charge"); + progress = nbttagcompound.getFloat("Progress"); + stage = nbttagcompound.getInteger("Stage"); + duration = nbttagcompound.getInteger("Duration"); + reverse = nbttagcompound.getBoolean("Reverse"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("Charge", charge); + nbttagcompound.setFloat("Progress", progress); + nbttagcompound.setInteger("Stage", stage); + nbttagcompound.setInteger("Duration", duration); + nbttagcompound.setBoolean("Reverse", reverse); + } + + public void addCharge(RainSubstrate substrate) { + charge = 1; + speed = substrate.speed; + duration = substrate.duration; + reverse = substrate.reverse; + } + + @Override + public void activate() { + if (Proxies.render.hasRendering()) { + worldObj.playSoundEffect(xCoord, yCoord, zCoord, "ambient.weather.thunder", 4F, + (1.0F + (worldObj.rand.nextFloat() - worldObj.rand.nextFloat()) * 0.2F) * 0.7F); + + float f = xCoord + 0.5F; + float f1 = yCoord + 0.0F + (worldObj.rand.nextFloat() * 6F) / 16F; + float f2 = zCoord + 0.5F; + float f3 = 0.52F; + float f4 = worldObj.rand.nextFloat() * 0.6F - 0.3F; + + Proxies.common.addEntityExplodeFX(worldObj, (f - f3), f1, (f2 + f4), 0F, 0F, 0F); + Proxies.common.addEntityExplodeFX(worldObj, (f + f3), f1, (f2 + f4), 0F, 0F, 0F); + Proxies.common.addEntityExplodeFX(worldObj, (f + f4), f1, (f2 - f3), 0F, 0F, 0F); + Proxies.common.addEntityExplodeFX(worldObj, (f + f4), f1, (f2 + f3), 0F, 0F, 0F); + } + + if (Proxies.common.isSimulating(worldObj)) { + if (reverse) + worldObj.getWorldInfo().setRaining(false); + else { + worldObj.getWorldInfo().setRaining(true); + worldObj.getWorldInfo().setRainTime(duration); + } + charge = 0; + duration = 0; + reverse = false; + sendNetworkUpdate(); + } + } + + @Override + public boolean workCycle() { + return false; + } + + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + if (charge != 0) + return 0; + + if (!FuelManager.rainSubstrate.containsKey(stack)) + return 0; + + RainSubstrate substrate = FuelManager.rainSubstrate.get(stack); + if (!substrate.item.isItemEqual(stack)) + return 0; + + if (doAdd) + addCharge(substrate); + return 1; + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + return null; + } + + @Override + public int getSizeInventory() { + return 0; + } + + @Override + public ItemStack getStackInSlot(int var1) { + return null; + } + + @Override + public ItemStack decrStackSize(int var1, int var2) { + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int var1) { + return null; + } + + @Override + public void setInventorySlotContents(int var1, ItemStack var2) { + } + + @Override + public int getInventoryStackLimit() { + return 0; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } +} diff --git a/forestry_common/factory/forestry/factory/gadgets/TileWorktable.java b/forestry_common/factory/forestry/factory/gadgets/TileWorktable.java new file mode 100755 index 000000000..21953c97e --- /dev/null +++ b/forestry_common/factory/forestry/factory/gadgets/TileWorktable.java @@ -0,0 +1,539 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gadgets; + +import java.util.LinkedList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; + +import forestry.api.core.ForestryAPI; +import forestry.api.core.INBTTagable; +import forestry.core.gadgets.TileBase; +import forestry.core.gui.ContainerDummy; +import forestry.core.interfaces.ICrafter; +import forestry.core.network.ForestryPacket; +import forestry.core.network.GuiId; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketTileNBT; +import forestry.core.network.PacketTileUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.PlainInventory; +import forestry.core.utils.StackUtils; +import forestry.core.utils.TileInventoryAdapter; + +public class TileWorktable extends TileBase implements ICrafter { + + /* CONSTANTS */ + public final static int SLOT_CRAFTING_1 = 0; + public final static int SLOT_CRAFTING_RESULT = 9; + public final static short SLOT_INVENTORY_1 = 0; + public final static short SLOT_INVENTORY_COUNT = 18; + private final static Container DUMMY_CONTAINER = new ContainerDummy(); + private final static RecipeBridge RECIPE_BRIDGE = new RecipeBridge(); + + private static class RecipeBridge { + + private final LinkedList overrides = new LinkedList(); + + public IRecipe getRecipe(InventoryCrafting crafting, World world) { + for (IRecipe recipe : overrides) { + if (recipe.matches(crafting, world)) + return recipe; + } + + for (Object obj : CraftingManager.getInstance().getRecipeList()) { + IRecipe recipe = (IRecipe) obj; + if (recipe.matches(crafting, world)) + return recipe; + } + + return null; + } + } + + /* RECIPE MEMORY */ + public static final class Recipe implements IRecipe, INBTTagable { + + private InventoryAdapter matrix; + private long lastUsed; + private boolean locked; + private World cachedWorld; + private IRecipe cachedRecipe; + + public Recipe(InventoryCrafting crafting) { + this.matrix = new InventoryAdapter(new PlainInventory(crafting)); + } + + public Recipe(NBTTagCompound nbttagcompound) { + readFromNBT(nbttagcompound); + } + + public void setCacheWorld(World world) { + this.cachedWorld = world; + } + + private boolean updateCachedIRecipe() { + + if (cachedRecipe != null) + return true; + + InventoryCrafting crafting = new InventoryCrafting(DUMMY_CONTAINER, 3, 3); + for (int i = 0; i < crafting.getSizeInventory(); i++) { + crafting.setInventorySlotContents(i, matrix.getStackInSlot(i)); + } + + cachedRecipe = RECIPE_BRIDGE.getRecipe(crafting, cachedWorld); + return cachedRecipe != null; + } + + public void updateLastUse(World world) { + lastUsed = world.getTotalWorldTime(); + setCacheWorld(world); + } + + public void toogleLock() { + locked = !locked; + } + + public InventoryAdapter getMatrix() { + return matrix; + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventorycrafting) { + if (updateCachedIRecipe()) + return cachedRecipe.getRecipeOutput(); + + return null; + } + + @Override + public ItemStack getRecipeOutput() { + if (updateCachedIRecipe()) + return cachedRecipe.getRecipeOutput(); + + return null; + } + + public long getLastUsed() { + return this.lastUsed; + } + + public boolean isLocked() { + return this.locked; + } + + @Override + public int getRecipeSize() { + return matrix.getSizeInventory(); + } + + @Override + public boolean matches(InventoryCrafting crafting, World world) { + if (crafting.getSizeInventory() != matrix.getSizeInventory()) + return false; + + if (!updateCachedIRecipe()) + return false; + + return cachedRecipe.matches(crafting, world); + } + + @Override + public final void readFromNBT(NBTTagCompound nbttagcompound) { + matrix = new InventoryAdapter(new InventoryCrafting(DUMMY_CONTAINER, 3, 3)); + matrix.readFromNBT(nbttagcompound); + sanitizeMatrix(); + lastUsed = nbttagcompound.getLong("LastUsed"); + locked = nbttagcompound.getBoolean("Locked"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + sanitizeMatrix(); + matrix.writeToNBT(nbttagcompound); + nbttagcompound.setLong("LastUsed", lastUsed); + nbttagcompound.setBoolean("Locked", locked); + } + + /** + * This is a nasty hack to hide a bug where the recipe stacks somehow + * get the stackSize set to -1. Which makes the recipe no longer work, + * ever. I've seen the bug, even inspected the NBT data of an afflicted + * worktable, but can't duplicate it, and can't trace it. -CovertJaguar + */ + private void sanitizeMatrix() { + for (int slot = 0; slot < matrix.getSizeInventory(); slot++) { + ItemStack stack = matrix.getStackInSlot(slot); + if (stack != null) + stack.stackSize = 1; + } + } + } + + public static class RecipeMemory implements INBTTagable, IInventory { + + private LinkedList recipes = new LinkedList(); + private long lastUpdate; + + public long getLastUpdate() { + return lastUpdate; + } + + public Recipe getOrCreateRecipe(World world, InventoryCrafting crafting) { + + Recipe memory = getMemorized(crafting, world); + if (memory != null) { + return memory; + } + + return new Recipe(crafting); + } + + public void memorizeRecipe(World world, Recipe recipe) { + + lastUpdate = world.getTotalWorldTime(); + recipe.updateLastUse(world); + + if (recipes.contains(recipe)) + return; + if (recipes.size() < 8) { + recipes.add(recipe); + return; + } + + Recipe oldest = null; + for (Recipe existing : recipes) { + if (oldest != null && oldest.getLastUsed() < existing.getLastUsed()) + continue; + if (existing.isLocked()) + continue; + + oldest = existing; + } + if (oldest != null) { + recipes.remove(oldest); + recipes.add(recipe); + } + + } + + public Recipe getRecipe(int recipeIndex) { + if (recipes.size() > recipeIndex) + return recipes.get(recipeIndex); + + return null; + } + + public ItemStack getRecipeOutput(int recipeIndex) { + if (recipes.size() > recipeIndex) + return recipes.get(recipeIndex).getRecipeOutput(); + else + return null; + } + + public boolean isLocked(int recipeIndex) { + if (recipes.size() > recipeIndex) + return recipes.get(recipeIndex).isLocked(); + + return false; + } + + public void toggleLock(World world, int recipeIndex) { + lastUpdate = world.getTotalWorldTime(); + if (recipes.size() > recipeIndex) + recipes.get(recipeIndex).toogleLock(); + } + + private Recipe getMemorized(InventoryCrafting crafting, World world) { + for (Recipe recipe : recipes) { + if (recipe.matches(crafting, world)) + return recipe; + } + + return null; + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + recipes = new LinkedList(); + if (!nbttagcompound.hasKey("RecipeMemory")) + return; + + NBTTagList nbttaglist = nbttagcompound.getTagList("RecipeMemory", 10); + for (int j = 0; j < nbttaglist.tagCount(); ++j) { + NBTTagCompound nbttagcompound2 = nbttaglist.getCompoundTagAt(j); + recipes.add(new Recipe(nbttagcompound2)); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + NBTTagList nbttaglist = new NBTTagList(); + for (int i = 0; i < recipes.size(); i++) { + if (recipes.get(i) != null) { + NBTTagCompound nbttagcompound2 = new NBTTagCompound(); + recipes.get(i).writeToNBT(nbttagcompound2); + nbttaglist.appendTag(nbttagcompound2); + } + } + nbttagcompound.setTag("RecipeMemory", nbttaglist); + } + + @Override + public int getSizeInventory() { + return recipes.size(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return getRecipeOutput(i); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int i) { + return null; + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + } + + @Override + public String getInventoryName() { + return ""; + } + + @Override + public boolean hasCustomInventoryName() { + return false; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public void markDirty() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return false; + } + } + /* MEMBERS */ + private Recipe currentRecipe; + private final RecipeMemory memorized; + private final TileInventoryAdapter craftingInventory; + private final TileInventoryAdapter accessibleInventory; + + public TileWorktable() { + craftingInventory = new TileInventoryAdapter(this, 10, "CraftItems"); + accessibleInventory = new TileInventoryAdapter(this, 18, "Items"); + + memorized = new RecipeMemory(); + } + + @Override + public String getInventoryName() { + return "factory2.2"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.WorktableGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + /* LOADING & SAVING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + craftingInventory.writeToNBT(nbttagcompound); + accessibleInventory.writeToNBT(nbttagcompound); + + memorized.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + craftingInventory.readFromNBT(nbttagcompound); + accessibleInventory.readFromNBT(nbttagcompound); + + memorized.readFromNBT(nbttagcompound); + } + + /* NETWORK */ + @Override + public void fromPacket(ForestryPacket packetRaw) { + if (packetRaw instanceof PacketTileUpdate) { + super.fromPacket(packetRaw); + return; + } + + PacketTileNBT packet = (PacketTileNBT) packetRaw; + readFromNBT(packet.getTagCompound()); + } + + public void sendAll(EntityPlayer player) { + Proxies.net.sendToPlayer(new PacketTileNBT(PacketIds.TILE_NBT, this), player); + } + + /* RECIPE SELECTION */ + public RecipeMemory getMemory() { + return memorized; + } + + public void chooseRecipe(int recipeIndex) { + if (recipeIndex == 9) { + for (int slot = 0; slot < craftingInventory.getSizeInventory(); slot++) { + craftingInventory.setInventorySlotContents(slot, null); + } + return; + } + + Recipe recipe = memorized.getRecipe(recipeIndex); + recipe.sanitizeMatrix(); + IInventory matrix = recipe.getMatrix(); + if (matrix == null) + return; + + for (int slot = 0; slot < matrix.getSizeInventory(); slot++) { + craftingInventory.setInventorySlotContents(slot, matrix.getStackInSlot(slot)); + } + } + + /* CRAFTING */ + public void setRecipe(InventoryCrafting crafting) { + + IRecipe recipe = RECIPE_BRIDGE.getRecipe(crafting, worldObj); + currentRecipe = recipe != null ? memorized.getOrCreateRecipe(worldObj, crafting) : null; + updateCraftResult(); + } + + private void updateCraftResult() { + if (currentRecipe != null) { + ItemStack result = currentRecipe.getCraftingResult(null); + if (result != null) { + craftingInventory.setInventorySlotContents(SLOT_CRAFTING_RESULT, result.copy()); + return; + } + } + + craftingInventory.setInventorySlotContents(SLOT_CRAFTING_RESULT, null); + } + + private boolean validateResources() { + // Need at least one matched set + if (currentRecipe == null) + return false; + return StackUtils.containsSets(currentRecipe.getMatrix().getStacks(SLOT_CRAFTING_1, 9), accessibleInventory.getStacks(SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT), currentRecipe.getRecipeOutput(), true, true) > 0; + } + + private void removeResources(EntityPlayer player) { + removeSets(1, craftingInventory.getStacks(SLOT_CRAFTING_1, 9), player); + } + + private void removeSets(int count, ItemStack[] set, EntityPlayer player) { + + for (int i = 0; i < count; i++) { + ItemStack[] condensedSet = StackUtils.condenseStacks(set); + for (ItemStack req : condensedSet) { + for (int j = SLOT_INVENTORY_1; j < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT; j++) { + ItemStack pol = accessibleInventory.getStackInSlot(j); + if (pol == null) + continue; + + if (!StackUtils.isCraftingEquivalent(pol, req, true, true)) + continue; + + ItemStack removed = accessibleInventory.decrStackSize(j, req.stackSize); + req.stackSize -= removed.stackSize; + + if (req.getItem().hasContainerItem(req)) + StackUtils.stowContainerItem(removed, accessibleInventory, j, player); + if (req.stackSize <= 0) + break; + } + } + } + + } + + @Override + public boolean canTakeStack(int slotIndex) { + return validateResources(); + } + + @Override + public ItemStack takenFromSlot(int slotIndex, boolean consumeRecipe, EntityPlayer player) { + if (!validateResources()) + return null; + + if (Proxies.common.isSimulating(worldObj)) + memorized.memorizeRecipe(worldObj, currentRecipe); + removeResources(player); + updateCraftResult(); + return currentRecipe.getRecipeOutput().copy(); + } + + @Override + public ItemStack getResult() { + if (currentRecipe == null) + return null; + + if (currentRecipe.getRecipeOutput() != null) + return currentRecipe.getRecipeOutput().copy(); + return null; + } + + /* INVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return accessibleInventory; + } + + /** + * @return Inaccessible crafting inventory for the craft grid. + */ + public InventoryAdapter getCraftingInventory() { + return craftingInventory; + } +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerBottler.java b/forestry_common/factory/forestry/factory/gui/ContainerBottler.java new file mode 100755 index 000000000..612db6a0d --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerBottler.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.factory.gadgets.MachineBottler; + +public class ContainerBottler extends ContainerLiquidTanks { + + protected MachineBottler tile; + + public ContainerBottler(InventoryPlayer player, MachineBottler tile) { + super(tile, tile); + + this.tile = tile; + this.addSlot(new SlotLiquidContainer(tile, MachineBottler.SLOT_RESOURCE, 116, 19, true)); + this.addSlot(new SlotClosed(tile, MachineBottler.SLOT_PRODUCT, 116, 55)); + this.addSlot(new SlotLiquidContainer(tile, MachineBottler.SLOT_CAN, 26, 38)); + + int var3; + for (var3 = 0; var3 < 3; ++var3) + for (int var4 = 0; var4 < 9; ++var4) + this.addSlot(new Slot(player, var4 + var3 * 9 + 9, 8 + var4 * 18, 84 + var3 * 18)); + + for (var3 = 0; var3 < 9; ++var3) + this.addSlot(new Slot(player, var3, 8 + var3 * 18, 142)); + + } + + // @Override client side only + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return tile.isUseableByPlayer(entityplayer); + } +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerCarpenter.java b/forestry_common/factory/forestry/factory/gui/ContainerCarpenter.java new file mode 100755 index 000000000..30a24fefb --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerCarpenter.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryCraftResult; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotCraftAuto; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.core.gui.slots.SlotLocked; +import forestry.core.gui.slots.SlotOutput; +import forestry.core.interfaces.IContainerCrafting; +import forestry.core.proxy.Proxies; +import forestry.factory.gadgets.MachineCarpenter; + +public class ContainerCarpenter extends ContainerLiquidTanks implements IContainerCrafting { + + private class SlotCrate extends SlotCraftAuto { + + public SlotCrate(IContainerCrafting container, IInventory iinventory, int slotNumber, int x, int y) { + super(container, iinventory, slotNumber, x, y); + } + + @Override + public boolean isItemValid(ItemStack stack) { + return MachineCarpenter.RecipeManager.isBox(stack); + } + } + private MachineCarpenter machine; + private final IInventory craftingInventory; + private IInventory internalInventory; + public InventoryCraftingAuto craftMatrix; + public InventoryCraftResult craftResult; + + public ContainerCarpenter(InventoryPlayer inventoryplayer, MachineCarpenter tile) { + super(tile.getInternalInventory(), tile); + + machine = tile; + machine.activeContainer = this; + craftingInventory = machine.getCraftingInventory(); + internalInventory = machine.getInternalInventory(); + + craftMatrix = new InventoryCraftingAuto(this, 3, 3); + craftResult = new InventoryCraftResult(); + + // Internal inventory + for (int i = 0; i < 2; i++) { + for (int k = 0; k < 9; k++) { + addSlot(new Slot(internalInventory, MachineCarpenter.SLOT_INVENTORY_1 + k + i * 9, 8 + k * 18, 90 + i * 18)); + } + } + + // Liquid Input + this.addSlot(new SlotLiquidContainer(internalInventory, MachineCarpenter.SLOT_CAN_INPUT, 120, 20)); + // Boxes + this.addSlot(new SlotCrate(this, internalInventory, MachineCarpenter.SLOT_BOX, 83, 20)); + // Product + this.addSlot(new SlotOutput(internalInventory, MachineCarpenter.SLOT_PRODUCT, 120, 56)); + + // CraftResult display + addSlot(new SlotLocked(craftResult, 0, 80, 51)); + + // Crafting matrix + for (int l = 0; l < 3; l++) { + for (int k1 = 0; k1 < 3; k1++) { + addSlot(new SlotCraftMatrix(this, craftingInventory, k1 + l * 3, 10 + k1 * 18, 20 + l * 18)); + } + } + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) { + for (int l1 = 0; l1 < 9; l1++) { + addSlot(new Slot(inventoryplayer, l1 + i1 * 9 + 9, 8 + l1 * 18, 136 + i1 * 18)); + } + } + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) { + addSlot(new Slot(inventoryplayer, j1, 8 + j1 * 18, 194)); + } + + // Update crafting matrix with current contents of tileentity. + for (int i = 0; i < craftMatrix.getSizeInventory(); i++) { + craftMatrix.setInventorySlotContents(i, craftingInventory.getStackInSlot(i)); + } + } + + public ContainerCarpenter(MachineCarpenter tile) { + super(tile.getInternalInventory(), tile); + craftMatrix = new InventoryCraftingAuto(this, 3, 3); + craftResult = new InventoryCraftResult(); + craftingInventory = tile.getCraftingInventory(); + + // Update crafting matrix with current contents of tileentity. + for (int i = 0; i < craftMatrix.getSizeInventory(); i++) { + craftMatrix.setInventorySlotContents(i, craftingInventory.getStackInSlot(i)); + } + } + + @Override + public void updateProgressBar(int i, int j) { + machine.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) { + machine.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + updateProductSlot(); + } + + /** + * Replaces the original onCraftMatrixChanged + * + * @param iinventory + * @param slot + */ + @Override + public void onCraftMatrixChanged(IInventory iinventory, int slot) { + craftingInventory.setInventorySlotContents(slot, iinventory.getStackInSlot(slot)); + if (slot < craftMatrix.stackList.length) + craftMatrix.stackList[slot] = iinventory.getStackInSlot(slot); + resetProductDisplay(); + } + + public void updateProductDisplay() { + // Update crafting matrix with current contents of tileentity. + for (int i = 0; i < craftMatrix.getSizeInventory(); i++) { + craftMatrix.setInventorySlotContents(i, craftingInventory.getStackInSlot(i)); + } + resetProductDisplay(); + } + + private void resetProductDisplay() { + if (machine != null) { + machine.setCurrentRecipe(MachineCarpenter.RecipeManager.findMatchingRecipe(machine.resourceTank.getFluid(), machine.getBoxStack(), craftMatrix, + machine.getWorldObj())); + updateProductSlot(); + } + } + + private void updateProductSlot() { + // Update crafting display + if (machine.currentRecipe != null) + craftResult.setInventorySlotContents(0, machine.currentRecipe.getCraftingResult()); + else + craftResult.setInventorySlotContents(0, null); + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + machine.activeContainer = null; + if (entityplayer == null) + return; + + InventoryPlayer inventoryplayer = entityplayer.inventory; + if (inventoryplayer.getItemStack() != null) { + Proxies.common.dropItemPlayer(entityplayer, inventoryplayer.getItemStack()); + inventoryplayer.setItemStack(null); + } + + } +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerCentrifuge.java b/forestry_common/factory/forestry/factory/gui/ContainerCentrifuge.java new file mode 100755 index 000000000..4dbee591d --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerCentrifuge.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotClosed; +import forestry.factory.gadgets.MachineCentrifuge; + +public class ContainerCentrifuge extends ContainerForestry { + + protected MachineCentrifuge tile; + + public ContainerCentrifuge(InventoryPlayer player, MachineCentrifuge tile) { + super(tile); + + this.tile = tile; + + // Resource + this.addSlot(new Slot(tile, 0, 34, 37)); + + // Product Inventory + for (int l = 0; l < 3; l++) + for (int k = 0; k < 3; k++) + addSlot(new SlotClosed(tile, 1 + k + l * 3, 98 + k * 18, 19 + l * 18)); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSlot(new Slot(player, l1 + i1 * 9 + 9, 8 + l1 * 18, 84 + i1 * 18)); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSlot(new Slot(player, j1, 8 + j1 * 18, 142)); + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerFabricator.java b/forestry_common/factory/forestry/factory/gui/ContainerFabricator.java new file mode 100755 index 000000000..6214b55a7 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerFabricator.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotCrafter; +import forestry.factory.gadgets.MachineFabricator; + +public class ContainerFabricator extends ContainerLiquidTanks { + + private MachineFabricator tile; + + public ContainerFabricator(InventoryPlayer player, MachineFabricator tile) { + super(tile, tile); + this.tile = tile; + + // Internal inventory + for (int i = 0; i < 2; i++) + for (int k = 0; k < 9; k++) + addSlot(new Slot(tile, MachineFabricator.SLOT_INVENTORY_1 + k + i * 9, 8 + k * 18, 84 + i * 18)); + + // Molten resource + this.addSlot(new Slot(tile, MachineFabricator.SLOT_METAL, 26, 21)); + + // Plan + this.addSlot(new Slot(tile, MachineFabricator.SLOT_PLAN, 139, 17)); + + // Result + this.addSlot(new SlotCrafter(tile, tile, MachineFabricator.SLOT_RESULT, 139, 53)); + + // Crafting matrix + for (int l = 0; l < 3; l++) + for (int k = 0; k < 3; k++) + addSlot(new Slot(tile, MachineFabricator.SLOT_CRAFTING_1 + k + l * 3, 67 + k * 18, 17 + l * 18)); + + // Player inventory + for (int i = 0; i < 3; i++) + for (int k = 0; k < 9; k++) + addSlot(new Slot(player, k + i * 9 + 9, 8 + k * 18, 129 + i * 18)); + // Player hotbar + for (int j = 0; j < 9; j++) + addSlot(new Slot(player, j, 8 + j * 18, 187)); + + } + + // @Override client side only + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerFermenter.java b/forestry_common/factory/forestry/factory/gui/ContainerFermenter.java new file mode 100755 index 000000000..aff002beb --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerFermenter.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.core.gui.slots.SlotOutput; +import forestry.factory.gadgets.MachineFermenter; + +public class ContainerFermenter extends ContainerLiquidTanks { + protected MachineFermenter fermenter; + + public ContainerFermenter(InventoryPlayer player, MachineFermenter fermenter) { + super(fermenter, fermenter); + + this.fermenter = fermenter; + this.addSlot(new SlotCustom(fermenter, MachineFermenter.SLOT_RESOURCE, 85, 23, true)); + this.addSlot(new SlotCustom(fermenter, MachineFermenter.SLOT_FUEL, 75, 57, true)); + this.addSlot(new SlotOutput(fermenter, MachineFermenter.SLOT_CAN_OUTPUT, 150, 58)); + this.addSlot(new SlotLiquidContainer(fermenter, MachineFermenter.SLOT_CAN_INPUT, 150, 22, true)); + this.addSlot(new SlotLiquidContainer(fermenter, MachineFermenter.SLOT_INPUT, 10, 40)); + + for (int i = 0; i < 3; ++i) + for (int var4 = 0; var4 < 9; ++var4) + this.addSlot(new Slot(player, var4 + i * 9 + 9, 8 + var4 * 18, 84 + i * 18)); + + for (int i = 0; i < 9; ++i) + this.addSlot(new Slot(player, i, 8 + i * 18, 142)); + + } + + @Override + public void updateProgressBar(int i, int j) { + fermenter.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + fermenter.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return fermenter.isUseableByPlayer(entityplayer); + } +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerMoistener.java b/forestry_common/factory/forestry/factory/gui/ContainerMoistener.java new file mode 100755 index 000000000..70625ea4d --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerMoistener.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotCraftAuto; +import forestry.core.gui.slots.SlotWorking; +import forestry.core.interfaces.IContainerCrafting; +import forestry.factory.gadgets.MachineMoistener; + +public class ContainerMoistener extends ContainerLiquidTanks implements IContainerCrafting { + + protected MachineMoistener tile; + + public ContainerMoistener(InventoryPlayer player, MachineMoistener tile) { + super(tile, tile); + + this.tile = tile; + // Stash + for (int l = 0; l < 2; l++) + for (int k1 = 0; k1 < 3; k1++) + addSlot(new Slot(tile, k1 + l * 3, 39 + k1 * 18, 16 + l * 18)); + // Reservoir + for (int k1 = 0; k1 < 3; k1++) + addSlot(new Slot(tile, k1 + 6, 39 + k1 * 18, 22 + 36)); + + // Working slot + this.addSlot(new SlotWorking(tile, 9, 105, 37)); + + // Product slot + this.addSlot(new Slot(tile, 10, 143, 55)); + // Boxes + this.addSlot(new SlotCraftAuto(this, tile, 11, 143, 19)); + + // Player inventory + int var3; + for (var3 = 0; var3 < 3; ++var3) + for (int var4 = 0; var4 < 9; ++var4) + this.addSlot(new Slot(player, var4 + var3 * 9 + 9, 8 + var4 * 18, 84 + var3 * 18)); + + for (var3 = 0; var3 < 9; ++var3) + this.addSlot(new Slot(player, var3, 8 + var3 * 18, 142)); + + } + + // @Override client side only + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + @Override + public void onCraftMatrixChanged(IInventory iinventory, int slot) { + inventory.setInventorySlotContents(slot, iinventory.getStackInSlot(slot)); + tile.checkRecipe(); + } + + @Override + public boolean canInteractWith(EntityPlayer player) { + return this.tile.isUseableByPlayer(player); + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerRaintank.java b/forestry_common/factory/forestry/factory/gui/ContainerRaintank.java new file mode 100755 index 000000000..2e7eb584d --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerRaintank.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.factory.gadgets.MachineRaintank; + +public class ContainerRaintank extends ContainerLiquidTanks { + + protected MachineRaintank tile; + + public ContainerRaintank(InventoryPlayer player, MachineRaintank tile) { + super(tile, tile); + + this.tile = tile; + this.addSlot(new SlotLiquidContainer(tile, MachineRaintank.SLOT_RESOURCE, 116, 19, true)); + this.addSlot(new SlotClosed(tile, MachineRaintank.SLOT_PRODUCT, 116, 55)); + + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 9; ++j) + this.addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + + for (int i = 0; i < 9; ++i) + this.addSlot(new Slot(player, i, 8 + i * 18, 142)); + + } + + // @Override client side only + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return tile.isUseableByPlayer(entityplayer); + } +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerSqueezer.java b/forestry_common/factory/forestry/factory/gui/ContainerSqueezer.java new file mode 100755 index 000000000..107379538 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerSqueezer.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.factory.gadgets.MachineSqueezer; + +public class ContainerSqueezer extends ContainerLiquidTanks { + + protected MachineSqueezer tile; + + public ContainerSqueezer(InventoryPlayer player, MachineSqueezer tile) { + super(tile, tile); + + this.tile = tile; + + // Resource inventory + for (int l = 0; l < 3; l++) + for (int k = 0; k < 3; k++) + addSlot(new Slot(tile, k + l * 3, 19 + k * 18, 18 + l * 18)); + + // Remnants slot + this.addSlot(new SlotClosed(tile, 9, 123, 19)); + + // Can slot + this.addSlot(new SlotLiquidContainer(tile, 10, 106, 55, true)); + // Output slot + this.addSlot(new SlotClosed(tile, 11, 140, 55)); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSlot(new Slot(player, l1 + i1 * 9 + 9, 8 + l1 * 18, 84 + i1 * 18)); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSlot(new Slot(player, j1, 8 + j1 * 18, 142)); + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerStill.java b/forestry_common/factory/forestry/factory/gui/ContainerStill.java new file mode 100755 index 000000000..6f80b54dd --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerStill.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerLiquidTanks; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.factory.gadgets.MachineStill; + +public class ContainerStill extends ContainerLiquidTanks { + protected MachineStill processor; + + public ContainerStill(InventoryPlayer player, MachineStill tile) { + super(tile, tile); + + this.processor = tile; + this.addSlot(new Slot(tile, MachineStill.SLOT_PRODUCT, 150, 54)); + this.addSlot(new SlotLiquidContainer(tile, MachineStill.SLOT_RESOURCE, 150, 18, true)); + this.addSlot(new SlotLiquidContainer(tile, MachineStill.SLOT_CAN, 10, 36)); + + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 9; ++j) + this.addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + + for (int i = 0; i < 9; ++i) + this.addSlot(new Slot(player, i, 8 + i * 18, 142)); + + } + + // @Override client side only + public void updateProgressBar(int i, int j) { + processor.getGUINetworkData(i, j); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) + processor.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return processor.isUseableByPlayer(entityplayer); + } +} diff --git a/forestry_common/factory/forestry/factory/gui/ContainerWorktable.java b/forestry_common/factory/forestry/factory/gui/ContainerWorktable.java new file mode 100755 index 000000000..829bc84ef --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/ContainerWorktable.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryCraftResult; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.IGuiSelectable; +import forestry.core.gui.slots.SlotCrafter; +import forestry.core.interfaces.IContainerCrafting; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.factory.gadgets.TileWorktable; + +public class ContainerWorktable extends ContainerForestry implements IContainerCrafting, IGuiSelectable { + + EntityPlayer player; + TileWorktable tile; + IInventory craftingInventory; + IInventory internalInventory; + InventoryCrafting craftMatrix = new InventoryCrafting(this, 3, 3); + InventoryCraftResult craftResult = new InventoryCraftResult(); + long lastUpdate; + + public ContainerWorktable(EntityPlayer player, TileWorktable tile) { + super(tile.getInternalInventory()); + this.tile = tile; + + craftingInventory = tile.getCraftingInventory(); + internalInventory = tile.getInternalInventory(); + + // Internal inventory + for (int i = 0; i < 2; i++) { + for (int k = 0; k < 9; k++) { + addSlot(new Slot(internalInventory, TileWorktable.SLOT_INVENTORY_1 + k + i * 9, 8 + k * 18, 90 + i * 18)); + } + } + + // Crafting matrix + for (int l = 0; l < 3; l++) { + for (int k1 = 0; k1 < 3; k1++) { + addSlot(new SlotCraftMatrix(this, craftingInventory, k1 + l * 3, 11 + k1 * 18, 20 + l * 18)); + } + } + + // CraftResult display + addSlot(new SlotCrafter(craftingInventory, tile, TileWorktable.SLOT_CRAFTING_RESULT, 77, 38)); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) { + for (int l1 = 0; l1 < 9; l1++) { + addSlot(new Slot(player.inventory, l1 + i1 * 9 + 9, 8 + l1 * 18, 136 + i1 * 18)); + } + } + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) { + addSlot(new Slot(player.inventory, j1, 8 + j1 * 18, 194)); + } + + // Update crafting matrix with current contents of tileentity. + updateMatrix(); + updateRecipe(); + + this.player = player; + tile.sendAll(player); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (lastUpdate == tile.getMemory().getLastUpdate()) + return; + + lastUpdate = tile.getMemory().getLastUpdate(); + tile.sendAll(player); + } + + @Override + public void onCraftMatrixChanged(IInventory iinventory, int slot) { +// craftingInventory.setInventorySlotContents(slot, iinventory.getStackInSlot(slot)); + if (slot < craftMatrix.getSizeInventory()) + craftMatrix.setInventorySlotContents(slot, iinventory.getStackInSlot(slot)); + updateRecipe(); + } + + private void updateMatrix() { + for (int i = 0; i < craftMatrix.getSizeInventory(); i++) { + craftMatrix.setInventorySlotContents(i, craftingInventory.getStackInSlot(i)); + } + } + + private void updateRecipe() { + tile.setRecipe(craftMatrix); + } + + public void sendRecipeClick(int mouseButton, int recipeIndex) { + PacketPayload payload = new PacketPayload(2, 0, 0); + payload.intPayload[0] = mouseButton; + payload.intPayload[1] = recipeIndex; + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + } + + @Override + public void handleSelectionChange(EntityPlayer player, PacketUpdate packet) { + if (packet.payload.intPayload[0] > 0) { + tile.getMemory().toggleLock(player.worldObj, packet.payload.intPayload[1]); + } else { + tile.chooseRecipe(packet.payload.intPayload[1]); + updateMatrix(); + updateRecipe(); + } + } + + @Override + public void setSelection(PacketUpdate packet) { + } +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiBottler.java b/forestry_common/factory/forestry/factory/gui/GuiBottler.java new file mode 100755 index 000000000..f49cf4713 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiBottler.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineBottler; + +public class GuiBottler extends GuiForestry { + + public GuiBottler(InventoryPlayer inventory, MachineBottler processor) { + super(Defaults.TEXTURE_PATH_GUI + "/bottler.png", new ContainerBottler(inventory, processor), processor); + widgetManager.add(new TankWidget(this.widgetManager, 53, 17, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineBottler boiler = tile; + + if (boiler.isWorking()) { + int i1 = boiler.getFillProgressScaled(24); + drawTexturedModalRect(guiLeft + 80, guiTop + 39, 176, 74, 24 - i1, 16); + } + } +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiCarpenter.java b/forestry_common/factory/forestry/factory/gui/GuiCarpenter.java new file mode 100755 index 000000000..d8d5b4c67 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiCarpenter.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineCarpenter; + +public class GuiCarpenter extends GuiForestry { + + public GuiCarpenter(InventoryPlayer inventory, MachineCarpenter tile) { + super(Defaults.TEXTURE_PATH_GUI + "/carpenter.png", new ContainerCarpenter(inventory, tile), tile); + this.ySize = 218; + + widgetManager.add(new TankWidget(this.widgetManager, 150, 17, 0)); + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + inventorySlots.onContainerClosed(mc.thePlayer); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineCarpenter machine = tile; + + if (machine.isWorking()) { + int progressScaled = 16 - machine.getCraftingProgressScaled(16); + drawTexturedModalRect(guiLeft + 98, guiTop + 51 + 16 - progressScaled, 176, 60 + 16 - progressScaled, 4, progressScaled); + } + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiCentrifuge.java b/forestry_common/factory/forestry/factory/gui/GuiCentrifuge.java new file mode 100755 index 000000000..6615d8527 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiCentrifuge.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineCentrifuge; + +public class GuiCentrifuge extends GuiForestry { + + public GuiCentrifuge(InventoryPlayer inventory, MachineCentrifuge tile) { + super(Defaults.TEXTURE_PATH_GUI + "/centrifuge.png", new ContainerCentrifuge(inventory, tile), tile); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineCentrifuge machine = tile; + + int progress = 16 - machine.getProgressScaled(16); + drawTexturedModalRect(guiLeft + 62, guiTop + 36 + 17 - progress, 176, 17 - progress, 4, progress); + } +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiFabricator.java b/forestry_common/factory/forestry/factory/gui/GuiFabricator.java new file mode 100755 index 000000000..9d11fe70b --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiFabricator.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.ReservoirWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineFabricator; + +public class GuiFabricator extends GuiForestry { + + public GuiFabricator(InventoryPlayer player, MachineFabricator tile) { + super(Defaults.TEXTURE_PATH_GUI + "/fabricator.png", new ContainerFabricator(player, tile), tile); + this.ySize = 211; + widgetManager.add(new ReservoirWidget(this.widgetManager, 26, 48, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + MachineFabricator fabricator = tile; + int heatScaled = fabricator.getHeatScaled(52); + if (heatScaled > 0) + drawTexturedModalRect(guiLeft + 55, guiTop + 17 + 52 - heatScaled, 192, 0 + 52 - heatScaled, 4, heatScaled); + + int meltingPointScaled = fabricator.getMeltingPointScaled(52); + if (meltingPointScaled > 0) + drawTexturedModalRect(guiLeft + 52, guiTop + 15 + 52 - meltingPointScaled, 196, 0, 10, 5); + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiFermenter.java b/forestry_common/factory/forestry/factory/gui/GuiFermenter.java new file mode 100755 index 000000000..8abea8c09 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiFermenter.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineFermenter; + +public class GuiFermenter extends GuiForestry { + + public GuiFermenter(InventoryPlayer inventory, MachineFermenter tile) { + super(Defaults.TEXTURE_PATH_GUI + "/fermenter.png", new ContainerFermenter(inventory, tile), tile); + widgetManager.add(new TankWidget(this.widgetManager, 35, 19, 0)); + widgetManager.add(new TankWidget(this.widgetManager, 125, 19, 1)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineFermenter machine = tile; + + // Fuel remaining + int fuelRemain = machine.getBurnTimeRemainingScaled(16); + if (fuelRemain > 0) + drawTexturedModalRect(guiLeft + 98, guiTop + 46 + 17 - fuelRemain, 176, 78 + 17 - fuelRemain, 4, fuelRemain); + + // Raw bio mush remaining + int bioRemain = machine.getFermentationProgressScaled(16); + if (bioRemain > 0) + drawTexturedModalRect(guiLeft + 74, guiTop + 32 + 17 - bioRemain, 176, 60 + 17 - bioRemain, 4, bioRemain); + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiMoistener.java b/forestry_common/factory/forestry/factory/gui/GuiMoistener.java new file mode 100755 index 000000000..32500d264 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiMoistener.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineMoistener; + +public class GuiMoistener extends GuiForestry { + + public GuiMoistener(InventoryPlayer inventory, MachineMoistener tile) { + super(Defaults.TEXTURE_PATH_GUI + "/moistener.png", new ContainerMoistener(inventory, tile), tile); + widgetManager.add(new TankWidget(this.widgetManager, 16, 16, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineMoistener machine = tile; + + // Mycelium production progress + if (machine.isProducing()) { + int i1 = machine.getProductionProgressScaled(16); + drawTexturedModalRect(guiLeft + 124, guiTop + 36, 176, 74, 16 - i1, 16); + } + + // Resource consumption progress + if (machine.isWorking()) { + int i1 = machine.getConsumptionProgressScaled(54); + drawTexturedModalRect(guiLeft + 93, guiTop + 18 + i1, 176, 92 + i1, 29, 54 - i1); + } + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiRaintank.java b/forestry_common/factory/forestry/factory/gui/GuiRaintank.java new file mode 100755 index 000000000..dff6dcaa8 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiRaintank.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineRaintank; + +public class GuiRaintank extends GuiForestry { + + public GuiRaintank(InventoryPlayer inventory, MachineRaintank tile) { + super(Defaults.TEXTURE_PATH_GUI + "/raintank.png", new ContainerRaintank(inventory, tile), tile); + widgetManager.add(new TankWidget(this.widgetManager, 53, 17, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineRaintank machine = tile; + + if (machine.isFilling()) { + int progress = machine.getFillProgressScaled(24); + drawTexturedModalRect(guiLeft + 80, guiTop + 39, 176, 74, 24 - progress, 16); + } + + } +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiSqueezer.java b/forestry_common/factory/forestry/factory/gui/GuiSqueezer.java new file mode 100755 index 000000000..2edd8a27f --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiSqueezer.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineSqueezer; + +public class GuiSqueezer extends GuiForestry { + + public GuiSqueezer(InventoryPlayer inventory, MachineSqueezer tile) { + super(Defaults.TEXTURE_PATH_GUI + "/squeezer.png", new ContainerSqueezer(inventory, tile), tile); + widgetManager.add(new TankWidget(this.widgetManager, 85, 15, 0)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineSqueezer machine = tile; + + int progress = machine.getProgressScaled(43); + drawTexturedModalRect(guiLeft + 75, guiTop + 20, 176, 60, 43 - progress, 18); + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiStill.java b/forestry_common/factory/forestry/factory/gui/GuiStill.java new file mode 100755 index 000000000..981a67728 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiStill.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.MachineStill; + +public class GuiStill extends GuiForestry { + + public GuiStill(InventoryPlayer inventory, MachineStill tile) { + super(Defaults.TEXTURE_PATH_GUI + "/still.png", new ContainerStill(inventory, tile), tile); + widgetManager.add(new TankWidget(this.widgetManager, 35, 15, 0)); + widgetManager.add(new TankWidget(this.widgetManager, 125, 15, 1)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + MachineStill boiler = tile; + + if (boiler.isWorking()) + drawTexturedModalRect(guiLeft + 81, guiTop + 57, 176, 60, 14, 14); + + int massRemaining = boiler.getDistillationProgressScaled(16); + if (massRemaining > 0) + drawTexturedModalRect(guiLeft + 84, guiTop + 17 + 17 - massRemaining, 176, 74 + 17 - massRemaining, 4, massRemaining); + + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/GuiWorktable.java b/forestry_common/factory/forestry/factory/gui/GuiWorktable.java new file mode 100755 index 000000000..2ef596c06 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/GuiWorktable.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.WidgetManager; +import forestry.core.gui.widgets.Widget; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; +import forestry.factory.gadgets.TileWorktable; + +public class GuiWorktable extends GuiForestry { + + private class MemorizedSlot extends Widget { + + int slotNumber; + + public MemorizedSlot(WidgetManager manager, int xPos, int yPos, int slot) { + super(manager, xPos, yPos); + this.slotNumber = slot; + } + + private ItemStack getOutputStack() { + return worktable.getMemory().getRecipeOutput(slotNumber); + } + + @Override + public void draw(int startX, int startY) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + RenderHelper.enableGUIStandardItemLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + ItemStack output = getOutputStack(); + if (output != null) + manager.gui.drawItemStack(output, startX + xPos, startY + yPos); + //RenderHelper.disableStandardItemLighting(); + + GL11.glDisable(GL11.GL_DEPTH_TEST); + + if (worktable.getMemory().isLocked(slotNumber)) { + manager.gui.setZLevel(110f); + Proxies.common.bindTexture(SpriteSheet.ITEMS); + manager.gui.drawTexturedModelRectFromIcon(startX + xPos, startY + yPos, TextureManager.getInstance().getDefault("slots/locked"), 16, 16); + manager.gui.setZLevel(0f); + } + + GL11.glPopAttrib(); + } + + @Override + protected String getLegacyTooltip(EntityPlayer player) { + ItemStack output = getOutputStack(); + return output != null ? output.getDisplayName() : null; + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + container.sendRecipeClick(mouseButton, slotNumber); + } + } + + private class BookSlot extends Widget { + + private final ItemStack BOOK = new ItemStack(Items.book); + + public BookSlot(WidgetManager manager, int xPos, int yPos) { + super(manager, xPos, yPos); + } + + @Override + public void draw(int startX, int startY) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + RenderHelper.enableGUIStandardItemLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + manager.gui.drawItemStack(BOOK, startX + xPos, startY + yPos); + + GL11.glPopAttrib(); + } + + @Override + protected String getLegacyTooltip(EntityPlayer player) { + return StringUtil.localize("gui.worktable.clear"); + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + container.sendRecipeClick(mouseButton, 9); + } + } + private final TileWorktable worktable; + protected ContainerWorktable container; + + public GuiWorktable(EntityPlayer player, TileWorktable tile) { + super(Defaults.TEXTURE_PATH_GUI + "/worktable.png", new ContainerWorktable(player, tile)); + + ySize = 218; + worktable = tile; + this.tile = tile; + container = (ContainerWorktable) inventorySlots; + + widgetManager.add(new BookSlot(widgetManager, 128, 38)); + + widgetManager.add(new MemorizedSlot(widgetManager, 146, 20, 0)); + widgetManager.add(new MemorizedSlot(widgetManager, 146, 38, 1)); + widgetManager.add(new MemorizedSlot(widgetManager, 146, 56, 2)); + + widgetManager.add(new MemorizedSlot(widgetManager, 128, 56, 3)); + widgetManager.add(new MemorizedSlot(widgetManager, 110, 56, 4)); + + widgetManager.add(new MemorizedSlot(widgetManager, 110, 38, 5)); + widgetManager.add(new MemorizedSlot(widgetManager, 110, 20, 6)); + widgetManager.add(new MemorizedSlot(widgetManager, 128, 20, 7)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.title")); + } +} diff --git a/forestry_common/factory/forestry/factory/gui/InventoryCraftingAuto.java b/forestry_common/factory/forestry/factory/gui/InventoryCraftingAuto.java new file mode 100755 index 000000000..7636cafeb --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/InventoryCraftingAuto.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; + +public class InventoryCraftingAuto extends InventoryCrafting { + + private ContainerCarpenter eventHandler; + public ItemStack stackList[]; + private int inventoryWidth; + + public InventoryCraftingAuto(ContainerCarpenter container, int i, int j) { + super(container, i, j); + int k = i * j; + stackList = new ItemStack[k]; + eventHandler = container; + inventoryWidth = i; + } + + @Override + public ItemStack getStackInSlot(int i) { + if (i >= getSizeInventory()) + return null; + else + return stackList[i]; + } + + @Override + public ItemStack getStackInRowAndColumn(int i, int j) { + if (i < 0 || i >= inventoryWidth) + return null; + else { + int k = i + j * inventoryWidth; + return getStackInSlot(k); + } + } + + @Override + public ItemStack decrStackSize(int i, int j) { + if (stackList[i] != null) { + if (stackList[i].stackSize <= j) { + ItemStack itemstack = stackList[i]; + stackList[i] = null; + eventHandler.onCraftMatrixChanged(this, i); + return itemstack; + } + ItemStack itemstack1 = stackList[i].splitStack(j); + if (stackList[i].stackSize == 0) + stackList[i] = null; + eventHandler.onCraftMatrixChanged(this, i); + return itemstack1; + } else + return null; + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + stackList[i] = itemstack; + eventHandler.onCraftMatrixChanged(this, i); + } + + @Override + public String getInventoryName() { + return "Crafting"; + } + + @Override + public int getSizeInventory() { + return stackList.length; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public void markDirty() { + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + +} diff --git a/forestry_common/factory/forestry/factory/gui/SlotCraftMatrix.java b/forestry_common/factory/forestry/factory/gui/SlotCraftMatrix.java new file mode 100755 index 000000000..75f75b049 --- /dev/null +++ b/forestry_common/factory/forestry/factory/gui/SlotCraftMatrix.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.gui; + +import net.minecraft.inventory.IInventory; + +import forestry.core.gui.slots.SlotForestry; +import forestry.core.interfaces.IContainerCrafting; + +/** + * Informs the passed container of slot changes. Contains a dummy itemstack. + */ +public class SlotCraftMatrix extends SlotForestry { + + private IContainerCrafting eventHandler; + private int slot; + + public SlotCraftMatrix(IContainerCrafting container, IInventory iinventory, int i, int j, int k) { + super(iinventory, i, j, k); + setPhantom(); + this.eventHandler = container; + this.slot = i; + stackLimit = 1; + } + + @Override + public void onSlotChanged() { + super.onSlotChanged(); + eventHandler.onCraftMatrixChanged(inventory, slot); + } + +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideBottler.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideBottler.java new file mode 100755 index 000000000..a3a06c0bf --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideBottler.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import net.minecraft.item.ItemStack; + +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.LiquidSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.Slot; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.factory.gadgets.MachineBottler; + +public class CraftGuideBottler implements RecipeProvider { + + private final Slot[] slots = new Slot[4]; + + public CraftGuideBottler() { + slots[0] = new ItemSlot(12, 12, 16, 16).drawOwnBackground(); + slots[1] = new LiquidSlot(12, 30); + slots[2] = new ItemSlot(50, 21, 16, 16).setSlotType(SlotType.OUTPUT_SLOT).drawOwnBackground(); + slots[3] = new ItemSlot(31, 21, 16, 16).setSlotType(SlotType.MACHINE_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + if (ForestryBlock.factoryTESR == null) + return; + + ItemStack machine = new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_BOTTLER_META); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine); + + for (MachineBottler.Recipe recipe : MachineBottler.RecipeManager.recipes) { + Object[] array = new Object[4]; + + array[0] = recipe.can; + array[1] = recipe.input; + array[2] = recipe.bottled; + array[3] = machine; + generator.addRecipe(template, array); + } + } +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideCarpenter.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideCarpenter.java new file mode 100755 index 000000000..1d3645fef --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideCarpenter.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import net.minecraft.item.ItemStack; + +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.LiquidSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.Slot; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.utils.RecipeUtil; +import forestry.factory.gadgets.MachineCarpenter; + +public class CraftGuideCarpenter implements RecipeProvider { + + private final Slot[] slots = new Slot[12]; + + public CraftGuideCarpenter() { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + slots[i + j * 3] = new ItemSlot(i * 18 + 3, j * 18 + 3, 16, 16).drawOwnBackground(); + slots[9] = new ItemSlot(59, 21, 16, 16, true).setSlotType(SlotType.OUTPUT_SLOT).drawOwnBackground(); + slots[10] = new LiquidSlot(59, 39); + slots[11] = new ItemSlot(59, 3, 16, 16).setSlotType(SlotType.MACHINE_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + if (ForestryBlock.factoryTESR == null) + return; + + ItemStack machine = new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_CARPENTER_META); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine); + + for (MachineCarpenter.Recipe recipe : MachineCarpenter.RecipeManager.recipes) { + Object[] array = new Object[12]; + + Object[] flattened = RecipeUtil.getCraftingRecipeAsArray(recipe.asIRecipe()); + if (flattened == null) + flattened = generator.getCraftingRecipe(recipe.asIRecipe()); + if (flattened == null) + continue; + System.arraycopy(flattened, 0, array, 0, flattened.length); + if (recipe.getLiquid() != null) + array[10] = recipe.getLiquid(); + array[11] = machine; + generator.addRecipe(template, array); + } + } + +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideCentrifuge.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideCentrifuge.java new file mode 100755 index 000000000..dd0ab8910 --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideCentrifuge.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import java.util.Map.Entry; + +import net.minecraft.item.ItemStack; + +import uristqwerty.CraftGuide.api.ChanceSlot; +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.Slot; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.factory.gadgets.MachineCentrifuge; + +public class CraftGuideCentrifuge implements RecipeProvider { + + private final Slot[] slots = new Slot[11]; + + public CraftGuideCentrifuge() { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + slots[i + j * 3] = new ChanceSlot(i * 18 + 24, j * 18 + 3, 16, 16).setRatio(100).setSlotType(SlotType.OUTPUT_SLOT).drawOwnBackground(); + slots[9] = new ItemSlot(4, 31, 16, 16, true).drawOwnBackground(); + slots[10] = new ItemSlot(4, 11, 16, 16).setSlotType(SlotType.MACHINE_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + if (ForestryBlock.factoryTESR == null) + return; + + ItemStack machine = new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_CENTRIFUGE_META); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine); + + for (MachineCentrifuge.Recipe recipe : MachineCentrifuge.RecipeManager.recipes) { + Object[] array = new Object[11]; + @SuppressWarnings("unchecked") + Entry[] entries = recipe.products.entrySet().toArray(new Entry[0]); + + for (int i = 0; i < Math.min(entries.length, 9); i++) { + array[i] = entries[i].getValue() > 0 ? new Object[] { entries[i].getKey(), entries[i].getValue() } : null; + } + + array[9] = recipe.resource; + array[10] = machine; + + generator.addRecipe(template, array); + } + } +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideCustomRecipes.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideCustomRecipes.java new file mode 100755 index 000000000..b97a8d672 --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideCustomRecipes.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; + +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.core.interfaces.IDescriptiveRecipe; +import forestry.core.utils.RecipeUtil; + +public class CraftGuideCustomRecipes implements RecipeProvider { + + private final ItemSlot[] slots = new ItemSlot[10]; + + public CraftGuideCustomRecipes() { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + slots[i + j * 3] = new ItemSlot(i * 18 + 3, j * 18 + 3, 16, 16); + slots[9] = new ItemSlot(59, 21, 16, 16, true).setSlotType(SlotType.OUTPUT_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + ItemStack machine = new ItemStack(Blocks.crafting_table); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine, "/gui/CraftGuideRecipe.png", 1, 1, 82, 1); + + for (Object rec : CraftingManager.getInstance().getRecipeList()) { + if (!(rec instanceof IDescriptiveRecipe)) + continue; + + Object[] array = new Object[10]; + + Object[] flattened = RecipeUtil.getCraftingRecipeAsArray(rec); + if (flattened == null) + continue; + System.arraycopy(flattened, 0, array, 0, flattened.length); + generator.addRecipe(template, array); + + } + } + +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideFabricator.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideFabricator.java new file mode 100755 index 000000000..514a8f3b5 --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideFabricator.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import net.minecraft.item.ItemStack; + +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.LiquidSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.Slot; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.utils.RecipeUtil; +import forestry.factory.gadgets.MachineFabricator; + +public class CraftGuideFabricator implements RecipeProvider { + + private final Slot[] slots = new Slot[12]; + + public CraftGuideFabricator() { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + slots[i + j * 3] = new ItemSlot(i * 18 + 3, j * 18 + 3, 16, 16).drawOwnBackground(); + slots[9] = new ItemSlot(59, 21, 16, 16, true).setSlotType(SlotType.OUTPUT_SLOT).drawOwnBackground(); + slots[10] = new LiquidSlot(59, 39); + slots[11] = new ItemSlot(59, 3, 16, 16).setSlotType(SlotType.MACHINE_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + if (ForestryBlock.factoryTESR == null) + return; + + ItemStack machine = new ItemStack(ForestryBlock.factoryPlain, 1, Defaults.DEFINITION_FABRICATOR_META); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine); + + for (MachineFabricator.Recipe recipe : MachineFabricator.RecipeManager.recipes) { + Object[] array = new Object[12]; + + Object[] flattened = RecipeUtil.getCraftingRecipeAsArray(recipe.asIRecipe()); + if (flattened == null) + flattened = generator.getCraftingRecipe(recipe.asIRecipe()); + if (flattened == null) + continue; + System.arraycopy(flattened, 0, array, 0, flattened.length); + if (recipe.getLiquid() != null) + array[10] = recipe.getLiquid(); + array[11] = machine; + generator.addRecipe(template, array); + } + } + +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideFermenter.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideFermenter.java new file mode 100755 index 000000000..6ff3d293c --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideFermenter.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.fluids.FluidStack; + +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.LiquidSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.Slot; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.api.fuels.FuelManager; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.factory.gadgets.MachineFermenter; + +public class CraftGuideFermenter implements RecipeProvider { + + private final Slot[] slots = new Slot[5]; + + public CraftGuideFermenter() { + slots[0] = new ItemSlot(3, 12, 16, 16, true); + slots[1] = new ItemSlot(3, 30, 16, 16, true); + slots[2] = new LiquidSlot(21, 21); + slots[3] = new LiquidSlot(59, 21).setSlotType(SlotType.OUTPUT_SLOT); + slots[4] = new ItemSlot(40, 21, 16, 16).setSlotType(SlotType.MACHINE_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + if (ForestryBlock.factoryTESR == null) + return; + + ItemStack machine = new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_FERMENTER_META); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine); + List fuels = new ArrayList(FuelManager.fermenterFuel.keySet()); + + for (MachineFermenter.Recipe recipe : MachineFermenter.RecipeManager.recipes) { + Object[] array = new Object[5]; + + array[0] = recipe.resource; + array[1] = fuels; + array[2] = recipe.liquid; + FluidStack output = recipe.output.copy(); + output.amount *= recipe.fermentationValue; + output.amount *= recipe.modifier; + array[3] = output; + array[4] = machine; + generator.addRecipe(template, array); + } + } +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideIntegration.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideIntegration.java new file mode 100755 index 000000000..c95a42be1 --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideIntegration.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import java.lang.reflect.Method; + +import forestry.core.proxy.Proxies; + +public class CraftGuideIntegration { + + public static void register() { + registerRecipeProviders(); + } + + private static void registerRecipeProviders() { + + Proxies.log.info("Registering CraftGuide integration."); + try { + Class c = Class.forName("uristqwerty.CraftGuide.ReflectionAPI"); + Method m = c.getMethod("registerAPIObject", Object.class); + + Proxies.log.fine("Adding crafting handler custom recipes."); + m.invoke(null, new CraftGuideCustomRecipes()); + Proxies.log.fine("Adding crafting handler for the carpenter."); + m.invoke(null, new CraftGuideCarpenter()); + Proxies.log.fine("Adding crafting handler for the thermionic fabricator."); + m.invoke(null, new CraftGuideFabricator()); + Proxies.log.fine("Adding crafting handler for the centrifuge."); + m.invoke(null, new CraftGuideCentrifuge()); + Proxies.log.fine("Adding crafting handler for the squeezer."); + m.invoke(null, new CraftGuideSqueezer()); + Proxies.log.fine("Adding crafting handler for the fermenter."); + m.invoke(null, new CraftGuideFermenter()); + Proxies.log.fine("Adding crafting handler for the still."); + m.invoke(null, new CraftGuideStill()); + Proxies.log.fine("Adding crafting handler for the bottler."); + m.invoke(null, new CraftGuideBottler()); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideSqueezer.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideSqueezer.java new file mode 100755 index 000000000..9381bace9 --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideSqueezer.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import net.minecraft.item.ItemStack; + +import uristqwerty.CraftGuide.api.ChanceSlot; +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.LiquidSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.Slot; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.factory.gadgets.MachineSqueezer; + +public class CraftGuideSqueezer implements RecipeProvider { + + private final Slot[] slots = new Slot[12]; + + public CraftGuideSqueezer() { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + slots[i + j * 3] = new ItemSlot(i * 18 + 3, j * 18 + 3, 16, 16).drawOwnBackground(); + slots[9] = new ChanceSlot(59, 39, 16, 16, true).setRatio(100).setSlotType(SlotType.OUTPUT_SLOT).drawOwnBackground(); + slots[10] = new LiquidSlot(59, 21).setSlotType(SlotType.OUTPUT_SLOT); + slots[11] = new ItemSlot(59, 3, 16, 16).setSlotType(SlotType.MACHINE_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + if (ForestryBlock.factoryTESR == null) + return; + + ItemStack machine = new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_SQUEEZER_META); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine); + + for (MachineSqueezer.Recipe recipe : MachineSqueezer.RecipeManager.recipes) { + Object[] array = new Object[12]; + + System.arraycopy(recipe.resources, 0, array, 0, recipe.resources.length); + if (recipe.remnants != null) + array[9] = recipe.chance > 0 ? new Object[] { recipe.remnants.copy(), recipe.chance } : null; + if (recipe.liquid != null) + array[10] = recipe.liquid; + array[11] = machine; + generator.addRecipe(template, array); + } + } + +} diff --git a/forestry_common/factory/forestry/factory/recipes/CraftGuideStill.java b/forestry_common/factory/forestry/factory/recipes/CraftGuideStill.java new file mode 100755 index 000000000..985e9136e --- /dev/null +++ b/forestry_common/factory/forestry/factory/recipes/CraftGuideStill.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.factory.recipes; + +import net.minecraft.item.ItemStack; + +import uristqwerty.CraftGuide.api.ItemSlot; +import uristqwerty.CraftGuide.api.LiquidSlot; +import uristqwerty.CraftGuide.api.RecipeGenerator; +import uristqwerty.CraftGuide.api.RecipeProvider; +import uristqwerty.CraftGuide.api.RecipeTemplate; +import uristqwerty.CraftGuide.api.Slot; +import uristqwerty.CraftGuide.api.SlotType; + +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.factory.gadgets.MachineStill; + +public class CraftGuideStill implements RecipeProvider { + + private final Slot[] slots = new Slot[3]; + + public CraftGuideStill() { + slots[0] = new LiquidSlot(12, 21); + slots[1] = new LiquidSlot(50, 21).setSlotType(SlotType.OUTPUT_SLOT); + slots[2] = new ItemSlot(31, 21, 16, 16).setSlotType(SlotType.MACHINE_SLOT); + } + + @Override + public void generateRecipes(RecipeGenerator generator) { + + if (ForestryBlock.factoryTESR == null) + return; + + ItemStack machine = new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_STILL_META); + RecipeTemplate template = generator.createRecipeTemplate(slots, machine); + + for (MachineStill.Recipe recipe : MachineStill.RecipeManager.recipes) { + Object[] array = new Object[3]; + + array[0] = recipe.input; + array[1] = recipe.output; + array[2] = machine; + generator.addRecipe(template, array); + } + } +} diff --git a/forestry_common/factory/forestry/plugins/PluginFactory.java b/forestry_common/factory/forestry/plugins/PluginFactory.java new file mode 100755 index 000000000..003ff5975 --- /dev/null +++ b/forestry_common/factory/forestry/plugins/PluginFactory.java @@ -0,0 +1,475 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.ArrayList; + +import net.minecraft.block.material.Material; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.core.PluginInfo; +import forestry.api.recipes.ICraftingProvider; +import forestry.api.recipes.RecipeManagers; +import forestry.core.GameMode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.BlockBase; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.gadgets.MachineNBTDefinition; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.items.ItemForestryBlock; +import forestry.core.items.ItemNBTTile; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.RecipeUtil; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.factory.GuiHandlerFactory; +import forestry.factory.gadgets.MachineBottler; +import forestry.factory.gadgets.MachineCarpenter; +import forestry.factory.gadgets.MachineCarpenter.RecipeManager; +import forestry.factory.gadgets.MachineCentrifuge; +import forestry.factory.gadgets.MachineFabricator; +import forestry.factory.gadgets.MachineFermenter; +import forestry.factory.gadgets.MachineMoistener; +import forestry.factory.gadgets.MachineRaintank; +import forestry.factory.gadgets.MachineSqueezer; +import forestry.factory.gadgets.MachineStill; +import forestry.factory.gadgets.MillRainmaker; +import forestry.factory.gadgets.TileWorktable; +import forestry.factory.recipes.CraftGuideIntegration; + +@PluginInfo(pluginID = "Factory", name = "Factory", author = "SirSengir", url = Defaults.URL, description = "Adds a wide variety of machines to craft, produce and process products.") +public class PluginFactory extends NativePlugin { + + public static MachineDefinition definitionBottler; + public static MachineDefinition definitionCarpenter; + public static MachineDefinition definitionCentrifuge; + public static MachineDefinition definitionFermenter; + public static MachineDefinition definitionMoistener; + public static MachineDefinition definitionSqueezer; + public static MachineDefinition definitionStill; + public static MachineDefinition definitionRainmaker; + public static MachineDefinition definitionFabricator; + public static MachineDefinition definitionRaintank; + public static MachineDefinition definitionWorktable; + + @Override + public boolean isAvailable() { + return !Config.disableFactory; + } + + @Override + public void preInit() { + super.preInit(); + + RecipeManagers.craftingProviders = new ArrayList(); + // Init bottler manager + RecipeManagers.craftingProviders.add(RecipeManagers.bottlerManager = new MachineBottler.RecipeManager()); + // Init carpenter manager + RecipeManagers.craftingProviders.add(RecipeManagers.carpenterManager = new MachineCarpenter.RecipeManager()); + // Init centrifuge manager + RecipeManagers.craftingProviders.add(RecipeManagers.centrifugeManager = new MachineCentrifuge.RecipeManager()); + // Init fabricator manager + RecipeManagers.craftingProviders.add(RecipeManagers.fabricatorManager = new MachineFabricator.RecipeManager()); + // Init fermenter manager + RecipeManagers.craftingProviders.add(RecipeManagers.fermenterManager = new MachineFermenter.RecipeManager()); + // Init moistener manager + RecipeManagers.craftingProviders.add(RecipeManagers.moistenerManager = new MachineMoistener.RecipeManager()); + // Init squeezer manager + RecipeManagers.craftingProviders.add(RecipeManagers.squeezerManager = new MachineSqueezer.RecipeManager()); + // Init still manager + RecipeManagers.craftingProviders.add(RecipeManagers.stillManager = new MachineStill.RecipeManager()); + + ForestryBlock.factoryTESR = new BlockBase(Material.iron, true); + ForestryBlock.factoryTESR.setBlockName("for.factory"); + Proxies.common.registerBlock(ForestryBlock.factoryTESR, ItemForestryBlock.class); + + definitionBottler = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_BOTTLER_META, "forestry.Bottler", MachineBottler.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/bottler_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_BOTTLER_META), + "X#X", + "#Y#", + "X#X", + '#', Blocks.glass, + 'X', ForestryItem.canEmpty, + 'Y', ForestryItem.sturdyCasing))); + + definitionCarpenter = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_CARPENTER_META, "forestry.Carpenter", MachineCarpenter.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/carpenter_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_CARPENTER_META), + "X#X", + "XYX", + "X#X", + '#', Blocks.glass, + 'X', "ingotBronze", + 'Y', ForestryItem.sturdyCasing))); + + definitionCentrifuge = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_CENTRIFUGE_META, "forestry.Centrifuge", MachineCentrifuge.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/centrifuge_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_CENTRIFUGE_META), + "X#X", + "XYX", + "X#X", + '#', Blocks.glass, + 'X', "ingotCopper", + 'Y', ForestryItem.sturdyCasing.getItemStack()))); + + definitionFermenter = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_FERMENTER_META, "forestry.Fermenter", MachineFermenter.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/fermenter_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_FERMENTER_META), + "X#X", + "#Y#", + "X#X", + '#', Blocks.glass, + 'X', "gearBronze", + 'Y', ForestryItem.sturdyCasing))); + + definitionMoistener = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_MOISTENER_META, "forestry.Moistener", MachineMoistener.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/moistener_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_MOISTENER_META), + "X#X", + "#Y#", + "X#X", + '#', Blocks.glass, + 'X', "gearCopper", + 'Y', ForestryItem.sturdyCasing))); + + definitionSqueezer = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_SQUEEZER_META, "forestry.Squeezer", MachineSqueezer.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/squeezer_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_SQUEEZER_META), + "X#X", + "XYX", + "X#X", + '#', Blocks.glass, + 'X', "ingotTin", + 'Y', ForestryItem.sturdyCasing.getItemStack()))); + + definitionStill = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_STILL_META, "forestry.Still", MachineStill.class, + Proxies.render.getRenderDefaultMachine(Defaults.TEXTURE_PATH_BLOCKS + "/still_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_STILL_META), + "X#X", + "#Y#", + "X#X", + '#', Blocks.glass, + 'X', Items.redstone, + 'Y', ForestryItem.sturdyCasing))); + + definitionRainmaker = ForestryBlock.factoryTESR.addDefinition(new MachineDefinition(Defaults.DEFINITION_RAINMAKER_META, "forestry.Rainmaker", MillRainmaker.class, + Proxies.render.getRenderMill(Defaults.TEXTURE_PATH_BLOCKS + "/rainmaker_"), ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryTESR, 1, Defaults.DEFINITION_RAINMAKER_META), + "X#X", + "#Y#", + "X#X", + '#', Blocks.glass, + 'X', "gearTin", + 'Y', ForestryItem.hardenedCasing))); + + ForestryBlock.factoryPlain = new BlockBase(Material.iron); + ForestryBlock.factoryPlain.setBlockName("for.factory2"); + Proxies.common.registerBlock(ForestryBlock.factoryPlain, ItemNBTTile.class); + + definitionFabricator = ForestryBlock.factoryPlain.addDefinition(new MachineDefinition(Defaults.DEFINITION_FABRICATOR_META, "forestry.Fabricator", MachineFabricator.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryPlain, + 1, Defaults.DEFINITION_FABRICATOR_META), + "X#X", + "#Y#", + "XZX", + '#', Blocks.glass, + 'X', Items.gold_ingot, + 'Y', ForestryItem.sturdyCasing, + 'Z', Blocks.chest)).setFaces(0, 1, 2, 3, 4, 4)); + + definitionRaintank = ForestryBlock.factoryPlain.addDefinition(new MachineDefinition(Defaults.DEFINITION_RAINTANK_META, "forestry.Raintank", MachineRaintank.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryPlain, 1, Defaults.DEFINITION_RAINTANK_META), + "X#X", + "XYX", + "X#X", + '#', Blocks.glass, + 'X', Items.iron_ingot, + 'Y', ForestryItem.sturdyCasing)) + .setFaces(0, 1, 0, 0, 0, 0)); + + definitionWorktable = ForestryBlock.factoryPlain.addDefinition(new MachineNBTDefinition(Defaults.DEFINITION_WORKTABLE_META, "forestry.Worktable", TileWorktable.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.factoryPlain, 1, Defaults.DEFINITION_WORKTABLE_META), + "B", + "W", + "C", + 'B', Items.book, + 'W', Blocks.crafting_table, + 'C', Blocks.chest)).setFaces(0, 1, 2, 3, 4, 4)); + } + + @Override + public void doInit() { + super.doInit(); + + definitionBottler.register(); + definitionCarpenter.register(); + definitionCentrifuge.register(); + definitionFabricator.register(); + definitionFermenter.register(); + definitionMoistener.register(); + definitionRaintank.register(); + definitionSqueezer.register(); + definitionStill.register(); + definitionRainmaker.register(); + definitionWorktable.register(); + + } + + @Override + public void postInit() { + super.postInit(); + + if (Proxies.common.isModLoaded("craftguide")) + CraftGuideIntegration.register(); + else + Proxies.log.info("Skipping CraftGuide integration."); + } + + @Override + protected void registerItems() { + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerRecipes() { + + // / FABRICATOR + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 0), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', "ingotCopper" }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 1), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', "ingotTin" }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 2), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', "ingotBronze" }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 3), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', Items.iron_ingot }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 4), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', Items.gold_ingot }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 5), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', Items.diamond }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 6), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', Blocks.obsidian }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 7), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', Items.blaze_powder }); + if (PluginIC2.rubber != null) + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 8), + new Object[] { " X ", "#X#", "XXX", '#', Items.redstone, 'X', PluginIC2.rubber }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 9), new Object[] { + " X ", "#X#", "XXX", '#', Items.redstone, 'X', Items.emerald }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 10), + new Object[] { " X ", "#X#", "XXX", '#', Items.redstone, 'X', "gemApatite" }); + RecipeManagers.fabricatorManager.addRecipe(null, LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 500), ForestryItem.tubes.getItemStack(4, 11), + new Object[] { " X ", "#X#", "XXX", '#', Items.redstone, 'X', new ItemStack(Items.dye, 1, 4) }); + + String[] dyes = { "dyeBlack", "dyeRed", "dyeGreen", "dyeBrown", "dyeBlue", "dyePurple", "dyeCyan", "dyeLightGray", "dyeGray", "dyePink", "dyeLime", + "dyeYellow", "dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite" }; + + if (ForestryItem.propolis != null) + for (int i = 0; i < 16; i++) { + RecipeManagers.fabricatorManager.addRecipe(ForestryItem.waxCast.getItemStack(1, Defaults.WILDCARD), LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, + Defaults.BUCKET_VOLUME), new ItemStack(ForestryBlock.glass, 1, 15 - i), new Object[] { "#", "X", '#', dyes[i], + 'X', ForestryItem.propolis.getItemStack(1, Defaults.WILDCARD) }); + } + + // / SQUEEZER + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { new ItemStack(Items.apple) }, LiquidHelper.getLiquid(Defaults.LIQUID_JUICE, GameMode.getGameMode().getIntegerSetting("squeezer.liquid.apple")), + ForestryItem.mulch.getItemStack(), GameMode.getGameMode().getIntegerSetting("squeezer.mulch.apple")); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { new ItemStack(Items.wheat_seeds) }, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, GameMode + .getGameMode().getIntegerSetting("squeezer.liquid.seed"))); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { new ItemStack(Items.pumpkin_seeds) }, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, GameMode + .getGameMode().getIntegerSetting("squeezer.liquid.seed"))); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { new ItemStack(Items.melon_seeds) }, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, GameMode + .getGameMode().getIntegerSetting("squeezer.liquid.seed"))); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { ForestryItem.phosphor.getItemStack(2), new ItemStack(Blocks.cobblestone) }, + LiquidHelper.getLiquid(Defaults.LIQUID_LAVA, 1600)); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { new ItemStack(Blocks.cactus) }, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 500)); + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { new ItemStack(Items.snowball), ForestryItem.craftingMaterial.getItemStack(4, 5) }, + LiquidHelper.getLiquid(Defaults.LIQUID_ICE, 4000)); + + // STILL + RecipeManagers.stillManager.addRecipe(Defaults.STILL_DESTILLATION_DURATION, LiquidHelper.getLiquid(Defaults.LIQUID_BIOMASS, + Defaults.STILL_DESTILLATION_INPUT), LiquidHelper.getLiquid(Defaults.LIQUID_ETHANOL, Defaults.STILL_DESTILLATION_OUTPUT)); + + // MOISTENER + RecipeManagers.moistenerManager.addRecipe(new ItemStack(Items.wheat_seeds), new ItemStack(Blocks.mycelium), 5000); + RecipeManagers.moistenerManager.addRecipe(new ItemStack(Blocks.cobblestone), new ItemStack(Blocks.mossy_cobblestone), 20000); + RecipeManagers.moistenerManager.addRecipe(new ItemStack(Blocks.stonebrick), new ItemStack(Blocks.stonebrick, 1, 1), 20000); + + // FERMENTER + RecipeUtil.injectLeveledRecipe(new ItemStack(Blocks.sapling, 1, 0), GameMode.getGameMode().getIntegerSetting("fermenter.yield.sapling"), Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(new ItemStack(Blocks.sapling, 1, 1), GameMode.getGameMode().getIntegerSetting("fermenter.yield.sapling"), Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(new ItemStack(Blocks.sapling, 1, 2), GameMode.getGameMode().getIntegerSetting("fermenter.yield.sapling"), Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(new ItemStack(Blocks.sapling, 1, 3), GameMode.getGameMode().getIntegerSetting("fermenter.yield.sapling"), Defaults.LIQUID_BIOMASS); + + RecipeUtil.injectLeveledRecipe(new ItemStack(Blocks.cactus), GameMode.getGameMode().getIntegerSetting("fermenter.yield.cactus"), Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(new ItemStack(Items.wheat), GameMode.getGameMode().getIntegerSetting("fermenter.yield.wheat"), Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(new ItemStack(Items.reeds), GameMode.getGameMode().getIntegerSetting("fermenter.yield.cane"), Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(new ItemStack(Blocks.brown_mushroom), GameMode.getGameMode().getIntegerSetting("fermenter.yield.mushroom"), Defaults.LIQUID_BIOMASS); + RecipeUtil.injectLeveledRecipe(new ItemStack(Blocks.red_mushroom), GameMode.getGameMode().getIntegerSetting("fermenter.yield.mushroom"), Defaults.LIQUID_BIOMASS); + + // FABRICATOR + RecipeManagers.fabricatorManager.addSmelting(new ItemStack(Blocks.glass), LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 1000), 1000); + RecipeManagers.fabricatorManager.addSmelting(new ItemStack(Blocks.glass_pane), LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 375), 1000); + RecipeManagers.fabricatorManager.addSmelting(new ItemStack(Blocks.sand), LiquidHelper.getLiquid(Defaults.LIQUID_GLASS, 1000), 3000); + + // / CARPENTER + RecipeManagers.carpenterManager.addRecipe(50, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, 250), null, ForestryItem.impregnatedCasing.getItemStack(), + new Object[] { "###", "# #", "###", '#', "logWood" }); + RecipeManagers.carpenterManager.addRecipe(50, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, 500), null, new ItemStack(ForestryBlock.core, 1, Defaults.DEFINITION_ESCRITOIRE_META), + new Object[] { "# ", "###", "# #", '#', "plankWood" }); + + // RESOURCES + RecipeManagers.carpenterManager.addRecipe(10, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, 100), null, ForestryItem.stickImpregnated.getItemStack(2), + new Object[] { "#", "#", '#', "logWood" }); + RecipeManagers.carpenterManager.addRecipe(5, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 250), null, ForestryItem.woodPulp.getItemStack(4), + new Object[] { "#", '#', "logWood" }); + RecipeManagers.carpenterManager.addRecipe(5, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 250), null, new ItemStack(Items.paper, 1), new Object[] { "#", + "#", '#', "pulpWood" }); + RecipeManagers.carpenterManager.addRecipe(5, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, new ItemStack(ForestryBlock.soil, 9, 0), + new Object[] { "###", "#X#", "###", '#', Blocks.dirt, 'X', ForestryItem.mulch }); + RecipeManagers.carpenterManager.addRecipe(5, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, new ItemStack(ForestryBlock.soil, 8, 1), + new Object[] { "#X#", "XYX", "#X#", '#', Blocks.dirt, 'X', Blocks.sand, 'Y', + ForestryItem.mulch }); + RecipeManagers.carpenterManager.addRecipe(75, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 5000), null, ForestryItem.hardenedCasing.getItemStack(), + new Object[] { "# #", " Y ", "# #", '#', Items.diamond, 'Y', ForestryItem.sturdyCasing }); + + // / CHIPSETS + RecipeManagers.carpenterManager.addRecipe(20, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.circuitboards.getItemStack(1, 0), + new Object[] { "R R", "R#R", "R R", '#', "ingotTin", 'R', Items.redstone }); + RecipeManagers.carpenterManager.addRecipe(40, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.circuitboards.getItemStack(1, 1), + new Object[] { "R#R", "R#R", "R#R", '#', "ingotBronze", 'R', Items.redstone }); + RecipeManagers.carpenterManager.addRecipe(80, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.circuitboards.getItemStack(1, 2), + new Object[] { "R#R", "R#R", "R#R", '#', Items.iron_ingot, 'R', Items.redstone }); + RecipeManagers.carpenterManager.addRecipe(80, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.circuitboards.getItemStack(1, 3), + new Object[] { "R#R", "R#R", "R#R", '#', Items.gold_ingot, 'R', Items.redstone }); + RecipeManagers.carpenterManager.addRecipe(40, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.solderingIron.getItemStack(), + new Object[] { " # ", "# #", " B", '#', Items.iron_ingot, 'B', "ingotBronze" }); + // ForestryCore.oreHandler.registerCarpenterRecipe(solderingIron); + + // RAIN SUBSTRATES + RecipeManagers.carpenterManager.addRecipe(5, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.iodineCharge.getItemStack(), + new Object[] { "Z#Z", "#Y#", "X#X", '#', ForestryItem.pollen, 'X', Items.gunpowder, + 'Y', ForestryItem.canEmpty, 'Z', ForestryItem.honeyDrop }); + // ForestryCore.oreHandler.registerCarpenterRecipe(iodineCapsule); + RecipeManagers.carpenterManager.addRecipe( + 5, + LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), + null, + ForestryItem.craftingMaterial.getItemStack(1, 4), + new Object[] { "Z#Z", "#Y#", "X#X", '#', ForestryItem.royalJelly, 'X', Items.gunpowder, + 'Y', ForestryItem.canEmpty, 'Z', ForestryItem.honeydew }); + // ForestryCore.oreHandler.registerCarpenterRecipe(dissipationCharge); + + // Ender pearl + RecipeManagers.carpenterManager.addRecipe(100, null, new ItemStack(Items.ender_pearl, 1), new Object[] { " # ", "###", " # ", '#', + ForestryItem.craftingMaterial.getItemStack(1, 1) }); + // Woven Silk + RecipeManagers.carpenterManager.addRecipe(10, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 500), null, ForestryItem.craftingMaterial.getItemStack(1, 3), + new Object[] { "###", "###", "###", '#', ForestryItem.craftingMaterial.getItemStack(1, 2) }); + + // Boxes + RecipeManagers.carpenterManager.addRecipe(5, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.carton.getItemStack(2), + new Object[] { " # ", "# #", " # ", '#', "pulpWood" }); + RecipeManagers.carpenterManager.addRecipe(20, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.crate.getItemStack(24), + new Object[] { " # ", "# #", " # ", '#', "logWood" }); + + // Assembly Kits + RecipeManagers.carpenterManager.addRecipe(20, null, ForestryItem.carton.getItemStack(), ForestryItem.kitPickaxe.getItemStack(), new Object[] { + "###", + " X ", + " X ", + '#', "ingotBronze", + 'X', "stickWood" }); + + RecipeManagers.carpenterManager.addRecipe(20, null, ForestryItem.carton.getItemStack(), ForestryItem.kitShovel.getItemStack(), + new Object[] { " # ", " X ", " X ", '#', "ingotBronze", 'X', "stickWood" }); + + // Reclamation + RecipeManagers.carpenterManager.addRecipe(null, ForestryItem.ingotBronze.getItemStack(2, ForestryItem.ingotBronze.item().getMaxDamage()), + new Object[] { "#", '#', ForestryItem.brokenBronzePickaxe }); + RecipeManagers.carpenterManager.addRecipe(null, ForestryItem.ingotBronze.getItemStack(), new Object[] { "#", '#', ForestryItem.brokenBronzeShovel }); + + // Crating and uncrating condensed + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedWood.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedCobblestone.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedDirt.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedStone.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedBrick.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedCacti.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedSand.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedObsidian.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedNetherrack.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedSoulsand.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedSandstone.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedBogearth.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedHumus.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedNetherbrick.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedPeat.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedApatite.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedFertilizer.getItemStack()); + ((RecipeManager) RecipeManagers.carpenterManager).addCrating("ingotTin", ForestryItem.ingotTin.getItemStack(), ForestryItem.cratedTin.getItemStack()); + ((RecipeManager) RecipeManagers.carpenterManager).addCrating("ingotCopper", ForestryItem.ingotCopper.getItemStack(), ForestryItem.cratedCopper.getItemStack()); + ((RecipeManager) RecipeManagers.carpenterManager).addCrating("ingotBronze", ForestryItem.ingotBronze.getItemStack(), ForestryItem.cratedBronze.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedWheat.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedMycelium.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedMulch.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedCookies.getItemStack()); + + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedHoneycombs.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedBeeswax.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedPollen.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedPropolis.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedHoneydew.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedRoyalJelly.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedCocoaComb.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedRedstone.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedLapis.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedReeds.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedClay.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedGlowstone.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedApples.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedNetherwart.getItemStack()); + + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedSimmeringCombs.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedStringyCombs.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedFrozenCombs.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedDrippingCombs.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedRefractoryWax.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedPhosphor.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedAsh.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedCharcoal.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedGravel.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedCoal.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedSeeds.getItemStack()); + RecipeManagers.carpenterManager.addCrating(ForestryItem.cratedSaplings.getItemStack()); + + } + + @Override + protected void registerCrates() { + // TODO Auto-generated method stub + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerFactory(); + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } +} diff --git a/forestry_common/farming/forestry/farming/EventHandlerFarming.java b/forestry_common/farming/forestry/farming/EventHandlerFarming.java new file mode 100755 index 000000000..3b0237849 --- /dev/null +++ b/forestry_common/farming/forestry/farming/EventHandlerFarming.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming; + +import net.minecraft.block.Block; + +import cpw.mods.fml.common.eventhandler.Event.Result; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; + +import net.minecraftforge.event.entity.player.BonemealEvent; + +import forestry.core.config.ForestryBlock; +import forestry.core.proxy.Proxies; +import forestry.farming.gadgets.BlockMushroom; + +public class EventHandlerFarming { + + @SubscribeEvent + public void handleBonemeal(BonemealEvent event) { + + if (!Proxies.common.isSimulating(event.world)) + return; + + Block block = event.world.getBlock(event.x, event.y, event.z); + if (block != ForestryBlock.mushroom) + return; + + ((BlockMushroom) ForestryBlock.mushroom).func_149878_d(event.world, event.x, event.y, event.z, event.world.rand); + event.setResult(Result.ALLOW); + } +} diff --git a/forestry_common/farming/forestry/farming/FarmHelper.java b/forestry_common/farming/forestry/farming/FarmHelper.java new file mode 100755 index 000000000..c90fd712b --- /dev/null +++ b/forestry_common/farming/forestry/farming/FarmHelper.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming; + +import forestry.api.core.IStructureLogic; +import forestry.api.farming.IFarmComponent; +import forestry.api.farming.IFarmInterface; +import forestry.farming.gadgets.StructureLogicFarm; + +public class FarmHelper implements IFarmInterface { + + @Override + public IStructureLogic createFarmStructureLogic(IFarmComponent structure) { + return new StructureLogicFarm(structure); + } + +} diff --git a/forestry_common/farming/forestry/farming/FarmTarget.java b/forestry_common/farming/forestry/farming/FarmTarget.java new file mode 100755 index 000000000..1eda2b1cd --- /dev/null +++ b/forestry_common/farming/forestry/farming/FarmTarget.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming; + +import forestry.core.utils.Vect; + +public class FarmTarget { + + private Vect start; + private int yOffset; + private int extent; + private int limit; + + public FarmTarget(Vect start) { + this.start = start; + } + + public void setYOffset(int yOffset) { + this.yOffset = yOffset; + } + + public void setLimit(int limit) { + this.limit = limit; + } + + public void setExtent(int extent) { + this.extent = extent; + } + + public Vect getStart() { + return start; + } + + public int getYOffset() { + return this.yOffset; + } + + public int getLimit() { + return limit; + } + + public int getExtent() { + return extent; + } +} diff --git a/forestry_common/farming/forestry/farming/GuiHandlerFarming.java b/forestry_common/farming/forestry/farming/GuiHandlerFarming.java new file mode 100755 index 000000000..aa533ae3c --- /dev/null +++ b/forestry_common/farming/forestry/farming/GuiHandlerFarming.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketSocketUpdate; +import forestry.core.proxy.Proxies; +import forestry.farming.gadgets.TileFarmPlain; +import forestry.farming.gui.ContainerFarm; +import forestry.farming.gui.GuiFarm; + +public class GuiHandlerFarming extends GuiHandlerBase { + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + case MultiFarmGUI: + TileFarmPlain tile = (TileFarmPlain) getTileForestry(world, x, y, z); + Proxies.net.sendToPlayer(new PacketSocketUpdate(PacketIds.SOCKET_UPDATE, x, y, z, tile), player); + return new ContainerFarm(player.inventory, tile); + default: + return null; + + } + } + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + case MultiFarmGUI: + return new GuiFarm(player, (TileFarmPlain) getTileForestry(world, x, y, z)); + default: + return null; + + } + } + +} diff --git a/forestry_common/farming/forestry/farming/circuits/CircuitFarmLogic.java b/forestry_common/farming/forestry/farming/circuits/CircuitFarmLogic.java new file mode 100755 index 000000000..0d646cacf --- /dev/null +++ b/forestry_common/farming/forestry/farming/circuits/CircuitFarmLogic.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.circuits; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.IFarmHousing; +import forestry.core.circuits.Circuit; +import forestry.farming.logic.FarmLogic; + +public class CircuitFarmLogic extends Circuit { + + private Class logicClass; + private boolean isManual = false; + + public CircuitFarmLogic(String uid, Class logicClass, String[] descriptions) { + super(uid, false, uid, descriptions); + this.logicClass = logicClass; + setLimit(4); + } + + public CircuitFarmLogic setManual() { + isManual = true; + return this; + } + + @Override + public boolean isCircuitable(TileEntity tile) { + return tile instanceof IFarmHousing; + } + + @Override + public void onInsertion(int slot, TileEntity tile) { + if (!isCircuitable(tile)) + return; + + FarmLogic logic = null; + try { + logic = logicClass.getConstructor(new Class[] { IFarmHousing.class }).newInstance(new Object[] { (IFarmHousing) tile }); + } catch (Exception ex) { + throw new RuntimeException("Failed to instantiate logic of class " + logicClass.getName() + ": " + ex.getMessage()); + } + + if (logic != null) { + logic.setManual(isManual); + ((IFarmHousing) tile).setFarmLogic(ForgeDirection.values()[slot + 2], logic); + } + } + + @Override + public void onLoad(int slot, TileEntity tile) { + onInsertion(slot, tile); + } + + @Override + public void onRemoval(int slot, TileEntity tile) { + if (!isCircuitable(tile)) + return; + + ((IFarmHousing) tile).resetFarmLogic(ForgeDirection.values()[slot + 2]); + } + + @Override + public void onTick(int slot, TileEntity tile) { + } + +} diff --git a/forestry_common/farming/forestry/farming/gadgets/BlockFarm.java b/forestry_common/farming/forestry/farming/gadgets/BlockFarm.java new file mode 100755 index 000000000..8c89973e1 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/BlockFarm.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.gadgets.BlockStructure; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; +import forestry.farming.gadgets.TileFarm.EnumFarmBlock; +import forestry.plugins.PluginFarming; + +public class BlockFarm extends BlockStructure { + + public BlockFarm() { + super(Material.rock); + setHardness(1.0f); + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + @SideOnly(Side.CLIENT) + public void getSubBlocks(Item item, CreativeTabs tab, List list) { + for (int i = 0; i < 6; i++) { + if (i == 1) + continue; + + for (EnumFarmBlock block : EnumFarmBlock.values()) { + ItemStack stack = new ItemStack(item, 1, i); + NBTTagCompound compound = new NBTTagCompound(); + block.saveToCompound(compound); + stack.setTagCompound(compound); + list.add(stack); + } + } + } + + @Override + public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z) { + ArrayList drops = getDrops(world, x, y, z, 0, 0); + if (drops.isEmpty()) + return super.getPickBlock(target, world, x, y, z); + return drops.get(0); + } + + @Override + public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entityliving, ItemStack stack) { + super.onBlockPlacedBy(world, x, y, z, entityliving, stack); + if (!stack.hasTagCompound()) + return; + + TileFarm tile = (TileFarm) world.getTileEntity(x, y, z); + tile.setFarmBlock(EnumFarmBlock.getFromCompound(stack.getTagCompound())); + } + + @Override + public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) { + int meta = world.getBlockMetadata(x, y, z); + if (Proxies.common.isSimulating(world) && canHarvestBlock(player, meta)) { + List drops = getDrops(world, x, y, z, 0, 0); + for (ItemStack drop : drops) { + StackUtils.dropItemStackAsEntity(drop, world, x, y, z); + } + } + return world.setBlockToAir(x, y, z); + } + + @Override + public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) { + ArrayList drops = new ArrayList(); + int meta = world.getBlockMetadata(x, y, z); + TileEntity tile = world.getTileEntity(x, y, z); + if (tile instanceof TileFarm) { + TileFarm farm = (TileFarm) tile; + + ItemStack stack = new ItemStack(this, 1, meta != 1 ? meta : 0); + NBTTagCompound compound = new NBTTagCompound(); + farm.getFarmBlock().saveToCompound(compound); + stack.setTagCompound(compound); + drops.add(stack); + } + return drops; + } + + @Override + public int getDamageValue(World world, int x, int y, int z) { + int meta = world.getBlockMetadata(x, y, z); + return meta != 1 ? meta : 0; + } + + @Override + public TileEntity createTileEntity(World world, int metadata) { + switch (metadata) { + case 2: + return new TileGearbox(); + case 3: + return new TileHatch(); + case 4: + return new TileValve(); + case 5: + return new TileControl(); + default: + return new TileFarmPlain(); + } + } + + @Override + public TileEntity createNewTileEntity(World world, int meta) { + return createTileEntity(world, meta); + } + + /* ICONS */ + @Override + public int getRenderType() { + return PluginFarming.modelIdFarmBlock; + } + + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + EnumFarmBlock.registerIcons(register); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int metadata) { + return getBlockTextureFromSideAndMetadata(EnumFarmBlock.BRICK, side, metadata); + } + + @SideOnly(Side.CLIENT) + public IIcon getBlockTextureFromSideAndMetadata(EnumFarmBlock type, int side, int metadata) { + return StackUtils.getBlock(type.base).getIcon(side, type.base.getItemDamage()); + } + + @SideOnly(Side.CLIENT) + public IIcon getOverlayTextureForBlock(int side, int metadata) { + + EnumFarmBlock type = EnumFarmBlock.BRICK_STONE; + if (metadata == 0 && side == 2) + return type.getIcon(TileFarm.TYPE_REVERSE); + else if (metadata == 0 && (side == 0 || side == 1)) + return type.getIcon(TileFarm.TYPE_TOP); + + switch (metadata) { + case 1: + return type.getIcon(TileFarm.TYPE_BAND); + case 2: + return type.getIcon(TileFarm.TYPE_GEARS); + case 3: + return type.getIcon(TileFarm.TYPE_HATCH); + case 4: + return type.getIcon(TileFarm.TYPE_VALVE); + case 5: + return type.getIcon(TileFarm.TYPE_CONTROL); + default: + return type.getIcon(TileFarm.TYPE_PLAIN); + } + } + + @Override + public boolean canConnectRedstone(IBlockAccess world, int x, int y, int z, int side) { + if (world.getBlockMetadata(x, y, z) == 5) + return true; + else + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) { + TileEntity tile = world.getTileEntity(x, y, z); + ItemStack base = EnumFarmBlock.BRICK_STONE.base; + + if (tile instanceof TileFarm) + base = ((TileFarm) tile).farmBlock.base; + + return StackUtils.getBlock(base).getIcon(side, base.getItemDamage()); + } +} diff --git a/forestry_common/farming/forestry/farming/gadgets/BlockMushroom.java b/forestry_common/farming/forestry/farming/gadgets/BlockMushroom.java new file mode 100755 index 000000000..13d787850 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/BlockMushroom.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import java.util.ArrayList; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockSapling; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.core.config.Defaults; +import forestry.core.proxy.Proxies; +import forestry.farming.worldgen.WorldGenBigMushroom; + +public class BlockMushroom extends BlockSapling { + + private final WorldGenerator[] generators; + private final ItemStack[] drops; + + public BlockMushroom() { + super(); + setHardness(0.0f); + this.generators = new WorldGenerator[] { new WorldGenBigMushroom(Blocks.brown_mushroom_block), new WorldGenBigMushroom(Blocks.red_mushroom_block) }; + this.drops = new ItemStack[] { new ItemStack(Blocks.brown_mushroom), new ItemStack(Blocks.red_mushroom) }; + setCreativeTab(null); + setTickRandomly(true); + } + + @Override + public boolean getTickRandomly() { + return true; + } + + // / DROPS + @Override + public ArrayList getDrops(World world, int X, int Y, int Z, int metadata, int fortune) { + ArrayList ret = new ArrayList(); + + int type = metadata & 0x03; + ret.add(drops[type]); + + return ret; + } + + @Override + protected boolean canPlaceBlockOn(Block block) { + return block == Blocks.mycelium; + } + + @Override + public void updateTick(World world, int i, int j, int k, Random random) { + + if (!Proxies.common.isSimulating(world)) + return; + + int meta = world.getBlockMetadata(i, j, k); + int type = meta & 0x03; + int maturity = meta >> 2; + + tickGermling(world, i, j, k, random, type, maturity); + } + + private void tickGermling(World world, int i, int j, int k, Random random, int type, int maturity) { + + int lightvalue = world.getBlockLightValue(i, j + 1, k); + + if (random.nextInt(2) != 0) + return; + + if (maturity != 3) { + maturity = 3; + int matX = maturity << 2; + int meta = (matX | type); + world.setBlockMetadataWithNotify(i, j, k, meta, Defaults.FLAG_BLOCK_SYNCH); + } else if (lightvalue <= 7) + func_149878_d(world, i, j, k, random); + } + + @Override + public void func_149878_d(World world, int i, int j, int k, Random random) { + int type = world.getBlockMetadata(i, j, k) & 0x03; + + if(type >= generators.length) + return; + + world.setBlockToAir(i, j, k); + if (!generators[type].generate(world, random, i, j, k)) + world.setBlock(i, j, k, this, type, 0); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerBlockIcons(IIconRegister register) { + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIcon(int side, int meta) { + int type = meta & 0x03; + if (type > 0) + return Blocks.red_mushroom.getIcon(side, meta); + else + return Blocks.brown_mushroom.getIcon(side, meta); + } + +} diff --git a/forestry_common/farming/forestry/farming/gadgets/StructureLogicFarm.java b/forestry_common/farming/forestry/farming/gadgets/StructureLogicFarm.java new file mode 100755 index 000000000..81add36b1 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/StructureLogicFarm.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import java.util.HashSet; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.TileEntity; + +import forestry.api.core.ITileStructure; +import forestry.api.farming.IFarmComponent; +import forestry.core.gadgets.BlockStructure.EnumStructureState; +import forestry.core.gadgets.StructureLogic; +import forestry.core.utils.Schemata; +import forestry.core.utils.Schemata.EnumStructureBlock; +import forestry.core.utils.Vect; + +public class StructureLogicFarm extends StructureLogic { + + /* CONSTANTS */ + public static final String UID_FARM = "farm"; + public static final Schemata SCHEMATA_FARM_3x3 = new Schemata("farm3x3", 5, 6, 5, + "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBMBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF").setOffsets(-2, -3, -2); + public static final Schemata SCHEMATA_FARM_4x3 = new Schemata("farm3x4", 6, 6, 5, + "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBMBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF").setOffsets(-2, -3, -3); + public static final Schemata SCHEMATA_FARM_4x4 = new Schemata("farm4x4", 6, 6, 6, + "FFFFFF", "FFFFFF", "FFFFFF", "FFFFFF", "FFFFFF", "FFFFFF", + "FFFFFF", "FAAAAF", "FAAAAF", "FBBBBF", "FAAAAF", "FFFFFF", + "FFFFFF", "FAAAAF", "FAAAAF", "FBBMBF", "FAAAAF", "FFFFFF", + "FFFFFF", "FAAAAF", "FAAAAF", "FBBBBF", "FAAAAF", "FFFFFF", + "FFFFFF", "FAAAAF", "FAAAAF", "FBBBBF", "FAAAAF", "FFFFFF", + "FFFFFF", "FFFFFF", "FFFFFF", "FFFFFF", "FFFFFF", "FFFFFF").setOffsets(-3, -3, -3); + public static final Schemata SCHEMATA_FARM_5x3 = new Schemata("farm3x5", 7, 6, 5, + "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBMBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FAAAF", "FAAAF", "FBBBF", "FAAAF", "FFFFF", + "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF", "FFFFF").setOffsets(-3, -3, -2); + public static final Schemata SCHEMATA_FARM_5x5 = new Schemata("farm5x5", 7, 6, 7, + "FFFFFFF", "FFFFFFF", "FFFFFFF", "FFFFFFF", "FFFFFFF", "FFFFFFF", + "FFFFFFF", "FAAAAAF", "FAAAAAF", "FBBBBBF", "FAAAAAF", "FFFFFFF", + "FFFFFFF", "FAAAAAF", "FAAAAAF", "FBBBBBF", "FAAAAAF", "FFFFFFF", + "FFFFFFF", "FAAAAAF", "FAAAAAF", "FBBMBBF", "FAAAAAF", "FFFFFFF", + "FFFFFFF", "FAAAAAF", "FAAAAAF", "FBBBBBF", "FAAAAAF", "FFFFFFF", + "FFFFFFF", "FAAAAAF", "FAAAAAF", "FBBBBBF", "FAAAAAF", "FFFFFFF", + "FFFFFFF", "FFFFFFF", "FFFFFFF", "FFFFFFF", "FFFFFFF", "FFFFFFF").setOffsets(-3, -3, -3); + + public static HashSet bricks = new HashSet(); + static { + bricks.add(Blocks.brick_block); + bricks.add(Blocks.stonebrick); + bricks.add(Blocks.sandstone); + bricks.add(Blocks.nether_brick); + bricks.add(Blocks.quartz_block); + } + + public StructureLogicFarm(ITileStructure structure) { + super(UID_FARM, structure); + schematas = new Schemata[] { SCHEMATA_FARM_3x3, SCHEMATA_FARM_4x3, SCHEMATA_FARM_5x3, SCHEMATA_FARM_5x5, SCHEMATA_FARM_4x4 }; + metaOnValid.put(EnumStructureBlock.BLOCK_B, 1); + } + + @Override + protected EnumStructureState determineMasterState(Schemata schemata, boolean rotate) { + + Vect dimensions = schemata.getDimensions(rotate); + int offsetX = schemata.getxOffset(); + int offsetZ = schemata.getzOffset(); + if (rotate) { + offsetX = schemata.getzOffset(); + offsetZ = schemata.getxOffset(); + } + + for (int i = 0; i < dimensions.x; i++) + for (int j = 0; j < schemata.getHeight(); j++) + for (int k = 0; k < dimensions.z; k++) { + + int x = structureTile.xCoord + i + offsetX; + int y = structureTile.yCoord + j + schemata.getyOffset(); + int z = structureTile.zCoord + k + offsetZ; + + if (!structureTile.getWorldObj().blockExists(x, y, z)) + return EnumStructureState.INDETERMINATE; + + EnumStructureBlock required = schemata.getAt(i, j, k, rotate); + + if (required == EnumStructureBlock.ANY) + continue; + + TileEntity tile = structureTile.getWorldObj().getTileEntity(x, y, z); + Block block = structureTile.getWorldObj().getBlock(x, y, z); + + switch (required) { + case AIR: + if (!block.isAir(structureTile.getWorldObj(), x, y, z)) + return EnumStructureState.INVALID; + break; + case BLOCK_A: + if (tile == null || !(tile instanceof IFarmComponent)) + return EnumStructureState.INVALID; + if (!((ITileStructure) tile).getTypeUID().equals(UID_FARM)) + return EnumStructureState.INVALID; + break; + case BLOCK_B: + case MASTER: + if (tile == null || !(tile instanceof TileFarm)) + return EnumStructureState.INVALID; + if (((TileFarm) tile).hasFunction()) + return EnumStructureState.INVALID; + break; + case BLOCK_C: + if (!bricks.contains(block)) + return EnumStructureState.INVALID; + break; + case FOREIGN: + if (tile instanceof ITileStructure) + return EnumStructureState.INVALID; + break; + default: + return EnumStructureState.INDETERMINATE; + } + } + + return EnumStructureState.VALID; + } + +} diff --git a/forestry_common/farming/forestry/farming/gadgets/TileControl.java b/forestry_common/farming/forestry/farming/gadgets/TileControl.java new file mode 100755 index 000000000..41563f3e6 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/TileControl.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.core.ITileStructure; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmComponent; +import forestry.api.farming.IFarmListener; +import forestry.api.farming.IFarmLogic; +import forestry.core.utils.Vect; + +public class TileControl extends TileFarm implements IFarmListener { + + public TileControl() { + fixedType = TYPE_CONTROL; + } + + @Override + protected void updateServerSide() { + if (!isInited) + registerWithMaster(); + } + + @Override + public void setCentralTE(TileEntity tile) { + super.setCentralTE(tile); + registerWithMaster(); + } + + private boolean isInited = false; + + private void registerWithMaster() { + + isInited = true; + if (!hasMaster()) + return; + + ITileStructure central = getCentralTE(); + if (!(central instanceof IFarmComponent)) + return; + + ((IFarmComponent) central).registerListener(this); + } + + @Override + public boolean hasFunction() { + return true; + } + + @Override + protected void createInventory() { + } + + /* IFARMLISTENER */ + @Override + public boolean cancelTask(IFarmLogic logic, ForgeDirection direction) { + return hasRedstoneSignal(direction) || hasRedstoneSignal(ForgeDirection.UP) || hasRedstoneSignal(ForgeDirection.DOWN); + } + + private boolean hasRedstoneSignal(ForgeDirection direction) { + Vect side = new Vect(xCoord + direction.offsetX, yCoord + direction.offsetY, zCoord + direction.offsetZ); + + ForgeDirection opp = direction.getOpposite(); + int dir = opp.offsetZ < 0 ? 2 : opp.offsetZ > 0 ? 3 : opp.offsetX < 0 ? 4 : opp.offsetX > 0 ? 5 : 0; + return worldObj.getIndirectPowerLevelTo(side.x, side.y, side.z, dir) > 0 || worldObj.isBlockProvidingPowerTo(side.x, side.y, side.z, dir) > 0; + } + + @Override + public boolean beforeCropHarvest(ICrop crop) { + return false; + } + + @Override + public void afterCropHarvest(Collection harvested, ICrop crop) { + } + + @Override + public void hasCollected(Collection collected, IFarmLogic logic) { + } + + @Override + public void hasCultivated(IFarmLogic logic, int x, int y, int z, ForgeDirection direction, int extent) { + } + + @Override + public void hasScheduledHarvest(Collection harvested, IFarmLogic logic, int x, int y, int z, ForgeDirection direction, int extent) { + } + +} diff --git a/forestry_common/farming/forestry/farming/gadgets/TileFarm.java b/forestry_common/farming/forestry/farming/gadgets/TileFarm.java new file mode 100755 index 000000000..4e3552b21 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/TileFarm.java @@ -0,0 +1,359 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.ForestryAPI; +import forestry.api.core.IStructureLogic; +import forestry.api.core.ITileStructure; +import forestry.api.farming.Farmables; +import forestry.api.farming.IFarmComponent; +import forestry.api.farming.IFarmListener; +import forestry.core.gadgets.TileForestry; +import forestry.core.network.GuiId; +import forestry.core.network.PacketPayload; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.TileInventoryAdapter; +import forestry.core.utils.Utils; + +public abstract class TileFarm extends TileForestry implements IFarmComponent { + + public static final int TYPE_PLAIN = 0; + public static final int TYPE_REVERSE = 1; + public static final int TYPE_TOP = 2; + public static final int TYPE_BAND = 3; + public static final int TYPE_GEARS = 4; + public static final int TYPE_HATCH = 5; + public static final int TYPE_VALVE = 6; + public static final int TYPE_CONTROL = 7; + + public enum EnumFarmBlock { + + BRICK_STONE(new ItemStack(Blocks.stonebrick, 1, 0)), + BRICK_MOSSY(new ItemStack(Blocks.stonebrick, 1, 1)), + BRICK_CRACKED(new ItemStack(Blocks.stonebrick, 1, 2)), + BRICK(new ItemStack(Blocks.brick_block)), + SANDSTONE_SMOOTH(new ItemStack(Blocks.sandstone, 1, 2)), + SANDSTONE_CHISELED(new ItemStack(Blocks.sandstone, 1, 1)), + BRICK_NETHER(new ItemStack(Blocks.nether_brick)), + BRICK_CHISELED(new ItemStack(Blocks.stonebrick, 1, 3)), + QUARTZ(new ItemStack(Blocks.quartz_block, 1, 0)), + QUARTZ_CHISELED(new ItemStack(Blocks.quartz_block, 1, 1)), + QUARTZ_LINES(new ItemStack(Blocks.quartz_block, 1, 2)); + public final ItemStack base; + + private EnumFarmBlock(ItemStack base) { + this.base = base; + } + @SideOnly(Side.CLIENT) + private static IIcon[] icons; + + @SideOnly(Side.CLIENT) + public static void registerIcons(IIconRegister register) { + + icons = new IIcon[8]; + // for(int i = 0; i < values().length; i++) { + // generateTexturesIfNeeded(values()[i]); + + icons[0] = TextureManager.getInstance().registerTex(register, "farm/plain"); + icons[1] = TextureManager.getInstance().registerTex(register, "farm/reverse"); + icons[2] = TextureManager.getInstance().registerTex(register, "farm/top"); + icons[3] = TextureManager.getInstance().registerTex(register, "farm/band"); + icons[4] = TextureManager.getInstance().registerTex(register, "farm/gears"); + icons[5] = TextureManager.getInstance().registerTex(register, "farm/hatch"); + icons[6] = TextureManager.getInstance().registerTex(register, "farm/valve"); + icons[7] = TextureManager.getInstance().registerTex(register, "farm/control"); + // } + } + + @SideOnly(Side.CLIENT) + public IIcon getIcon(int type) { + return icons[type]; + } + + public void saveToCompound(NBTTagCompound compound) { + compound.setInteger("FarmBlock", this.ordinal()); + } + + public String getName() { + return base.getItem().getItemStackDisplayName(base); + } + + public ItemStack getCraftingIngredient() { + return base; + } + + public static EnumFarmBlock getFromCompound(NBTTagCompound compound) { + + if (compound != null) { + int farmBlockOrdinal = compound.getInteger("FarmBlock"); + if (farmBlockOrdinal < EnumFarmBlock.values().length) + return EnumFarmBlock.values()[farmBlockOrdinal]; + } + + return EnumFarmBlock.BRICK_STONE; + } + } + + public TileFarm() { + this.structureLogic = Farmables.farmInterface.createFarmStructureLogic(this); + } + + /* GUI */ + @Override + public void openGui(EntityPlayer player) { + if (this.isMaster()) + player.openGui(ForestryAPI.instance, GuiId.MultiFarmGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + else if (this.hasMaster()) + player.openGui(ForestryAPI.instance, GuiId.MultiFarmGUI.ordinal(), worldObj, masterX, masterY, masterZ); + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + this.isMaster = nbttagcompound.getBoolean("IsMaster"); + this.masterX = nbttagcompound.getInteger("MasterX"); + this.masterY = nbttagcompound.getInteger("MasterY"); + this.masterZ = nbttagcompound.getInteger("MasterZ"); + + farmBlock = EnumFarmBlock.getFromCompound(nbttagcompound); + + // Init for master state + if (isMaster) + makeMaster(); + + if (inventory != null) + inventory.readFromNBT(nbttagcompound); + + structureLogic.readFromNBT(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setBoolean("IsMaster", isMaster); + nbttagcompound.setInteger("MasterX", masterX); + nbttagcompound.setInteger("MasterY", masterY); + nbttagcompound.setInteger("MasterZ", masterZ); + + farmBlock.saveToCompound(nbttagcompound); + + if (inventory != null) + inventory.writeToNBT(nbttagcompound); + + structureLogic.writeToNBT(nbttagcompound); + } + + /* UPDATING */ + @Override + public void initialize() { + } + + @Override + public void updateEntity() { + + if (!Proxies.common.isSimulating(worldObj)) + updateClientSide(); + else { + + if (!isInited) { + initialize(); + isInited = true; + } + + // Periodic validation if needed + if (worldObj.getTotalWorldTime() % 200 == 0 && (!isIntegratedIntoStructure() || isMaster())) + validateStructure(); + + updateServerSide(); + } + } + + protected void updateServerSide() { + } + + protected void updateClientSide() { + } + + /* CONSTRUCTION MATERIAL */ + EnumFarmBlock farmBlock = EnumFarmBlock.BRICK_STONE; + protected int fixedType = -1; + + public void setFarmBlock(EnumFarmBlock block) { + farmBlock = block; + sendNetworkUpdate(); + } + + public EnumFarmBlock getFarmBlock() { + return farmBlock; + } + + @SideOnly(Side.CLIENT) + public IIcon getIcon(int side, int meta) { + /* + * if(fixedType >= 0) return farmBlock.getIcon(fixedType); + * + * int type = 0; if (meta == 1) type = TYPE_BAND; + * + * if (meta == 0 && side == 2) type = TYPE_REVERSE; else if (meta == 0 && (side == 0 || side == 1)) type = TYPE_TOP; + * + * return farmBlock.getIcon(type); + */ + return null; + } + + /* INVENTORY MANAGMENT */ + protected TileInventoryAdapter inventory; + + protected abstract void createInventory(); + + /* TILEFORESTRY */ + @Override + public PacketPayload getPacketPayload() { + PacketPayload payload = new PacketPayload(0, 1); + payload.shortPayload[0] = (short) farmBlock.ordinal(); + return payload; + } + + @Override + public void fromPacketPayload(PacketPayload payload) { + EnumFarmBlock farmType = EnumFarmBlock.values()[payload.shortPayload[0]]; + if (this.farmBlock != farmType) { + this.farmBlock = farmType; + worldObj.func_147479_m(xCoord, yCoord, zCoord); + } + } + + /* ITILESTRUCTURE */ + IStructureLogic structureLogic; + private boolean isMaster; + private int masterX, masterZ; + private int masterY = -99; + + @Override + public String getTypeUID() { + return structureLogic.getTypeUID(); + } + + @Override + public void validateStructure() { + structureLogic.validateStructure(); + } + + @Override + public void makeMaster() { + setCentralTE(null); + this.isMaster = true; + + if (inventory == null) + createInventory(); + } + + @Override + public void onStructureReset() { + setCentralTE(null); + if (worldObj.getBlockMetadata(xCoord, yCoord, zCoord) == 1) + worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, 0, 0); + isMaster = false; + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + @Override + public ITileStructure getCentralTE() { + + if (!isIntegratedIntoStructure()) + return null; + + if (!isMaster) { + TileEntity tile = worldObj.getTileEntity(masterX, masterY, masterZ); + if (tile instanceof ITileStructure) { + ITileStructure master = (ITileStructure) worldObj.getTileEntity(masterX, masterY, masterZ); + if (master.isMaster()) + return master; + else + return null; + } else + return null; + } else + return this; + + } + + private boolean isSameTile(TileEntity tile) { + return tile.xCoord == xCoord && tile.yCoord == yCoord && tile.zCoord == zCoord; + } + + @Override + public void setCentralTE(TileEntity tile) { + if (tile == null || tile == this || isSameTile(tile)) { + this.masterX = this.masterZ = 0; + this.masterY = -99; + return; + } + + this.isMaster = false; + this.masterX = tile.xCoord; + this.masterY = tile.yCoord; + this.masterZ = tile.zCoord; + + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + @Override + public boolean isMaster() { + return isMaster; + } + + protected boolean hasMaster() { + return this.masterY >= 0; + } + + @Override + public IInventory getInventory() { + return inventory; + } + + @Override + public boolean isIntegratedIntoStructure() { + return isMaster || this.masterY >= 0; + } + + @Override + public void registerListener(IFarmListener listener) { + } + + @Override + public void removeListener(IFarmListener listener) { + } + + @Override + public String getInventoryName() { + return "Farm"; + } + + /* INTERACTION */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return Utils.isUseableByPlayer(player, this, worldObj, xCoord, yCoord, zCoord); + } +} diff --git a/forestry_common/farming/forestry/farming/gadgets/TileFarmPlain.java b/forestry_common/farming/forestry/farming/gadgets/TileFarmPlain.java new file mode 100755 index 000000000..60c2c876d --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/TileFarmPlain.java @@ -0,0 +1,965 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; + +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry.FluidContainerData; +import net.minecraftforge.fluids.FluidStack; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuitBoard; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmComponent; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmListener; +import forestry.api.farming.IFarmLogic; +import forestry.api.farming.IFarmable; +import forestry.core.EnumErrorCode; +import forestry.core.GameMode; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.interfaces.IClimatised; +import forestry.core.interfaces.IHintSource; +import forestry.core.interfaces.ISocketable; +import forestry.core.proxy.Proxies; +import forestry.core.utils.DelayTimer; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.TileInventoryAdapter; +import forestry.core.utils.Vect; +import forestry.farming.FarmTarget; +import forestry.farming.logic.FarmLogicArboreal; +import forestry.plugins.PluginFarming; + +public class TileFarmPlain extends TileFarm implements IFarmHousing, ISocketable, IClimatised, IHintSource { + + public static final int SLOT_RESOURCES_1 = 0; + public static final int SLOT_GERMLINGS_1 = 6; + public static final int SLOT_PRODUCTION_1 = 12; + public static final int SLOT_COUNT_RESERVOIRS = 6; + public static final int SLOT_COUNT_PRODUCTION = 8; + + public static final int SLOT_FERTILIZER = 20; + public static final int SLOT_CAN = 21; + + public static final int SLOT_COUNT = 22; + + public static final FluidStack STACK_WATER = LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1); + + public static final int DELAY_HYDRATION = 100; + public static final float RAINFALL_MODIFIER_CAP = 15f; + public static final int BUFFER_FERTILIZER = 200; + + private IFarmLogic[] farmLogics = new IFarmLogic[4]; + + private TreeMap targets; + private int allowedExtent = 0; + private final DelayTimer checkTimer = new DelayTimer(); + + private final InventoryAdapter sockets = new InventoryAdapter(1, "sockets"); + + private ForestryTank liquidTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + + private IFarmLogic harvestProvider; // The farm logic which supplied the pending crops. + private final Stack pendingCrops = new Stack(); + private final Stack pendingProduce = new Stack(); + private int storedFertilizer; + private int fertilizerValue = 2000; + + private boolean stage = false; + + private int biomeId; + private float temperature; + private float humidity; + + private int hydrationDelay = 0; + private int ticksSinceRainfall = 0; + + public TileFarmPlain() { + fertilizerValue = GameMode.getGameMode().getIntegerSetting("farms.fertilizer.value"); + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + storedFertilizer = nbttagcompound.getInteger("StoredFertilizer"); + hydrationDelay = nbttagcompound.getInteger("HydrationDelay"); + ticksSinceRainfall = nbttagcompound.getInteger("TicksSinceRainfall"); + sockets.readFromNBT(nbttagcompound); + + refreshFarmLogics(); + + liquidTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + if (nbttagcompound.hasKey("LiquidTank")) + liquidTank.readFromNBT(nbttagcompound.getCompoundTag("LiquidTank")); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + sockets.writeToNBT(nbttagcompound); + nbttagcompound.setInteger("StoredFertilizer", storedFertilizer); + nbttagcompound.setInteger("HydrationDelay", hydrationDelay); + nbttagcompound.setInteger("TicksSinceRainfall", ticksSinceRainfall); + + NBTTagCompound NBTresourceSlot = new NBTTagCompound(); + liquidTank.writeToNBT(NBTresourceSlot); + nbttagcompound.setTag("LiquidTank", NBTresourceSlot); + + } + + /* UPDATING */ + @Override + public void initialize() { + setBiomeInformation(); + } + + @Override + protected void updateServerSide() { + super.updateServerSide(); + + if (!isMaster()) + return; + + if (worldObj.isRaining()) { + if (hydrationDelay > 0) + hydrationDelay--; + else + ticksSinceRainfall = 0; + } else { + hydrationDelay = DELAY_HYDRATION; + if (ticksSinceRainfall < Integer.MAX_VALUE) + ticksSinceRainfall++; + } + + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + // Check if we have suitable items waiting in the item slot + if (inventory.getStackInSlot(SLOT_CAN) != null) { + FluidContainerData container = LiquidHelper.getLiquidContainer(inventory.getStackInSlot(SLOT_CAN)); + if (container != null && LiquidHelper.isLiquid(Defaults.LIQUID_WATER, container.fluid)) { + + inventory.setInventorySlotContents(SLOT_CAN, StackUtils.replenishByContainer(this, inventory.getStackInSlot(SLOT_CAN), container, liquidTank)); + if (inventory.getStackInSlot(SLOT_CAN).stackSize <= 0) + inventory.setInventorySlotContents(SLOT_CAN, null); + } + } + + } + + private void setBiomeInformation() { + BiomeGenBase biome = worldObj.getBiomeGenForCoords(xCoord, zCoord); + this.biomeId = biome.biomeID; + this.temperature = biome.temperature; + this.humidity = biome.rainfall; + setErrorState(EnumErrorCode.OK); + } + + private void createTargets() { + + targets = new TreeMap(); + + int groundY = yCoord - 1; + allowedExtent = 0; + + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { + if (direction == ForgeDirection.UP || direction == ForgeDirection.DOWN) + continue; + // System.out.println(String.format("Master at %s/%s/%s:%s", xCoord, yCoord, zCoord, groundY)); + ArrayList potential = new ArrayList(); + + int xDistance = 0; + int zDistance = 0; + Vect candidate = new Vect(xCoord, groundY, zCoord); + + // Determine distance from master TE + while (true) { + xDistance += direction.offsetX; + zDistance += direction.offsetZ; + // System.out.println(String.format("New offset for %s: x:%s z:%s", direction, xDistance, zDistance)); + // System.out.println(String.format("Validating for %s: x:%s y:%s z:%s", direction, xCoord + xDistance, groundY, zCoord + zDistance)); + + TileEntity tile = worldObj.getTileEntity(xCoord + xDistance, groundY, zCoord + zDistance); + if (tile == null) + // System.out.println("NUll TE"); + break; + if (!(tile instanceof IFarmComponent)) + // System.out.println("Not instaceof of farm component"); + break; + + candidate = new Vect(xCoord + xDistance, groundY, zCoord + zDistance); + } + // System.out.println(String.format("Determined distance for %s at %s.", direction, candidate)); + + // Determine block to start search from + ForgeDirection search; + if (direction.offsetX != 0) + search = ForgeDirection.SOUTH; + else + search = ForgeDirection.EAST; + + int xOffset = 0; + int zOffset = 0; + Vect start = candidate; + while (true) { + xOffset += search.offsetX; + zOffset += search.offsetZ; + + TileEntity tile = worldObj.getTileEntity(candidate.x + xOffset, candidate.y, candidate.z + zOffset); + if (tile == null) + break; + if (!(tile instanceof IFarmComponent)) + break; + + start = new Vect(candidate.x + xOffset, candidate.y, candidate.z + zOffset); + } + // System.out.println(String.format("Determined start block for %s at %s.", direction, candidate)); + + ForgeDirection reverse = search.getOpposite(); + ForgeDirection tocenter = direction.getOpposite(); + Vect last = new Vect(start.x + direction.offsetX, start.y, start.z + direction.offsetZ); + potential.add(new FarmTarget(last)); + while (true) { + // Switch to next potential block in the farm. + last = new Vect(last.x + reverse.offsetX, last.y, last.z + reverse.offsetZ); + // Check validity. + TileEntity tile = worldObj.getTileEntity(last.x + tocenter.offsetX, last.y, last.z + tocenter.offsetZ); + + // break if we have reached the end of the farm's length. + if (tile == null) + break; + if (!(tile instanceof IFarmComponent)) + break; + + potential.add(new FarmTarget(last)); + } + + // System.out.println(String.format("Adding %s to %s", potential.size(), direction)); + + // Set the maximum allowed extent. + if (potential.size() + 1 > allowedExtent) + allowedExtent = potential.size() + 1; + targets.put(direction, potential.toArray(new FarmTarget[0])); + } + + // Fill out the corners + // System.out.println("Trying to round corners"); + TreeMap cache = new TreeMap(); + + for (Map.Entry entry : targets.entrySet()) { + ForgeDirection direction = entry.getKey(); + // If the count of possible targets does matches the allowedExtent, we are on the long side and will not process + if (direction == ForgeDirection.SOUTH || direction == ForgeDirection.NORTH) { + cache.put(entry.getKey(), entry.getValue()); + continue; + } + + // Set start and direction to search + ArrayList targ = new ArrayList(Arrays.asList(entry.getValue())); + int sidecount = targ.size(); + + FarmTarget start = entry.getValue()[0]; + ForgeDirection search = ForgeDirection.SOUTH; + int cornerShift = 0; + if (!Config.squareFarms) + cornerShift = 1; + // System.out.println(String.format("Processing start at %s for direction %s.", start.getStart(), direction)); + + for (int i = cornerShift; i < allowedExtent + 1; i++) { + FarmTarget corner = new FarmTarget(new Vect(start.getStart().x + search.offsetX * i, start.getStart().y, start.getStart().z + search.offsetZ + * i)); + if (!Config.squareFarms) { + corner.setLimit(allowedExtent - i); + // System.out.println(String.format("Setting %s at extent %s", corner.getStart().toString(), corner.getExtent())); + if (corner.getLimit() > 0) + targ.add(0, corner); + } else + targ.add(0, corner); + } + + search = search.getOpposite(); + for (int i = sidecount; i < sidecount + allowedExtent - cornerShift; i++) { + FarmTarget corner = new FarmTarget(new Vect(start.getStart().x + search.offsetX * i, start.getStart().y, start.getStart().z + search.offsetZ + * i)); + if (!Config.squareFarms) + corner.setLimit(sidecount + allowedExtent - 1 - i); + // System.out.println(String.format("Setting %s at extent %s", corner.getStart().toString(), corner.getExtent())); + targ.add(corner); + } + + cache.put(entry.getKey(), targ.toArray(new FarmTarget[0])); + } + + targets = cache; + } + + private void setExtents() { + + for (Map.Entry entry : targets.entrySet()) { + ForgeDirection direction = entry.getKey(); + for (FarmTarget target : entry.getValue()) { + + int yOffset = 0; + for (yOffset = 2; yOffset > -3; yOffset--) { + Vect position = new Vect(target.getStart().x, target.getStart().y + yOffset, target.getStart().z); + if (StructureLogicFarm.bricks.contains(worldObj.getBlock(position.x, position.y, position.z))) + break; + } + target.setYOffset(yOffset + 1); + + int extent = 0; + // Determine extent limit + int limit = allowedExtent; + if (target.getLimit() > 0) + limit = target.getLimit(); + + // Determine extent + for (extent = 0; extent < limit; extent++) { + Vect position = new Vect(target.getStart().x + direction.offsetX * extent, target.getStart().y + yOffset, target.getStart().z + + direction.offsetZ * extent); + if (!StructureLogicFarm.bricks.contains(worldObj.getBlock(position.x, position.y, position.z))) + break; + } + + target.setExtent(extent); + } + } + } + + @Override + protected void createInventory() { + inventory = new TileInventoryAdapter(this, SLOT_COUNT, "Items"); + } + + @Override + public boolean doWork() { + + setBiomeInformation(); + + // System.out.println("Starting doWork()"); + if (targets == null) { + createTargets(); + setExtents(); + } else if (checkTimer.delayPassed(worldObj, 400)) + setExtents(); + + if (inventory == null) + createInventory(); + + // System.out.println("Targets set"); + if (tryAddPending()) + return true; + + // System.out.println("Nothing pending added."); + // Abort if we still have produce waiting. + if (!pendingProduce.isEmpty()) { + setErrorState(EnumErrorCode.NOSPACE); + return false; + } + + // System.out.println("Product queue empty."); + if (storedFertilizer <= BUFFER_FERTILIZER) { + replenishFertilizer(); + if (storedFertilizer <= 0) { + setErrorState(EnumErrorCode.NOFERTILIZER); + return false; + } + } + + // Cull queued crops. + if (!pendingCrops.isEmpty()) + if (cullCrop(pendingCrops.peek(), harvestProvider)) { + pendingCrops.pop(); + return true; + } else + return false; + + // Cultivation and collection + boolean consumedEnergy = false; + boolean hasFarmland = false; + boolean hasFertilizer = false; + boolean hasLiquid = false; + + cycle: for (Map.Entry entry : targets.entrySet()) { + if (farmLogics.length <= entry.getKey().ordinal() - 2 || farmLogics[entry.getKey().ordinal() - 2] == null) + continue; + + boolean didWork = false; + + IFarmLogic logic = farmLogics[entry.getKey().ordinal() - 2]; + + // Allow listeners to cancel this cycle. + for (IFarmListener listener : eventHandlers) + if (listener.cancelTask(logic, entry.getKey())) + continue cycle; + + // Always try to collect windfall first. + if (doCollection(logic)) + didWork = true; + else + for (int i = 0; i < entry.getValue().length; i++) { + + FarmTarget target = entry.getValue()[i]; + if (target.getExtent() <= 0) + continue; + else + hasFarmland = true; + + if (!stage) { + + // Check fertilizer and water + if (!hasFertilizer(logic.getFertilizerConsumption())) + continue; + else + hasFertilizer = true; + + FluidStack liquid = LiquidHelper.getLiquid(Defaults.LIQUID_WATER, logic.getWaterConsumption(getHydrationModifier())); + if (liquid.amount > 0 && !hasLiquid(liquid)) + continue; + else + hasLiquid = true; + + if (doCultivationPhase(logic, target, entry.getKey())) { + // Remove fertilizer and water + removeFertilizer(logic.getFertilizerConsumption()); + removeLiquid(liquid); + + didWork = true; + } + + } else { + hasFertilizer = true; + hasLiquid = true; + didWork = doHarvestPhase(logic, target, entry.getKey()); + } + + if (didWork) + break; + } + + if (didWork) { + consumedEnergy = true; + break; + } + } + + if (consumedEnergy) + setErrorState(EnumErrorCode.OK); + else if (!hasFarmland) + setErrorState(EnumErrorCode.NOFARMLAND); + else if (!hasFertilizer) + setErrorState(EnumErrorCode.NOFERTILIZER); + else if (!hasLiquid) + setErrorState(EnumErrorCode.NOLIQUID); + else + setErrorState(EnumErrorCode.OK); + // Farms alternate between cultivation and harvest. + stage = !stage; + return consumedEnergy; + } + + private boolean doCultivationPhase(IFarmLogic logic, FarmTarget target, ForgeDirection direction) { + + if (logic.cultivate(target.getStart().x, target.getStart().y + target.getYOffset(), target.getStart().z, direction, target.getExtent())) { + for (IFarmListener listener : eventHandlers) + listener.hasCultivated(logic, target.getStart().x, target.getStart().y, target.getStart().z, direction, target.getExtent()); + return true; + } + + return false; + } + + private boolean doHarvestPhase(IFarmLogic logic, FarmTarget target, ForgeDirection direction) { + + Collection next = logic.harvest(target.getStart().x, target.getStart().y + target.getYOffset(), target.getStart().z, direction, + target.getExtent()); + if (next == null || next.size() <= 0) + return false; + + // Let event handlers know. + for (IFarmListener listener : eventHandlers) + listener.hasScheduledHarvest(next, logic, target.getStart().x, target.getStart().y + target.getYOffset(), target.getStart().z, direction, + target.getExtent()); + + pendingCrops.addAll(next); + harvestProvider = logic; + return true; + } + + private boolean doCollection(IFarmLogic logic) { + + Collection collected = logic.collect(); + if (collected == null || collected.size() <= 0) + return false; + + // Let event handlers know. + for (IFarmListener listener : eventHandlers) + listener.hasCollected(collected, logic); + + for (ItemStack produce : collected) { + + // Germlings try to go into germling slots first. + if (logic.isAcceptedGermling(produce)) + produce.stackSize -= inventory.addStack(produce, SLOT_GERMLINGS_1, SLOT_COUNT_RESERVOIRS, false, true); + + if (produce.stackSize <= 0) + continue; + produce.stackSize -= inventory.addStack(produce, SLOT_PRODUCTION_1, SLOT_COUNT_PRODUCTION, false, true); + if (produce.stackSize <= 0) + continue; + + pendingProduce.push(produce); + } + + return true; + } + + private boolean cullCrop(ICrop crop, IFarmLogic provider) { + + // Let event handlers handle the harvest first. + for (IFarmListener listener : eventHandlers) + if (listener.beforeCropHarvest(crop)) + return true; + + // Check fertilizer + if (!hasFertilizer(provider.getFertilizerConsumption())) { + setErrorState(EnumErrorCode.NOFERTILIZER); + return false; + } + + // Check water + FluidStack liquid = LiquidHelper.getLiquid(Defaults.LIQUID_WATER, provider.getWaterConsumption(getHydrationModifier())); + if (liquid.amount > 0 && !hasLiquid(liquid)) { + setErrorState(EnumErrorCode.NOLIQUID); + return false; + } + + Collection harvested = crop.harvest(); + if (harvested == null) { + Proxies.log.fine("Failed to harvest crop: " + crop.toString()); + return true; + } + + // Remove fertilizer and water + removeFertilizer(provider.getFertilizerConsumption()); + removeLiquid(liquid); + + // Let event handlers handle the harvest first. + for (IFarmListener listener : eventHandlers) + listener.afterCropHarvest(harvested, crop); + + // Stow harvest. + for (ItemStack harvest : harvested) { + + // Special case germlings + for (IFarmLogic logic : farmLogics) + if (logic.isAcceptedGermling(harvest)) { + harvest.stackSize -= inventory.addStack(harvest, SLOT_GERMLINGS_1, SLOT_COUNT_RESERVOIRS, false, true); + break; + } + + // Handle the rest + if (harvest.stackSize <= 0) + continue; + + harvest.stackSize -= inventory.addStack(harvest, SLOT_PRODUCTION_1, SLOT_COUNT_PRODUCTION, false, true); + if (harvest.stackSize <= 0) + continue; + + pendingProduce.push(harvest); + } + + return true; + } + + private boolean tryAddPending() { + if (pendingProduce.isEmpty()) + return false; + + ItemStack next = pendingProduce.peek(); + if (inventory.tryAddStack(next, SLOT_PRODUCTION_1, SLOT_COUNT_PRODUCTION, true, true)) { + pendingProduce.pop(); + return true; + } + + setErrorState(EnumErrorCode.NOSPACE); + return false; + } + + /* FERTILIZER HANDLING */ + private void replenishFertilizer() { + if(fertilizerValue < 0) { + storedFertilizer += 2000; + return; + } + + ItemStack fertilizer = inventory.getStackInSlot(SLOT_FERTILIZER); + if (fertilizer == null || fertilizer.stackSize <= 0) + return; + + if (!acceptsAsFertilizer(fertilizer)) + return; + + inventory.decrStackSize(SLOT_FERTILIZER, 1); + storedFertilizer += fertilizerValue; + } + + private boolean hasFertilizer(int amount) { + if(fertilizerValue < 0) + return true; + + return storedFertilizer >= amount; + } + + private void removeFertilizer(int amount) { + + if(fertilizerValue < 0) + return; + + storedFertilizer -= amount; + if (storedFertilizer < 0) + storedFertilizer = 0; + } + + public int getStoredFertilizerScaled(int scale) { + if (storedFertilizer == 0) + return 0; + + return (storedFertilizer * scale) / (fertilizerValue + BUFFER_FERTILIZER); + } + + /* STRUCTURE HANDLING */ + @Override + public void makeMaster() { + super.makeMaster(); + if (liquidTank == null) + liquidTank = new ForestryTank(Defaults.PROCESSOR_TANK_CAPACITY); + refreshFarmLogics(); + } + + @Override + public void onStructureReset() { + super.onStructureReset(); + } + + public ForestryTank getTank() { + return liquidTank; + } + + @Override + public void setFarmLogic(ForgeDirection direction, IFarmLogic logic) { + farmLogics[direction.ordinal() - 2] = logic; + } + + @Override + public void resetFarmLogic(ForgeDirection direction) { + farmLogics[direction.ordinal() - 2] = new FarmLogicArboreal(this); + } + + public IFarmLogic[] getFarmLogics() { + return farmLogics; + } + + private void refreshFarmLogics() { + + farmLogics = new IFarmLogic[] { new FarmLogicArboreal(this), new FarmLogicArboreal(this), new FarmLogicArboreal(this), new FarmLogicArboreal(this) }; + + // See whether we have socketed stuff. + ItemStack chip = sockets.getStackInSlot(0); + if (chip != null) { + ICircuitBoard chipset = ChipsetManager.circuitRegistry.getCircuitboard(chip); + if (chipset != null) + chipset.onLoad(this); + } + } + + /* ISOCKETABLE */ + @Override + public int getSocketCount() { + return sockets.getSizeInventory(); + } + + @Override + public ItemStack getSocket(int slot) { + return sockets.getStackInSlot(slot); + } + + @Override + public void setSocket(int slot, ItemStack stack) { + + if (stack != null && !ChipsetManager.circuitRegistry.isChipset(stack)) + return; + + // Dispose correctly of old chipsets + if (sockets.getStackInSlot(slot) != null) + if (ChipsetManager.circuitRegistry.isChipset(sockets.getStackInSlot(slot))) { + ICircuitBoard chipset = ChipsetManager.circuitRegistry.getCircuitboard(sockets.getStackInSlot(slot)); + if (chipset != null) + chipset.onRemoval(this); + } + + if (stack == null) { + sockets.setInventorySlotContents(slot, stack); + refreshFarmLogics(); + return; + } + + sockets.setInventorySlotContents(slot, stack); + + ICircuitBoard chipset = ChipsetManager.circuitRegistry.getCircuitboard(stack); + if (chipset != null) + chipset.onInsertion(this); + } + + /* IFARMHOUSING */ + @Override + public World getWorld() { + return worldObj; + } + + @Override + public boolean hasResources(ItemStack[] resources) { + return inventory.contains(resources, SLOT_RESOURCES_1, SLOT_COUNT_RESERVOIRS); + } + + @Override + public void removeResources(ItemStack[] resources) { + inventory.removeResources(resources, SLOT_RESOURCES_1, SLOT_COUNT_RESERVOIRS); + } + + @Override + public boolean hasLiquid(FluidStack liquid) { + return liquidTank.getFluidAmount() >= liquid.amount && liquidTank.getFluid().isFluidEqual(liquid); + } + + @Override + public void removeLiquid(FluidStack liquid) { + liquidTank.drain(liquid.amount, true); + } + + public boolean hasGermlings(ItemStack[] germlings) { + return inventory.contains(germlings, SLOT_GERMLINGS_1, SLOT_COUNT_RESERVOIRS); + } + + @Override + public boolean plantGermling(IFarmable germling, World world, int x, int y, int z) { + + for (int i = SLOT_GERMLINGS_1; i < SLOT_GERMLINGS_1 + SLOT_COUNT_RESERVOIRS; i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (!germling.isGermling(inventory.getStackInSlot(i))) + continue; + + if (!germling.plantSaplingAt(inventory.getStackInSlot(i), world, x, y, z)) + continue; + + inventory.decrStackSize(i, 1); + return true; + } + return false; + } + + /* IFARMCOMPONENT */ + private final Set eventHandlers = new LinkedHashSet(); + + @Override + public boolean hasFunction() { + return false; + } + + @Override + public void registerListener(IFarmListener listener) { + eventHandlers.add(listener); + } + + @Override + public void removeListener(IFarmListener listener) { + eventHandlers.remove(listener); + } + + @Override + public boolean acceptsAsGermling(ItemStack itemstack) { + if (itemstack == null) + return false; + if (farmLogics == null) + return false; + + for (IFarmLogic logic : farmLogics) + if (logic.isAcceptedGermling(itemstack)) + return true; + + return false; + } + + @Override + public boolean acceptsAsResource(ItemStack itemstack) { + if (itemstack == null) + return false; + if (farmLogics == null) + return false; + + for (IFarmLogic logic : farmLogics) + if (logic.isAcceptedResource(itemstack)) + return true; + + return false; + } + + @Override + public boolean acceptsAsFertilizer(ItemStack itemstack) { + if (itemstack == null) + return false; + + return StackUtils.isIdenticalItem(PluginFarming.farmFertilizer, itemstack); + } + + int[] coords; + int[] offset; + int[] area; + + @Override + public int[] getCoords() { + if (coords == null) + coords = new int[] { xCoord, yCoord, zCoord }; + return coords; + } + + @Override + public int[] getOffset() { + if (offset == null) + offset = new int[] { -10, -2, -10 }; + return offset; + } + + @Override + public int[] getArea() { + if (area == null) + area = new int[] { 21, 13, 21 }; + return area; + } + + /* NETWORK GUI */ + public void getGUINetworkData(int i, int j) { + + switch (i) { + case 0: + storedFertilizer = j; + break; + case 3: + this.temperature = (float) j / 100; + break; + case 4: + this.humidity = (float) j / 100; + break; + case 5: + ticksSinceRainfall = j; + break; + } + } + + public void sendGUINetworkData(Container container, ICrafting iCrafting) { + iCrafting.sendProgressBarUpdate(container, 0, storedFertilizer); + iCrafting.sendProgressBarUpdate(container, 3, Math.round(temperature * 100)); + iCrafting.sendProgressBarUpdate(container, 4, Math.round(humidity * 100)); + iCrafting.sendProgressBarUpdate(container, 5, ticksSinceRainfall); + } + + /* ICLIMATISED */ + public float getHydrationModifier() { + return getHydrationTempModifier() * getHydrationHumidModifier() * getHydrationRainfallModifier(); + } + + public float getHydrationTempModifier() { + return temperature > 0.8f ? temperature : 0.8f; + } + + public float getHydrationHumidModifier() { + float mod = 1 / humidity; + return mod < 2.0f ? mod : 2.0f; + } + + public float getHydrationRainfallModifier() { + float mod = (float) ticksSinceRainfall / 24000; + return mod > 0.5f ? mod < RAINFALL_MODIFIER_CAP ? mod : RAINFALL_MODIFIER_CAP : 0.5f; + } + + public double getDrought() { + return Math.round(((double) ticksSinceRainfall / 24000) * 10) / 10.; + } + + @Override + public boolean isClimatized() { + return true; + } + + @Override + public EnumTemperature getTemperature() { + if (EnumTemperature.isBiomeHellish(biomeId)) + return EnumTemperature.HELLISH; + + return EnumTemperature.getFromValue(getExactTemperature()); + } + + @Override + public EnumHumidity getHumidity() { + return EnumHumidity.getFromValue(getExactHumidity()); + } + + @Override + public float getExactTemperature() { + return temperature; + } + + @Override + public float getExactHumidity() { + return humidity; + } + + /* IHINTSOURCE */ + @Override + public boolean hasHints() { + return Config.hints.get("farm").length > 0; + } + + @Override + public String[] getHints() { + return Config.hints.get("farm"); + } + + /* IOWNABLE */ + @Override + public boolean isOwnable() { + return true; + } + +} diff --git a/forestry_common/farming/forestry/farming/gadgets/TileGearbox.java b/forestry_common/farming/forestry/farming/gadgets/TileGearbox.java new file mode 100755 index 000000000..cfbd5e618 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/TileGearbox.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.power.PowerHandler; +import buildcraft.api.power.PowerHandler.PowerReceiver; +import buildcraft.api.power.PowerHandler.Type; + +import forestry.api.core.ITileStructure; +import forestry.api.farming.IFarmHousing; +import forestry.core.GameMode; +import forestry.core.interfaces.IPowerHandler; + +public class TileGearbox extends TileFarm implements IPowerHandler { + + public static int WORK_CYCLES = 4; + public static int MIN_ENERGY_RECEIVED = 5; + public static int MAX_ENERGY_RECEIVED = 20; + public static int MIN_ACTIVATION_ENERGY = 5; + public static int MAX_ENERGY = 1000; + private int activationDelay = 0; + private int previousDelays = 0; + private int workCounter; + + public TileGearbox() { + powerProvider = new PowerHandler(this, Type.MACHINE); + powerProvider.configurePowerPerdition(0, 100); + powerProvider.configure(MIN_ENERGY_RECEIVED, + Math.round(MAX_ENERGY_RECEIVED * GameMode.getGameMode().getFloatSetting("energy.demand.modifier")), + Math.round(MIN_ACTIVATION_ENERGY * GameMode.getGameMode().getFloatSetting("energy.demand.modifier")), + Math.round(MAX_ENERGY * GameMode.getGameMode().getFloatSetting("energy.demand.modifier"))); + + fixedType = TYPE_GEARS; + } + + @Override + protected void createInventory() { + } + + @Override + public boolean hasFunction() { + return true; + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + powerProvider.readFromNBT(nbttagcompound); + + activationDelay = nbttagcompound.getInteger("ActivationDelay"); + previousDelays = nbttagcompound.getInteger("PrevDelays"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + powerProvider.writeToNBT(nbttagcompound); + + nbttagcompound.setInteger("ActivationDelay", activationDelay); + nbttagcompound.setInteger("PrevDelays", previousDelays); + } + + /* IPOWERRECEPTOR */ + PowerHandler powerProvider; + + @Override + public PowerReceiver getPowerReceiver(ForgeDirection side) { + return powerProvider.getPowerReceiver(); + } + + @Override + public PowerHandler getPowerHandler() { + return powerProvider; + } + + @Override + protected void updateServerSide() { + super.updateServerSide(); + + if (activationDelay > 0) { + activationDelay--; + return; + } + + if (workCounter >= WORK_CYCLES && worldObj.getTotalWorldTime() % 5 == 0) { + ITileStructure central = getCentralTE(); + if (!(central instanceof IFarmHousing)) + return; + + if (((IFarmHousing) central).doWork()) { + workCounter = 0; + previousDelays = 0; + } else { + // If the central TE doesn't have work, we add to the activation delay to throttle the CPU usage. + activationDelay = 10 * previousDelays < 120 ? 10 * previousDelays : 120; + previousDelays++; // First delay is free! + } + } + } + + @Override + public void doWork(PowerHandler workProvider) { + // Hard limit to 4 cycles / second. + if (workCounter < WORK_CYCLES) { + powerProvider.useEnergy(MIN_ACTIVATION_ENERGY, MIN_ACTIVATION_ENERGY, true); + workCounter++; + } + } +} diff --git a/forestry_common/farming/forestry/farming/gadgets/TileHatch.java b/forestry_common/farming/forestry/farming/gadgets/TileHatch.java new file mode 100755 index 000000000..00cbe06a9 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/TileHatch.java @@ -0,0 +1,339 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import java.util.ArrayList; +import java.util.LinkedList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidContainerRegistry; + +import buildcraft.api.gates.ITrigger; + +import forestry.api.core.ITileStructure; +import forestry.core.utils.BlockUtil; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; +import forestry.plugins.PluginFarming; + +public class TileHatch extends TileFarm implements ISidedInventory { + + public TileHatch() { + fixedType = TYPE_HATCH; + } + + @Override + public boolean hasFunction() { + return true; + } + + @Override + protected void createInventory() { + } + + @Override + protected void updateServerSide() { + if (worldObj.getTotalWorldTime() % 40 == 0) + dumpStash(); + } + + /* AUTO-EJECTING */ + protected void dumpStash() { + + if (!hasMaster()) + return; + + ArrayList pipes = new ArrayList(); + ForgeDirection[] tmp = BlockUtil.getPipeDirections(worldObj, Coords(), ForgeDirection.UP); + for (int i = 0; i < tmp.length; ++i) { + pipes.add(tmp[i]); + } + + if (pipes.size() > 0) + dumpToPipe(pipes); + else { + IInventory[] inventories = BlockUtil.getAdjacentInventories(worldObj, Coords(), ForgeDirection.UP); + dumpToInventory(inventories); + } + } + + private void dumpToPipe(ArrayList pipes) { + + ItemStack[] products = extractItem(true, ForgeDirection.DOWN, 1); + for (int i = 0; i < products.length; i++) + while (products[i].stackSize > 0) + BlockUtil.putFromStackIntoPipe(this, pipes, products[i]); + + } + + private void dumpToInventory(IInventory[] inventories) { + + ITileStructure central = getCentralTE(); + if (central == null) + return; + IInventory inv = central.getInventory(); + + for (int i = TileFarmPlain.SLOT_PRODUCTION_1; i < TileFarmPlain.SLOT_PRODUCTION_1 + TileFarmPlain.SLOT_COUNT_PRODUCTION; i++) { + if (inv.getStackInSlot(i) == null) + continue; + + ItemStack stack = inv.getStackInSlot(i); + + if (stack.stackSize <= 0) + continue; + + for (int j = 0; j < inventories.length; j++) { + + // Don't dump in arboretums! + if (inventories[j].getSizeInventory() < 4) + continue; + + // Get complete inventory (for double chests) + IInventory inventory = Utils.getChest(inventories[j]); + if (inventory instanceof ISidedInventory) { + ISidedInventory sidedInventory = (ISidedInventory)inventory; + int[] slots = sidedInventory.getAccessibleSlotsFromSide(ForgeDirection.UP.ordinal()); + for (int sl = 0; sl < slots.length; ++sl) { + StackUtils.stowInInventory(stack, sidedInventory, true, sl, 1); + } + } + else { + StackUtils.stowInInventory(stack, inventory, true); + if (stack.stackSize <= 0) { + inv.setInventorySlotContents(i, null); + break; + } + } + } + } + + } + + /* IINVENTORY */ + @Override + public InventoryAdapter getInternalInventory() { + return (InventoryAdapter)getStructureInventory(); + } + + private IInventory getStructureInventory() { + + if (hasMaster()) { + ITileStructure central = getCentralTE(); + if (central != null) + return central.getInventory(); + } + + return null; + } + + @Override + public int getSizeInventory() { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getSizeInventory(); + else + return 0; + } + + @Override + public ItemStack getStackInSlot(int slotIndex) { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getStackInSlot(slotIndex); + else + return null; + } + + @Override + public ItemStack decrStackSize(int slotIndex, int amount) { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.decrStackSize(slotIndex, amount); + else + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int slotIndex) { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getStackInSlotOnClosing(slotIndex); + else + return null; + } + + @Override + public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { + IInventory inv = getStructureInventory(); + if (inv != null) + inv.setInventorySlotContents(slotIndex, itemstack); + } + + @Override + public int getInventoryStackLimit() { + IInventory inv = getStructureInventory(); + if (inv != null) + return inv.getInventoryStackLimit(); + else + return 0; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex >= TileFarmPlain.SLOT_PRODUCTION_1 && slotIndex < TileFarmPlain.SLOT_PRODUCTION_1 + TileFarmPlain.SLOT_COUNT_PRODUCTION) + return true; + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if (!hasMaster()) + return false; + + ITileStructure struct = getCentralTE(); + if (!(struct instanceof TileFarmPlain)) + return false; + + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + TileFarmPlain housing = (TileFarmPlain) struct; + if (slotIndex == TileFarmPlain.SLOT_FERTILIZER && housing.acceptsAsFertilizer(itemstack)) + return true; + if (slotIndex >= TileFarmPlain.SLOT_RESOURCES_1 && slotIndex < TileFarmPlain.SLOT_RESOURCES_1 + TileFarmPlain.SLOT_COUNT_RESERVOIRS + && housing.acceptsAsResource(itemstack)) + return true; + if (slotIndex >= TileFarmPlain.SLOT_GERMLINGS_1 && slotIndex < TileFarmPlain.SLOT_GERMLINGS_1 + TileFarmPlain.SLOT_COUNT_RESERVOIRS + && housing.acceptsAsGermling(itemstack)) + return true; + if(slotIndex == TileFarmPlain.SLOT_CAN) + return FluidContainerRegistry.isFilledContainer(itemstack); + + return false; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + + IInventory inv; + if (hasMaster()) { + ITileStructure central = getCentralTE(); + if (central == null) + return new ItemStack[0]; + inv = getCentralTE().getInventory(); + } else + return StackUtils.EMPTY_STACK_ARRAY; + + ItemStack product = null; + + for (int i = TileFarmPlain.SLOT_PRODUCTION_1; i < TileFarmPlain.SLOT_PRODUCTION_1 + TileFarmPlain.SLOT_COUNT_PRODUCTION; i++) { + if (inv.getStackInSlot(i) == null) + continue; + + ItemStack stack = inv.getStackInSlot(i); + + if (doRemove) + product = inv.decrStackSize(i, 1); + else { + product = stack.copy(); + product.stackSize = 1; + } + break; + } + + if (product != null) + return new ItemStack[] { product }; + else + return StackUtils.EMPTY_STACK_ARRAY; + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + if (!hasMaster()) + return null; + + LinkedList list = new LinkedList(); + list.add(PluginFarming.lowResourceLiquid50); + list.add(PluginFarming.lowResourceLiquid25); + list.add(PluginFarming.lowSoil128); + list.add(PluginFarming.lowSoil64); + list.add(PluginFarming.lowSoil32); + list.add(PluginFarming.lowFertilizer50); + list.add(PluginFarming.lowFertilizer25); + return list; + } + +} diff --git a/forestry_common/farming/forestry/farming/gadgets/TileValve.java b/forestry_common/farming/forestry/farming/gadgets/TileValve.java new file mode 100755 index 000000000..50e9494a1 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gadgets/TileValve.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gadgets; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import forestry.core.interfaces.ILiquidTankContainer; +import forestry.core.utils.ForestryTank; + +public class TileValve extends TileFarm implements ILiquidTankContainer { + + public TileValve() { + fixedType = TYPE_VALVE; + } + + /* TILEFARM */ + @Override + public boolean hasFunction() { + return true; + } + + @Override + protected void createInventory() { + } + + /* ILIQUIDTANKCONTAINER */ + private ForestryTank getMasterTank() { + if (!isIntegratedIntoStructure() || !hasMaster()) + return null; + + TileFarmPlain central = (TileFarmPlain) getCentralTE(); + if (central == null) + return null; + + return central.getTank(); + } + + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + ForestryTank tank = getMasterTank(); + if (tank == null) + return 0; + + return tank.fill(resource, doFill); + } + + @Override + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + ForestryTank tank = getMasterTank(); + if (tank == null) + return null; + + return tank.drain(maxDrain, doDrain); + } + + @Override + public ForestryTank[] getTanks() { + ForestryTank tank = getMasterTank(); + if (tank == null) + return ForestryTank.FAKETANK_ARRAY; + + return new ForestryTank[] { tank }; + } + +} diff --git a/forestry_common/farming/forestry/farming/gui/ContainerFarm.java b/forestry_common/farming/forestry/farming/gui/ContainerFarm.java new file mode 100755 index 000000000..ea36e3f17 --- /dev/null +++ b/forestry_common/farming/forestry/farming/gui/ContainerFarm.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gui; + + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.farming.IFarmLogic; +import forestry.core.gui.ContainerSocketed; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.gui.slots.SlotForestry; +import forestry.core.gui.slots.SlotLiquidContainer; +import forestry.core.gui.slots.SlotOutput; +import forestry.core.network.PacketTankUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryTank; +import forestry.core.utils.TileInventoryAdapter; +import forestry.farming.gadgets.TileFarmPlain; +import forestry.plugins.PluginFarming; + +public class ContainerFarm extends ContainerSocketed { + + private class SlotResources extends SlotForestry { + + private final IFarmLogic[] logics; + + public SlotResources(IInventory inventory, IFarmLogic[] logics, int slotIndex, int xPos, int yPos) { + super(inventory, slotIndex, xPos, yPos); + this.logics = logics; + } + + @Override + public boolean isItemValid(ItemStack stack) { + for (IFarmLogic logic : logics) { + if (logic != null && logic.isAcceptedResource(stack)) + return true; + } + return false; + } + } + + private class SlotGermlings extends SlotForestry { + + private final IFarmLogic[] logics; + + public SlotGermlings(IInventory inventory, IFarmLogic[] logics, int slotIndex, int xPos, int yPos) { + super(inventory, slotIndex, xPos, yPos); + this.logics = logics; + } + + @Override + public boolean isItemValid(ItemStack stack) { + for (IFarmLogic logic : logics) { + if (logic != null && logic.isAcceptedGermling(stack)) + return true; + } + return false; + } + } + TileFarmPlain tile; + + public ContainerFarm(InventoryPlayer playerinventory, TileFarmPlain tile) { + super(playerinventory, tile); + + this.tile = tile; + + IInventory inventory = tile.getInventory(); + // Tile will not have an inventory client side. + if (inventory == null) + inventory = new TileInventoryAdapter(tile, TileFarmPlain.SLOT_COUNT, "Items"); + + // Resources + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + addSlot(new SlotResources(inventory, tile.getFarmLogics(), TileFarmPlain.SLOT_RESOURCES_1 + j + i * 2, 123 + j * 18, 22 + i * 18)); + } + } + + // Germlings + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + addSlot(new SlotGermlings(inventory, tile.getFarmLogics(), TileFarmPlain.SLOT_GERMLINGS_1 + j + i * 2, 164 + j * 18, 22 + i * 18)); + } + } + + // Production 1 + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + addSlot(new SlotOutput(inventory, TileFarmPlain.SLOT_PRODUCTION_1 + j + i * 2, 123 + j * 18, 86 + i * 18)); + } + } + + // Production 2 + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + addSlot(new SlotOutput(inventory, TileFarmPlain.SLOT_PRODUCTION_1 + 4 + j + i * 2, 164 + j * 18, 86 + i * 18)); + } + } + + // Fertilizer + addSlot(new SlotCustom(inventory, TileFarmPlain.SLOT_FERTILIZER, 63, 95, PluginFarming.farmFertilizer)); + // Can Slot + addSlot(new SlotLiquidContainer(inventory, TileFarmPlain.SLOT_CAN, 15, 95)); + + // Player inventory + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 9; j++) { + addSlot(new Slot(playerinventory, j + i * 9 + 9, 28 + j * 18, 138 + i * 18)); + } + } + // Player hotbar + for (int i = 0; i < 9; i++) { + addSlot(new Slot(playerinventory, i, 28 + i * 18, 196)); + } + } + + @Override + public void updateProgressBar(int i, int j) { + tile.getGUINetworkData(i, j); + } + private Map syncedFluids = new HashMap(); + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + for (int i = 0; i < crafters.size(); i++) { + tile.sendGUINetworkData(this, (ICrafting) crafters.get(i)); + } + + ForestryTank tank = tile.getTank(); + + // If null has been synced + if (tank.getFluid() == null && getTank(0).getFluidAmount() <= 0) + return; + // If fluid has been synced + if (tank.getFluid() != null && tank.getFluid().isFluidStackIdentical(getTank(0).getFluid())) + return; + + for (int j = 0; j < this.crafters.size(); ++j) { + if (this.crafters.get(j) instanceof EntityPlayerMP) { + EntityPlayerMP player = (EntityPlayerMP) this.crafters.get(j); + Proxies.net.sendToPlayer(new PacketTankUpdate(0, tank), player); + } + } + syncedFluids.put(0, new ForestryTank(tank.getFluid() == null ? null : tank.getFluid().copy(), tank.getCapacity())); + + } + + @Override + public void onTankUpdate(NBTTagCompound nbt) { + int tankID = nbt.getByte("tank"); + int capacity = nbt.getShort("capacity"); + ForestryTank tank = new ForestryTank(capacity); + tank.readFromNBT(nbt); + syncedFluids.put(tankID, tank); + } + + @Override + public ForestryTank getTank(int slot) { + return syncedFluids.get(slot) == null ? ForestryTank.FAKETANK : syncedFluids.get(slot); + } +} diff --git a/forestry_common/farming/forestry/farming/gui/GuiFarm.java b/forestry_common/farming/forestry/farming/gui/GuiFarm.java new file mode 100755 index 000000000..2b688f69c --- /dev/null +++ b/forestry_common/farming/forestry/farming/gui/GuiFarm.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.util.IIcon; + +import org.lwjgl.opengl.GL11; + +import forestry.api.farming.IFarmLogic; +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.Ledger; +import forestry.core.gui.WidgetManager; +import forestry.core.gui.tooltips.ToolTip; +import forestry.core.gui.widgets.SocketWidget; +import forestry.core.gui.widgets.TankWidget; +import forestry.core.gui.widgets.Widget; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StringUtil; +import forestry.farming.gadgets.TileFarmPlain; + +public class GuiFarm extends GuiForestry { + + protected class FarmLedger extends Ledger { + + public FarmLedger() { + super(ledgerManager); + maxHeight = 118; + overlayColor = fontColor.get("ledger.farm.background"); + } + + @Override + public void draw(int x, int y) { + + // Draw background + drawBackground(x, y); + + // Draw icon + drawIcon(Items.water_bucket.getIconFromDamage(0), x + 3, y + 4); + + if (!isFullyOpened()) + return; + + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.hydration"), x + 22, y + 8, fontColor.get("ledger.power.header")); + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.hydr.heat") + ":", x + 22, y + 20, fontColor.get("ledger.power.subheader")); + fontRendererObj.drawString(StringUtil.floatAsPercent(farm.getHydrationTempModifier()), x + 22, y + 32, fontColor.get("ledger.power.text")); + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.hydr.humid") + ":", x + 22, y + 44, fontColor.get("ledger.power.subheader")); + fontRendererObj.drawString(StringUtil.floatAsPercent(farm.getHydrationHumidModifier()), x + 22, y + 56, fontColor.get("ledger.power.text")); + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.hydr.rainfall") + ":", x + 22, y + 68, fontColor.get("ledger.power.subheader")); + fontRendererObj.drawString(StringUtil.floatAsPercent(farm.getHydrationRainfallModifier()) + " (" + farm.getDrought() + " d)", x + 22, y + 80, + fontColor.get("ledger.power.text")); + fontRendererObj.drawStringWithShadow(StringUtil.localize("gui.hydr.overall") + ":", x + 22, y + 92, fontColor.get("ledger.power.subheader")); + fontRendererObj.drawString(StringUtil.floatAsPercent(farm.getHydrationModifier()), x + 22, y + 104, fontColor.get("ledger.power.text")); + + } + + @Override + public String getTooltip() { + return StringUtil.floatAsPercent(farm.getHydrationModifier()) + " " + StringUtil.localize("gui.hydration"); + } + } + + private class FarmLogicSlot extends Widget { + + private final int slot; + + public FarmLogicSlot(WidgetManager manager, int xPos, int yPos, int slot) { + super(manager, xPos, yPos); + this.slot = slot; + } + + private IFarmLogic getLogic() { + return farm.getFarmLogics()[slot]; + } + + private IIcon getIconIndex() { + if (getLogic() == null) + return null; + return getLogic().getIcon(); + } + + @Override + public void draw(int startX, int startY) { + if (getLogic() == null) + return; + + if (getIconIndex() != null) { + GL11.glDisable(GL11.GL_LIGHTING); + Proxies.common.bindTexture(getLogic().getSpriteSheet()); + manager.gui.drawTexturedModelRectFromIcon(startX + xPos, startY + yPos, getIconIndex(), 16, 16); + GL11.glEnable(GL11.GL_LIGHTING); + } + + } + + @Override + public ToolTip getToolTip() { + return toolTip; + } + protected final ToolTip toolTip = new ToolTip(250) { + @Override + public void refresh() { + toolTip.clear(); + if (getLogic() == null) + return; + toolTip.add(getLogic().getName()); + toolTip.add("Fertilizer: " + getLogic().getFertilizerConsumption()); + toolTip.add("Water: " + getLogic().getWaterConsumption(farm.getHydrationModifier())); + } + }; + } + private final TileFarmPlain farm; + + public GuiFarm(EntityPlayer player, TileFarmPlain tile) { + super(Defaults.TEXTURE_PATH_GUI + "/mfarm.png", new ContainerFarm(player.inventory, tile), tile); + + widgetManager.add(new TankWidget(widgetManager, 15, 19, 0).setOverlayOrigin(216, 18)); + + widgetManager.add(new SocketWidget(widgetManager, 69, 40, tile, 0)); + + widgetManager.add(new FarmLogicSlot(widgetManager, 69, 22, 0)); + widgetManager.add(new FarmLogicSlot(widgetManager, 69, 58, 1)); + widgetManager.add(new FarmLogicSlot(widgetManager, 51, 40, 2)); + widgetManager.add(new FarmLogicSlot(widgetManager, 87, 40, 3)); + + this.xSize = 216; + this.ySize = 220; + this.tile = tile; + this.farm = tile; + } + + @Override + protected void initLedgers(Object inventory) { + super.initLedgers(inventory); + ledgerManager.insert(new FarmLedger()); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String title = StringUtil.localize("Farm"); + this.fontRendererObj.drawString(title, getCenteredOffset(title), 6, fontColor.get("gui.title")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + // Fuel remaining + int fertilizerRemain = tile.getStoredFertilizerScaled(16); + if (fertilizerRemain > 0) + drawTexturedModalRect(guiLeft + 81, guiTop + 94 + 17 - fertilizerRemain, xSize, 17 - fertilizerRemain, 4, fertilizerRemain); + + } +} diff --git a/forestry_common/farming/forestry/farming/items/ItemFarmBlock.java b/forestry_common/farming/forestry/farming/items/ItemFarmBlock.java new file mode 100755 index 000000000..1c9d0e271 --- /dev/null +++ b/forestry_common/farming/forestry/farming/items/ItemFarmBlock.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.items; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +import forestry.core.gadgets.IStructureBlockItem; +import forestry.core.utils.StringUtil; +import forestry.farming.gadgets.TileFarm.EnumFarmBlock; + +public class ItemFarmBlock extends ItemBlock implements IStructureBlockItem { + public ItemFarmBlock(Block block) { + super(block); + setHasSubtypes(true); + } + + @Override + public int getMetadata(int i) { + return i; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List info, boolean par4) { + if (!itemstack.hasTagCompound()) + return; + + info.add(EnumFarmBlock.getFromCompound(itemstack.getTagCompound()).getName()); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize(getUnlocalizedName(itemstack)); + } + + @Override + public String getUnlocalizedName(ItemStack itemstack) { + return "tile.ffarm." + itemstack.getItemDamage(); + } +} diff --git a/forestry_common/farming/forestry/farming/logic/Crop.java b/forestry_common/farming/forestry/farming/logic/Crop.java new file mode 100755 index 000000000..460711a08 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/Crop.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.core.config.Defaults; +import forestry.core.utils.Vect; + +public abstract class Crop implements ICrop { + + protected World world; + protected Vect position; + + public Crop(World world, Vect position) { + this.world = world; + this.position = position; + } + + protected final void setBlock(Vect position, Block block, int meta) { + world.setBlock(position.x, position.y, position.z, block, meta, Defaults.FLAG_BLOCK_SYNCH); + } + + protected final void clearBlock(Vect position) { + world.setBlockToAir(position.x, position.y, position.z); + if (world.getTileEntity(position.x, position.y, position.z) != null) + world.setTileEntity(position.x, position.y, position.z, null); + } + + protected final Block getBlock(Vect position) { + return world.getBlock(position.x, position.y, position.z); + } + + protected final int getBlockMeta(Vect position) { + return world.getBlockMetadata(position.x, position.y, position.z); + } + + protected final ItemStack getAsItemStack(Vect position) { + return new ItemStack(getBlock(position), 1, getBlockMeta(position)); + } + + protected abstract boolean isCrop(Vect pos); + + protected abstract Collection harvestBlock(Vect pos); + + @Override + public Collection harvest() { + if (!isCrop(position)) + return null; + + return harvestBlock(position); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/CropBlock.java b/forestry_common/farming/forestry/farming/logic/CropBlock.java new file mode 100755 index 000000000..7339374f1 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/CropBlock.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.core.proxy.Proxies; +import forestry.core.utils.Vect; + +public class CropBlock extends Crop { + + Block block; + int meta; + + public CropBlock(World world, Block block, int meta, Vect position) { + super(world, position); + this.block = block; + this.meta = meta; + } + + @Override + protected boolean isCrop(Vect pos) { + return getBlock(pos) == block && getBlockMeta(pos) == meta; + } + + @Override + protected Collection harvestBlock(Vect pos) { + Collection harvested = block.getDrops(world, pos.x, pos.y, pos.z, meta, 0); + Proxies.common.addBlockDestroyEffects(world, pos.x, pos.y, pos.z, block, 0); + // Block.breakBlock() is called by vanilla itself, removing TEs. + world.setBlockToAir(pos.x, pos.y, pos.z); + return harvested; + } + + @Override + public String toString() { + return String.format("CropBlock [ position: [ %s ]; block: %s; meta: %s ]", position.toString(), block.getUnlocalizedName(), meta); + } +} diff --git a/forestry_common/farming/forestry/farming/logic/CropFruit.java b/forestry_common/farming/forestry/farming/logic/CropFruit.java new file mode 100755 index 000000000..b328dbcc5 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/CropFruit.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import forestry.api.genetics.IFruitBearer; +import forestry.api.genetics.IFruitFamily; +import forestry.core.network.PacketFXSignal; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Vect; + +public class CropFruit extends Crop { + + IFruitFamily family; + + public CropFruit(World world, Vect position, IFruitFamily family) { + super(world, position); + this.family = family; + } + + @Override + protected boolean isCrop(Vect pos) { + TileEntity tile = world.getTileEntity(pos.x, pos.y, pos.z); + if (!(tile instanceof IFruitBearer)) + return false; + IFruitBearer bearer = (IFruitBearer) tile; + if (!bearer.hasFruit()) + return false; + if (bearer.getRipeness() < 0.9f) + return false; + + return true; + } + + @Override + protected Collection harvestBlock(Vect pos) { + TileEntity tile = world.getTileEntity(pos.x, pos.y, pos.z); + if (!(tile instanceof IFruitBearer)) + return new ArrayList(); + + Proxies.common.sendFXSignal(PacketFXSignal.VisualFXType.BLOCK_DESTROY, PacketFXSignal.SoundFXType.LEAF, world, pos.x, pos.y, pos.z, + world.getBlock(pos.x, pos.y, pos.z), 0); + return ((IFruitBearer) tile).pickFruit(null); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/CropPeat.java b/forestry_common/farming/forestry/farming/logic/CropPeat.java new file mode 100755 index 000000000..c88dc1ab3 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/CropPeat.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Vect; + +public class CropPeat extends Crop { + + public CropPeat(World world, Vect position) { + super(world, position); + } + + @Override + protected boolean isCrop(Vect pos) { + return getBlock(pos) == ForestryBlock.soil && (getBlockMeta(pos) & 0x03) == 1; + } + + @Override + protected Collection harvestBlock(Vect pos) { + ArrayList list = new ArrayList(); + list.add(ForestryItem.peat.getItemStack()); + + Proxies.common.addBlockDestroyEffects(world, pos.x, pos.y, pos.z, world.getBlock(pos.x, pos.y, pos.z), 0); + setBlock(pos, Blocks.dirt, 0); + return list; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/CropRubber.java b/forestry_common/farming/forestry/farming/logic/CropRubber.java new file mode 100755 index 000000000..4e4c635d0 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/CropRubber.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.core.config.Defaults; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Vect; +import forestry.plugins.PluginIC2; + +public class CropRubber extends CropBlock { + + public CropRubber(World world, Block block, int meta, Vect position) { + super(world, block, meta, position); + } + + @Override + protected Collection harvestBlock(Vect pos) { + Collection harvested = new ArrayList(); + harvested.add(PluginIC2.resin.copy()); + Proxies.common.addBlockDestroyEffects(world, pos.x, pos.y, pos.z, block, 0); + world.setBlock(pos.x, pos.y, pos.z, block, meta + 6, Defaults.FLAG_BLOCK_SYNCH); + return harvested; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogic.java b/forestry_common/farming/forestry/farming/logic/FarmLogic.java new file mode 100755 index 000000000..12c35c862 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogic.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmLogic; +import forestry.core.config.Defaults; +import forestry.core.render.SpriteSheet; +import forestry.core.utils.Vect; + +public abstract class FarmLogic implements IFarmLogic { + + World world; + IFarmHousing housing; + + boolean isManual; + + public FarmLogic(IFarmHousing housing) { + this.housing = housing; + } + + public FarmLogic setManual(boolean flag) { + isManual = flag; + return this; + } + + @Override + public ResourceLocation getSpriteSheet() { + return SpriteSheet.ITEMS.getLocation(); + } + + protected final boolean isAirBlock(Vect position) { + return world.isAirBlock(position.x, position.y, position.z); + } + + protected final boolean isWaterBlock(Vect position) { + return world.getBlock(position.x, position.y, position.z) == Blocks.water; + } + + protected final boolean isWoodBlock(Vect position) { + Block block = getBlock(position); + return block.isWood(world, position.x, position.y, position.z); + } + + protected final Block getBlock(Vect position) { + return world.getBlock(position.x, position.y, position.z); + } + + protected final int getBlockMeta(Vect position) { + return world.getBlockMetadata(position.x, position.y, position.z); + } + + protected final ItemStack getAsItemStack(Vect position) { + return new ItemStack(getBlock(position), 1, getBlockMeta(position)); + } + + protected final Vect translateWithOffset(int x, int y, int z, ForgeDirection direction, int step) { + return new Vect(x + direction.offsetX * step, y + direction.offsetY * step, z + direction.offsetZ * step); + } + + protected final void setBlock(Vect position, Block block, int meta) { + world.setBlock(position.x, position.y, position.z, block, meta, Defaults.FLAG_BLOCK_SYNCH); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicArboreal.java b/forestry_common/farming/forestry/farming/logic/FarmLogicArboreal.java new file mode 100755 index 000000000..2a4f14ddf --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicArboreal.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Stack; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.Farmables; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.render.SpriteSheet; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; + +public class FarmLogicArboreal extends FarmLogicHomogenous { + + public FarmLogicArboreal(IFarmHousing housing, ItemStack[] resource, ItemStack[] ground, ItemStack[] waste, IFarmable[] germlings) { + super(housing, resource, ground, waste, germlings); + } + + public FarmLogicArboreal(IFarmHousing housing) { + super(housing, new ItemStack[] { new ItemStack(Blocks.dirt) }, new ItemStack[] { new ItemStack(ForestryBlock.soil, 1, 0), + new ItemStack(ForestryBlock.soil, 1, Defaults.WILDCARD) }, new ItemStack[] { new ItemStack(Blocks.sand) }, Farmables.farmables.get( + "farmArboreal").toArray(new IFarmable[0])); + } + + @Override + public String getName() { + return "Managed Arboretum"; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Blocks.sapling.getBlockTextureFromSide(0); + } + + @Override + public ResourceLocation getSpriteSheet() { + return SpriteSheet.BLOCKS.getLocation(); + } + + @Override + public int getFertilizerConsumption() { + return 10; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (10 * hydrationModifier); + } + + @SuppressWarnings("unchecked") + @Override + public Collection collect() { + + Collection products = produce; + produce = new ArrayList(); + + Vect coords = new Vect(housing.getCoords()); + Vect area = new Vect(housing.getArea()); + Vect offset = new Vect(housing.getOffset()); + + Vect min = coords.add(offset); + Vect max = coords.add(offset).add(area); + + AxisAlignedBB harvestBox = AxisAlignedBB.getBoundingBox(min.x, min.y, min.z, max.x, max.y, max.z); + List list = housing.getWorld().getEntitiesWithinAABB(Entity.class, harvestBox); + + int i; + for (i = 0; i < list.size(); i++) { + Entity entity = list.get(i); + + if (entity instanceof EntityItem) { + EntityItem item = (EntityItem) entity; + if (!item.isDead) { + ItemStack contained = item.getEntityItem(); + if (isAcceptedGermling(contained) || isWindfall(contained)) { + produce.add(contained.copy()); + item.setDead(); + } + } + } + } + + return products; + } + + private final HashMap lastExtentsHarvest = new HashMap(); + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Collection crops = null; + + Vect start = new Vect(x, y, z); + if (!lastExtentsHarvest.containsKey(start)) + lastExtentsHarvest.put(start, 0); + + int lastExtent = lastExtentsHarvest.get(start); + if (lastExtent > extent) + lastExtent = 0; + + Vect position = translateWithOffset(x, y + 1, z, direction, lastExtent); + crops = getHarvestBlocks(position); + lastExtent++; + lastExtentsHarvest.put(start, lastExtent); + + return crops; + } + + private Collection getHarvestBlocks(Vect position) { + + ArrayList seen = new ArrayList(); + Stack crops = new Stack(); + + // Determine what type we want to harvest. + IFarmable germling = null; + for (IFarmable germl : germlings) { + ICrop crop = germl.getCropAt(world, position.x, position.y, position.z); + if (crop == null) + continue; + + crops.push(crop); + seen.add(position); + germling = germl; + break; + } + + if (germling == null) + return crops; + + ArrayList candidates = processHarvestBlock(germling, crops, seen, position, position); + ArrayList temp = new ArrayList(); + while (!candidates.isEmpty()) { + for (Vect candidate : candidates) + temp.addAll(processHarvestBlock(germling, crops, seen, position, candidate)); + candidates.clear(); + candidates.addAll(temp); + temp.clear(); + } + + return crops; + } + + protected int yOffset = 0; + + private ArrayList processHarvestBlock(IFarmable germling, Stack crops, Collection seen, Vect start, Vect position) { + + ArrayList candidates = new ArrayList(); + + // Get additional candidates to return + for (int i = -1; i < 2; i++) + for (int j = yOffset; j < 2; j++) + for (int k = -1; k < 2; k++) { + Vect candidate = new Vect(position.x + i, position.y + j, position.z + k); + if (candidate.equals(position)) + continue; + if (Math.abs(candidate.x - start.x) > 5) + continue; + if (Math.abs(candidate.z - start.z) > 5) + continue; + + // See whether the given position has already been processed + boolean skip = false; + for (Vect prcs : seen) + if (candidate.equals(prcs)) { + skip = true; + break; + } + + if (skip) + continue; + + ICrop crop = germling.getCropAt(world, candidate.x, candidate.y, candidate.z); + if (crop != null) { + crops.push(crop); + candidates.add(candidate); + seen.add(candidate); + } + } + + return candidates; + } + + @Override + protected boolean maintainGermlings(int x, int ySaplings, int z, ForgeDirection direction, int extent) { + + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, ySaplings, z, direction, i); + + if (isAirBlock(position)) { + //ForgeDirection reverse = direction.getOpposite(); + Vect soilBelow = new Vect(position.x, position.y - 1, position.z); + //Vect soilPrevious = new Vect(position.x * reverse.offsetX, position.y - 1, position.z * reverse.offsetZ); + for (ItemStack grnd : ground) { + if(StackUtils.isIdenticalItem(grnd, getAsItemStack(soilBelow))) + return plantSapling(position); + } + //if (!ground[0].itemID == getAsItemStack(soilPrevious).itemID && ground[0].itemID == getAsItemStack(soilBelow).itemID) + + //if (ground[0].isItemEqual(getAsItemStack(soilBelow))) + // return plantSapling(position); + } + + } + + return false; + } + + private boolean plantSapling(Vect position) { + + for (IFarmable candidate : germlings) + if (housing.plantGermling(candidate, world, position.x, position.y, position.z)) + return true; + + return false; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicCereal.java b/forestry_common/farming/forestry/farming/logic/FarmLogicCereal.java new file mode 100755 index 000000000..fc40135d8 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicCereal.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.init.Items; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.farming.Farmables; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; + +public class FarmLogicCereal extends FarmLogicCrops { + + public FarmLogicCereal(IFarmHousing housing) { + super(housing, Farmables.farmables.get("farmWheat").toArray(new IFarmable[0])); + } + + @Override + public String getName() { + if (isManual) + return "Manual Farm"; + else + return "Managed Farm"; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Items.wheat.getIconFromDamage(0); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicCocoa.java b/forestry_common/farming/forestry/farming/logic/FarmLogicCocoa.java new file mode 100755 index 000000000..a9eac6c82 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicCocoa.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Stack; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockLog; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.utils.Vect; + +public class FarmLogicCocoa extends FarmLogic { + + private final IFarmable cocoa = new FarmableCocoa(); + + public FarmLogicCocoa(IFarmHousing housing) { + super(housing); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Items.dye.getIconFromDamage(3); + } + + @Override + public String getName() { + return "Cocoa Plantation"; + } + + @Override + public int getFertilizerConsumption() { + return 120; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (20 * hydrationModifier); + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + return false; + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + return cocoa.isGermling(itemstack); + } + + @Override + public Collection collect() { + return null; + } + + private final HashMap lastExtentsCultivation = new HashMap(); + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Vect start = new Vect(x, y, z); + if (!lastExtentsCultivation.containsKey(start)) + lastExtentsCultivation.put(start, 0); + + int lastExtent = lastExtentsCultivation.get(start); + if (lastExtent > extent) + lastExtent = 0; + + Vect position = translateWithOffset(x, y + 1, z, direction, lastExtent); + boolean result = tryPlantingCocoa(position); + + lastExtent++; + lastExtentsCultivation.put(start, lastExtent); + + return result; + } + + private final HashMap lastExtentsHarvest = new HashMap(); + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Collection crops = null; + + Vect start = new Vect(x, y, z); + if (!lastExtentsHarvest.containsKey(start)) + lastExtentsHarvest.put(start, 0); + + int lastExtent = lastExtentsHarvest.get(start); + if (lastExtent > extent) + lastExtent = 0; + + Vect position = translateWithOffset(x, y + 1, z, direction, lastExtent); + crops = getHarvestBlocks(position); + lastExtent++; + lastExtentsHarvest.put(start, lastExtent); + + return crops; + } + + private boolean tryPlantingCocoa(Vect position) { + + Vect current = position; + while (isWoodBlock(current) && BlockLog.func_150165_c(getBlockMeta(current)) == 3) { + + for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { + if (direction == ForgeDirection.UP || direction == ForgeDirection.DOWN) + continue; + + Vect candidate = new Vect(current.x + direction.offsetX, current.y, current.z + direction.offsetZ); + if (isAirBlock(candidate)) + return housing.plantGermling(cocoa, world, candidate.x, candidate.y, candidate.z); + } + + current = current.add(new Vect(0, 1, 0)); + if (current.y - position.y > 1) + break; + } + + return false; + } + + private Collection getHarvestBlocks(Vect position) { + + ArrayList seen = new ArrayList(); + Stack crops = new Stack(); + + // Determine what type we want to harvest. + Block block = getBlock(position); + + ICrop crop = null; + if (!block.isWood(world, position.x, position.y, position.z)) { + crop = cocoa.getCropAt(world, position.x, position.y, position.z); + if (crop == null) + return crops; + } + + if (crop != null) + crops.add(crop); + + ArrayList candidates = processHarvestBlock(crops, seen, position, position); + ArrayList temp = new ArrayList(); + while (!candidates.isEmpty() && crops.size() < 20) { + for (Vect candidate : candidates) + temp.addAll(processHarvestBlock(crops, seen, position, candidate)); + candidates.clear(); + candidates.addAll(temp); + temp.clear(); + } + // Proxies.log.finest("Logic %s at %s/%s/%s has seen %s blocks.", getClass().getName(), position.x, position.y, position.z, seen.size()); + + return crops; + } + + private ArrayList processHarvestBlock(Stack crops, Collection seen, Vect start, Vect position) { + + ArrayList candidates = new ArrayList(); + + // Get additional candidates to return + for (int i = -1; i < 2; i++) + for (int j = 0; j < 2; j++) + for (int k = -1; k < 2; k++) { + Vect candidate = new Vect(position.x + i, position.y + j, position.z + k); + if (candidate.equals(position)) + continue; + if (Math.abs(candidate.x - start.x) > 5) + continue; + if (Math.abs(candidate.z - start.z) > 5) + continue; + + // See whether the given position has already been processed + boolean skip = false; + for (Vect prcs : seen) + if (candidate.equals(prcs)) { + skip = true; + break; + } + + if (skip) + continue; + + ICrop crop = cocoa.getCropAt(world, candidate.x, candidate.y, candidate.z); + if (crop != null) { + crops.push(crop); + candidates.add(candidate); + seen.add(candidate); + } else if (isWoodBlock(candidate)) { + candidates.add(candidate); + seen.add(candidate); + } + } + + return candidates; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicCrops.java b/forestry_common/farming/forestry/farming/logic/FarmLogicCrops.java new file mode 100755 index 000000000..50f872b39 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicCrops.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Stack; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.AxisAlignedBB; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; + +public abstract class FarmLogicCrops extends FarmLogicWatered { + + private final IFarmable[] seeds; + + public FarmLogicCrops(IFarmHousing housing, IFarmable[] seeds) { + super(housing, new ItemStack[] { new ItemStack(Blocks.dirt) }, new ItemStack[] { new ItemStack(Blocks.farmland) }, new ItemStack[] { + new ItemStack(Blocks.dirt), new ItemStack(Blocks.grass) }); + + this.seeds = seeds; + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + for (IFarmable germling : seeds) + if (germling.isGermling(itemstack)) + return true; + return false; + } + + public boolean isWindfall(ItemStack itemstack) { + for (IFarmable germling : seeds) + if (germling.isWindfall(itemstack)) + return true; + return false; + } + + @SuppressWarnings("unchecked") + @Override + public Collection collect() { + + Collection products = produce; + produce = new ArrayList(); + + Vect coords = new Vect(housing.getCoords()); + Vect area = new Vect(housing.getArea()); + Vect offset = new Vect(housing.getOffset()); + + Vect min = coords.add(offset); + Vect max = coords.add(offset).add(area); + + AxisAlignedBB harvestBox = AxisAlignedBB.getBoundingBox(min.x, min.y, min.z, max.x, max.y, max.z); + List list = housing.getWorld().getEntitiesWithinAABB(Entity.class, harvestBox); + + int i; + for (i = 0; i < list.size(); i++) { + Entity entity = list.get(i); + + if (entity instanceof EntityItem) { + EntityItem item = (EntityItem) entity; + if (!item.isDead) { + ItemStack contained = item.getEntityItem(); + if (isAcceptedGermling(contained) || isWindfall(contained)) { + produce.add(contained.copy()); + item.setDead(); + } + } + } + } + + return products; + } + + @Override + protected boolean maintainCrops(int x, int y, int z, ForgeDirection direction, int extent) { + + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y, z, direction, i); + if (!isAirBlock(position) && !Utils.isReplaceableBlock(world, position.x, position.y, position.z)) + continue; + + ItemStack below = getAsItemStack(position.add(new Vect(0, -1, 0))); + if (ground[0].getItem() != below.getItem()) + continue; + if (below.getItemDamage() <= 0) + continue; + + return trySetCrop(position); + } + + return false; + } + + private boolean trySetCrop(Vect position) { + + for (IFarmable candidate : seeds) + if (housing.plantGermling(candidate, world, position.x, position.y, position.z)) + return true; + + return false; + } + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Stack crops = new Stack(); + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y + 1, z, direction, i); + for (IFarmable seed : seeds) { + ICrop crop = seed.getCropAt(world, position.x, position.y, position.z); + if (crop != null) + crops.push(crop); + } + } + return crops; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicGourd.java b/forestry_common/farming/forestry/farming/logic/FarmLogicGourd.java new file mode 100755 index 000000000..8d8a6f5b1 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicGourd.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; +import java.util.Stack; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.Farmables; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.utils.Vect; + +public class FarmLogicGourd extends FarmLogic { + + private final IFarmable[] seeds; + + public FarmLogicGourd(IFarmHousing housing) { + super(housing); + seeds = Farmables.farmables.get("farmGourd").toArray(new IFarmable[0]); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Items.melon.getIconFromDamage(0); + } + + @Override + public String getName() { + return "Gourd Farm"; + } + + @Override + public int getFertilizerConsumption() { + return 10; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (40 * hydrationModifier); + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + return false; + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + return false; + } + + @Override + public Collection collect() { + return null; + } + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + return false; + } + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Stack crops = new Stack(); + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y + 1, z, direction, i); + for (IFarmable seed : seeds) { + ICrop crop = seed.getCropAt(world, position.x, position.y, position.z); + if (crop != null) + crops.push(crop); + } + } + return crops; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicHomogenous.java b/forestry_common/farming/forestry/farming/logic/FarmLogicHomogenous.java new file mode 100755 index 000000000..f97e0d210 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicHomogenous.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; + +public abstract class FarmLogicHomogenous extends FarmLogic { + + protected final ItemStack[] resource; + protected final ItemStack[] ground; + protected final ItemStack[] waste; + protected final IFarmable[] germlings; + + ArrayList produce = new ArrayList(); + + public FarmLogicHomogenous(IFarmHousing housing, ItemStack[] resource, ItemStack[] ground, ItemStack[] waste, IFarmable[] germlings) { + super(housing); + this.resource = resource; + this.ground = ground; + this.waste = waste; + this.germlings = germlings; + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + return resource[0].isItemEqual(itemstack); + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + for (IFarmable germling : germlings) + if (germling.isGermling(itemstack)) + return true; + return false; + } + + public boolean isWindfall(ItemStack itemstack) { + for (IFarmable germling : germlings) + if (germling.isWindfall(itemstack)) + return true; + return false; + } + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + world = housing.getWorld(); + + if (maintainSoil(x, y, z, direction, extent)) + return true; + + if (maintainGermlings(x, y + 1, z, direction, extent)) + return true; + + return false; + } + + private boolean maintainSoil(int x, int yGround, int z, ForgeDirection direction, int extent) { + + if (!housing.hasResources(resource)) + return false; + + cycle: for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, yGround, z, direction, i); + + if (!isAirBlock(position) && !Utils.isReplaceableBlock(world, position.x, position.y, position.z)) { + + ItemStack block = getAsItemStack(position); + + for (ItemStack grnd : ground) + if (StackUtils.isIdenticalItem(grnd, block)) + continue cycle; + + boolean removedWaste = false; + if (waste.length > 0) { + for(ItemStack wste : waste) { + if(!wste.isItemEqual(block)) + continue; + produce.add(wste.copy()); + removedWaste = true; + break; + } + } + if(!removedWaste) + return false; + } + + setBlock(position, StackUtils.getBlock(ground[0]), ground[0].getItemDamage()); + housing.removeResources(resource); + return true; + + } + + return false; + } + + protected abstract boolean maintainGermlings(int x, int ySaplings, int z, ForgeDirection direction, int extent); +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicInfernal.java b/forestry_common/farming/forestry/farming/logic/FarmLogicInfernal.java new file mode 100755 index 000000000..0dd3770b4 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicInfernal.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; +import java.util.Stack; + +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.Farmables; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; + +public class FarmLogicInfernal extends FarmLogicHomogenous { + + public FarmLogicInfernal(IFarmHousing housing) { + super(housing, new ItemStack[] { new ItemStack(Blocks.soul_sand) }, new ItemStack[] { new ItemStack(Blocks.soul_sand) }, new ItemStack[0], + Farmables.farmables.get("farmInfernal").toArray(new IFarmable[0])); + } + + @Override + public String getName() { + return "Managed Infernal Farm"; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Items.nether_wart.getIconFromDamage(0); + } + + @Override + public int getFertilizerConsumption() { + return 20; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return 0; + } + + @Override + public Collection collect() { + return null; + } + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Stack crops = new Stack(); + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y + 1, z, direction, i); + for (IFarmable farmable : germlings) { + ICrop crop = farmable.getCropAt(world, position.x, position.y, position.z); + if (crop != null) + crops.push(crop); + } + + } + return crops; + + } + + @Override + protected boolean maintainGermlings(int x, int y, int z, ForgeDirection direction, int extent) { + + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y, z, direction, i); + if (!isAirBlock(position) && !Utils.isReplaceableBlock(world, position.x, position.y, position.z)) + continue; + + ItemStack below = getAsItemStack(position.add(new Vect(0, -1, 0))); + if (ground[0].getItem() != below.getItem()) + continue; + + return trySetCrop(position); + } + + return false; + } + + private boolean trySetCrop(Vect position) { + + for (IFarmable candidate : germlings) + if (housing.plantGermling(candidate, world, position.x, position.y, position.z)) + return true; + + return false; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicOrchard.java b/forestry_common/farming/forestry/farming/logic/FarmLogicOrchard.java new file mode 100755 index 000000000..dff3be4b9 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicOrchard.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Stack; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.genetics.IFruitBearer; +import forestry.core.config.ForestryItem; +import forestry.core.utils.Vect; + +public class FarmLogicOrchard extends FarmLogic { + + public FarmLogicOrchard(IFarmHousing housing) { + super(housing); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return ForestryItem.fruits.item().getIconFromDamage(0); + } + + @Override + public String getName() { + return "Orchard"; + } + + @Override + public int getFertilizerConsumption() { + return 10; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (40 * hydrationModifier); + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + return false; + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + return false; + } + + @Override + public Collection collect() { + return null; + } + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + return false; + } + + private final HashMap lastExtents = new HashMap(); + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Collection crops = null; + + Vect start = new Vect(x, y, z); + if (!lastExtents.containsKey(start)) + lastExtents.put(start, 0); + + int lastExtent = lastExtents.get(start); + if (lastExtent > extent) + lastExtent = 0; + + // Proxies.log.finest("Logic %s is searching in direction %s at %s/%s/%s with extension %s.", getClass(), direction, x, y, z, lastExtent); + + Vect position = translateWithOffset(x, y + 1, z, direction, lastExtent); + crops = getHarvestBlocks(position); + lastExtent++; + lastExtents.put(start, lastExtent); + + return crops; + } + + private Collection getHarvestBlocks(Vect position) { + + ArrayList seen = new ArrayList(); + Stack crops = new Stack(); + + // Determine what type we want to harvest. + IFruitBearer bearer = getFruitBlock(position); + Block block = getBlock(position); + if ((!block.isWood(world, position.x, position.y, position.z)) && bearer == null) + return crops; + + ArrayList candidates = processHarvestBlock(crops, seen, position, position); + ArrayList temp = new ArrayList(); + while (!candidates.isEmpty() && crops.size() < 20) { + for (Vect candidate : candidates) + temp.addAll(processHarvestBlock(crops, seen, position, candidate)); + candidates.clear(); + candidates.addAll(temp); + temp.clear(); + } + // Proxies.log.finest("Logic at %s/%s/%s has seen %s blocks.", position.x, position.y, position.z, seen.size()); + + return crops; + } + + private ArrayList processHarvestBlock(Stack crops, Collection seen, Vect start, Vect position) { + + ArrayList candidates = new ArrayList(); + + // Get additional candidates to return + for (int i = -1; i < 2; i++) + for (int j = 0; j < 2; j++) + for (int k = -1; k < 2; k++) { + Vect candidate = new Vect(position.x + i, position.y + j, position.z + k); + if (candidate.equals(position)) + continue; + if (Math.abs(candidate.x - start.x) > 5) + continue; + if (Math.abs(candidate.z - start.z) > 5) + continue; + + // See whether the given position has already been processed + boolean skip = false; + for (Vect prcs : seen) + if (candidate.equals(prcs)) { + skip = true; + break; + } + + if (skip) + continue; + + IFruitBearer bearer = getFruitBlock(candidate); + if (bearer != null && bearer.hasFruit()) { + if (bearer.getRipeness() >= 0.9f) + crops.push(new CropFruit(world, candidate, bearer.getFruitFamily())); + candidates.add(candidate); + seen.add(candidate); + } else if (this.isWoodBlock(candidate)) { + candidates.add(candidate); + seen.add(candidate); + } + } + + return candidates; + } + + private IFruitBearer getFruitBlock(Vect position) { + TileEntity tile = world.getTileEntity(position.x, position.y, position.z); + if (!(tile instanceof IFruitBearer)) + return null; + + return (IFruitBearer) tile; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicPeat.java b/forestry_common/farming/forestry/farming/logic/FarmLogicPeat.java new file mode 100755 index 000000000..3dd7b8747 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicPeat.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; +import java.util.Stack; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; + +public class FarmLogicPeat extends FarmLogicWatered { + + public FarmLogicPeat(IFarmHousing housing) { + super(housing, new ItemStack[] { new ItemStack(ForestryBlock.soil, 1, 1) }, + new ItemStack[] { new ItemStack(ForestryBlock.soil, 1, 1) }, new ItemStack[] { new ItemStack(Blocks.dirt), new ItemStack(Blocks.grass) }); + } + + @Override + public int getFertilizerConsumption() { + return 2; + } + + @Override + public String getName() { + if (isManual) + return "Manual Peat Bog"; + else + return "Managed Peat Bog"; + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + return false; + } + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Stack crops = new Stack(); + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y, z, direction, i); + ItemStack occupant = getAsItemStack(position); + + if (StackUtils.getBlock(occupant) != ForestryBlock.soil) + continue; + int type = occupant.getItemDamage() & 0x03; + int maturity = occupant.getItemDamage() >> 2; + + if (type != 1) + continue; + + if (maturity >= 3) + crops.push(new CropPeat(world, position)); + + } + return crops; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return ForestryItem.peat.item().getIconFromDamage(0); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicPoale.java b/forestry_common/farming/forestry/farming/logic/FarmLogicPoale.java new file mode 100755 index 000000000..b58906ce8 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicPoale.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; +import java.util.Stack; + +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.Farmables; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; + +public class FarmLogicPoale extends FarmLogic { + + IFarmable[] germlings; + + public FarmLogicPoale(IFarmHousing housing) { + super(housing); + germlings = Farmables.farmables.get("farmPoales").toArray(new IFarmable[0]); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Items.reeds.getIconFromDamage(0); + } + + @Override + public String getName() { + if (isManual) + return "Manual Reed Farm"; + else + return "Managed Reed Farm"; + } + + @Override + public int getFertilizerConsumption() { + return 10; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (20 * hydrationModifier); + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + if (isManual) + return false; + + return StackUtils.equals(Blocks.sand, itemstack) || StackUtils.equals(Blocks.dirt, itemstack); + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + if (isManual) + return false; + + return itemstack.getItem() == Items.reeds; + } + + @Override + public Collection collect() { + return null; + } + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + return false; + } + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Stack crops = new Stack(); + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y + 1, z, direction, i); + for (IFarmable seed : germlings) { + ICrop crop = seed.getCropAt(world, position.x, position.y, position.z); + if (crop != null) + crops.push(crop); + } + } + return crops; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicRubber.java b/forestry_common/farming/forestry/farming/logic/FarmLogicRubber.java new file mode 100755 index 000000000..e10d1d801 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicRubber.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Stack; + +import net.minecraft.block.Block; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; +import forestry.plugins.PluginIC2; + +public class FarmLogicRubber extends FarmLogic { + + private boolean inActive; + + public FarmLogicRubber(IFarmHousing housing) { + super(housing); + if (PluginIC2.rubberwood == null || PluginIC2.resin == null) { + Proxies.log.warning("Failed to init a farm logic %s since IC2 was not found", getClass().getName()); + inActive = true; + } + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + if (!inActive) + return PluginIC2.resin.getIconIndex(); + else + return Items.gunpowder.getIconFromDamage(0); + } + + @Override + public String getName() { + return "Rubber Plantation"; + } + + @Override + public int getFertilizerConsumption() { + return 40; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (5 * hydrationModifier); + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + return false; + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + return false; + } + + @Override + public Collection collect() { + return null; + } + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + return false; + } + + private final HashMap lastExtents = new HashMap(); + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + if (inActive) + return null; + + world = housing.getWorld(); + + Collection crops = null; + Vect start = new Vect(x, y, z); + if (!lastExtents.containsKey(start)) + lastExtents.put(start, 0); + + int lastExtent = lastExtents.get(start); + if (lastExtent > extent) + lastExtent = 0; + + Vect position = translateWithOffset(x, y + 1, z, direction, lastExtent); + crops = getHarvestBlocks(position); + lastExtent++; + lastExtents.put(start, lastExtent); + + return crops; + } + + private Collection getHarvestBlocks(Vect position) { + + ArrayList seen = new ArrayList(); + Stack crops = new Stack(); + + // Determine what type we want to harvest. + Block block = getBlock(position); + if (!StackUtils.equals(block, PluginIC2.rubberwood)) + return crops; + + int meta = this.getBlockMeta(position); + if (meta >= 2 && meta <= 5) + crops.push(new CropRubber(world, block, meta, position)); + + ArrayList candidates = processHarvestBlock(crops, seen, position); + ArrayList temp = new ArrayList(); + while (!candidates.isEmpty() && crops.size() < 100) { + for (Vect candidate : candidates) + temp.addAll(processHarvestBlock(crops, seen, candidate)); + candidates.clear(); + candidates.addAll(temp); + temp.clear(); + } + + return crops; + } + + private ArrayList processHarvestBlock(Stack crops, Collection seen, Vect position) { + + ArrayList candidates = new ArrayList(); + + // Get additional candidates to return + for (int j = 0; j < 2; j++) { + Vect candidate = new Vect(position.x, position.y + j, position.z); + if (candidate.equals(position)) + continue; + + // See whether the given position has already been processed + boolean skip = false; + for (Vect prcs : seen) + if (candidate.equals(prcs)) { + skip = true; + break; + } + + if (skip) + continue; + + Block block = getBlock(candidate); + if (StackUtils.equals(block, PluginIC2.rubberwood)) { + int meta = this.getBlockMeta(candidate); + if (meta >= 2 && meta <= 5) + crops.push(new CropRubber(world, block, meta, candidate)); + candidates.add(candidate); + seen.add(candidate); + } + } + + return candidates; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicShroom.java b/forestry_common/farming/forestry/farming/logic/FarmLogicShroom.java new file mode 100755 index 000000000..94e93a735 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicShroom.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.farming.Farmables; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; + +public class FarmLogicShroom extends FarmLogicArboreal { + + public FarmLogicShroom(IFarmHousing housing) { + super(housing, new ItemStack[] { new ItemStack(Blocks.mycelium) }, new ItemStack[] { new ItemStack(Blocks.mycelium) }, new ItemStack[] { new ItemStack( + Blocks.dirt), new ItemStack(Blocks.grass) }, Farmables.farmables.get("farmShroom").toArray(new IFarmable[0])); + yOffset = -1; + } + + @Override + public String getName() { + if (isManual) + return "Manual Shroom Farm"; + else + return "Managed Shroom Farm"; + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Blocks.red_mushroom.getBlockTextureFromSide(0); + } + + @Override + public int getFertilizerConsumption() { + return 20; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (80 * hydrationModifier); + } + + @Override + public Collection collect() { + Collection products = produce; + produce = new ArrayList(); + return products; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicSucculent.java b/forestry_common/farming/forestry/farming/logic/FarmLogicSucculent.java new file mode 100755 index 000000000..5650d66ac --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicSucculent.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; +import java.util.Stack; + +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.farming.Farmables; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; + +public class FarmLogicSucculent extends FarmLogic { + + IFarmable[] germlings; + + public FarmLogicSucculent(IFarmHousing housing) { + super(housing); + germlings = Farmables.farmables.get("farmSucculentes").toArray(new IFarmable[0]); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Items.dye.getIconFromDamage(2); + } + + @Override + public String getName() { + if (isManual) + return "Manual Succulent Farm"; + else + return "Managed Succulent Farm"; + } + + @Override + public int getFertilizerConsumption() { + return 10; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return 1; + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + if (isManual) + return false; + + return StackUtils.equals(Blocks.sand, itemstack); + } + + @Override + public boolean isAcceptedGermling(ItemStack itemstack) { + if (isManual) + return false; + + return StackUtils.equals(Blocks.cactus, itemstack); + } + + @Override + public Collection collect() { + return null; + } + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + return false; + } + + @Override + public Collection harvest(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + Stack crops = new Stack(); + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y + 1, z, direction, i); + for (IFarmable seed : germlings) { + ICrop crop = seed.getCropAt(world, position.x, position.y, position.z); + if (crop != null) + crops.push(crop); + } + } + return crops; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicVegetable.java b/forestry_common/farming/forestry/farming/logic/FarmLogicVegetable.java new file mode 100755 index 000000000..fc169cad1 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicVegetable.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.init.Items; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.farming.Farmables; +import forestry.api.farming.IFarmHousing; +import forestry.api.farming.IFarmable; + +public class FarmLogicVegetable extends FarmLogicCrops { + + public FarmLogicVegetable(IFarmHousing housing) { + super(housing, Farmables.farmables.get("farmVegetables").toArray(new IFarmable[0])); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return Items.carrot.getIconFromDamage(0); + } + + @Override + public String getName() { + if (isManual) + return "Manual Vegetable Farm"; + else + return "Managed Vegetable Farm"; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmLogicWatered.java b/forestry_common/farming/forestry/farming/logic/FarmLogicWatered.java new file mode 100755 index 000000000..a9c591dfd --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmLogicWatered.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import forestry.api.farming.IFarmHousing; +import forestry.core.config.Defaults; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; + +public abstract class FarmLogicWatered extends FarmLogic { + + protected ItemStack[] ground; + private final ItemStack[] resource; + private final ItemStack[] waste; + + private static final FluidStack STACK_WATER = new FluidStack(LiquidHelper.getFluid(Defaults.LIQUID_WATER), 1000); + + ArrayList produce = new ArrayList(); + + public FarmLogicWatered(IFarmHousing housing, ItemStack[] resource, ItemStack[] ground, ItemStack[] waste) { + super(housing); + this.ground = ground; + this.resource = resource; + this.waste = waste; + } + + @Override + public int getFertilizerConsumption() { + return 5; + } + + @Override + public int getWaterConsumption(float hydrationModifier) { + return (int) (20 * hydrationModifier); + } + + @Override + public boolean isAcceptedResource(ItemStack itemstack) { + return resource[0].isItemEqual(itemstack); + } + + @Override + public Collection collect() { + Collection products = produce; + produce = new ArrayList(); + return products; + } + + @Override + public boolean cultivate(int x, int y, int z, ForgeDirection direction, int extent) { + + world = housing.getWorld(); + + if (maintainSoil(x, y, z, direction, extent)) + return true; + + if (!isManual && maintainWater(x, y, z, direction, extent)) + return true; + + if (maintainCrops(x, y + 1, z, direction, extent)) + return true; + + return false; + } + + private boolean isWaste(ItemStack stack) { + for (ItemStack block : waste) + if (block.isItemEqual(stack)) + return true; + return false; + } + + private boolean maintainSoil(int x, int y, int z, ForgeDirection direction, int extent) { + + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y, z, direction, i); + if (!isAirBlock(position) && !Utils.isReplaceableBlock(world, position.x, position.y, position.z)) { + + ItemStack block = getAsItemStack(position); + if (isWaste(block) && housing.hasResources(resource)) { + produce.addAll(StackUtils.getBlock(block).getDrops(world, x, y, z, block.getItemDamage(), 0)); + setBlock(position, Blocks.air, 0); + return trySetSoil(position); + } + + continue; + } + + if (isManual || isWaterBlock(position)) + continue; + + if (i % 2 != 0) { + ForgeDirection cclock = ForgeDirection.EAST; + if (direction == ForgeDirection.EAST) + cclock = ForgeDirection.SOUTH; + else if (direction == ForgeDirection.SOUTH) + cclock = ForgeDirection.EAST; + else if (direction == ForgeDirection.WEST) + cclock = ForgeDirection.SOUTH; + + Vect previous = translateWithOffset(position.x, position.y, position.z, cclock, 1); + ItemStack soil = getAsItemStack(previous); + if (!ground[0].isItemEqual(soil)) + trySetSoil(position); + continue; + } + + return trySetSoil(position); + } + + return false; + } + + private boolean maintainWater(int x, int y, int z, ForgeDirection direction, int extent) { + // Still not done, check water then + for (int i = 0; i < extent; i++) { + Vect position = translateWithOffset(x, y, z, direction, i); + if ((!isAirBlock(position) && !Utils.isReplaceableBlock(world, position.x, position.y, position.z)) + || isWaterBlock(position)) { + continue; + } + + boolean isEnclosed = true; + + if (world.isAirBlock(position.x + 1, position.y, position.z)) + isEnclosed = false; + else if (world.isAirBlock(position.x - 1, position.y, position.z)) + isEnclosed = false; + else if (world.isAirBlock(position.x, position.y, position.z + 1)) + isEnclosed = false; + else if (world.isAirBlock(position.x, position.y, position.z - 1)) + isEnclosed = false; + + if (isEnclosed) + return trySetWater(position); + } + + return false; + } + + protected boolean maintainCrops(int x, int y, int z, ForgeDirection direction, int extent) { + return false; + } + + private boolean trySetSoil(Vect position) { + if (!housing.hasResources(resource)) + return false; + setBlock(position, StackUtils.getBlock(ground[0]), ground[0].getItemDamage()); + housing.removeResources(resource); + return true; + } + + private boolean trySetWater(Vect position) { + System.out.println("trySetWater: at " + position.toString()); + + if (!housing.hasLiquid(STACK_WATER)) + return false; + + System.out.println("Can place water: at " + position.toString()); + + setBlock(position, Blocks.water, 0); + housing.removeLiquid(STACK_WATER); + return true; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableCocoa.java b/forestry_common/farming/forestry/farming/logic/FarmableCocoa.java new file mode 100755 index 000000000..e9a62fd20 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableCocoa.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmable; +import forestry.core.utils.BlockUtil; +import forestry.core.utils.Vect; + +public class FarmableCocoa implements IFarmable { + + public static final Block COCOA_PLANT = Blocks.cocoa; + public static final Item COCOA_SEED = Items.dye; + public static final int COCOA_META = 3; + + @Override + public boolean isSaplingAt(World world, int x, int y, int z) { + return world.getBlock(x, y, z) == COCOA_PLANT; + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + if (block != COCOA_PLANT) + return null; + int meta = world.getBlockMetadata(x, y, z); + if (BlockUtil.getMaturityPod(meta) < 2) + return null; + + return new CropBlock(world, block, meta, new Vect(x, y, z)); + } + + @Override + public boolean isGermling(ItemStack itemstack) { + return itemstack.getItem() == COCOA_SEED && itemstack.getItemDamage() == COCOA_META; + } + + @Override + public boolean isWindfall(ItemStack itemstack) { + return false; + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + return BlockUtil.tryPlantPot(world, x, y, z, COCOA_PLANT); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableFarmCraftory.java b/forestry_common/farming/forestry/farming/logic/FarmableFarmCraftory.java new file mode 100755 index 000000000..0ca8a525c --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableFarmCraftory.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Collection; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmable; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; +import forestry.plugins.PluginFarmCraftory; + +public class FarmableFarmCraftory implements IFarmable { + + Collection germlings; + Collection windfall; + + public FarmableFarmCraftory(Collection germlings, Collection windfall) { + this.germlings = germlings; + this.windfall = windfall; + } + + @Override + public boolean isSaplingAt(World world, int x, int y, int z) { + + if (world.isAirBlock(x, y, z)) + return false; + + Block block = world.getBlock(x, y, z); + if (block != PluginFarmCraftory.blockSingle && block != PluginFarmCraftory.blockMulti) + return false; + else + return true; + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + if (block != PluginFarmCraftory.blockSingle && block != PluginFarmCraftory.blockMulti) + return null; + TileEntity tile = world.getTileEntity(x, y, z); + if (tile == null) + return null; + if (PluginFarmCraftory.getGrowthStage(tile) < 2) + return null; + + return new CropBlock(world, block, world.getBlockMetadata(x, y, z), new Vect(x, y, z)); + } + + @Override + public boolean isGermling(ItemStack itemstack) { + for (ItemStack seed : germlings) + if (StackUtils.isIdenticalItem(seed, itemstack)) + return true; + + return false; + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + return germling.copy().tryPlaceItemIntoWorld(Utils.getForestryPlayer(world, x, y, z), world, x, y - 1, z, 1, 0, 0, 0); + } + + @Override + public boolean isWindfall(ItemStack itemstack) { + for (ItemStack fruit : windfall) + if (StackUtils.isIdenticalItem(fruit, itemstack)) + return true; + + return false; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableGE.java b/forestry_common/farming/forestry/farming/logic/FarmableGE.java new file mode 100755 index 000000000..0a8780683 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableGE.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.arboriculture.ITree; +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmable; +import forestry.core.config.ForestryBlock; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; +import forestry.plugins.PluginArboriculture; + +public class FarmableGE implements IFarmable { + + @Override + public boolean isSaplingAt(World world, int x, int y, int z) { + + if (world.isAirBlock(x, y, z)) + return false; + + return world.getBlock(x, y, z) == ForestryBlock.saplingGE; + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + if (block.isAir(world, x, y, z) || !block.isWood(world, x, y, z)) + return null; + + return new CropBlock(world, block, world.getBlockMetadata(x, y, z), new Vect(x, y, z)); + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + return germling.copy().tryPlaceItemIntoWorld(Utils.getForestryPlayer(world, x, y, z), world, x, y - 1, z, 1, 0, 0, 0); + } + + @Override + public boolean isGermling(ItemStack itemstack) { + ITree tree = PluginArboriculture.treeInterface.getMember(itemstack); + return tree != null; + } + + @Override + public boolean isWindfall(ItemStack itemstack) { + return false; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableGenericCrop.java b/forestry_common/farming/forestry/farming/logic/FarmableGenericCrop.java new file mode 100755 index 000000000..643a0e83a --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableGenericCrop.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmable; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; + +public class FarmableGenericCrop implements IFarmable { + + private final ItemStack seed; + private final Block block; + private final int mature; + + public FarmableGenericCrop(ItemStack seed, Block block, int mature) { + this.seed = seed; + this.block = block; + this.mature = mature; + } + + @Override + public boolean isSaplingAt(World world, int x, int y, int z) { + + if (world.isAirBlock(x, y, z)) + return false; + + if (world.getBlock(x, y, z) != block) + return false; + else + return true; + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + if (world.getBlock(x, y, z) != block) + return null; + if (world.getBlockMetadata(x, y, z) != mature) + return null; + + return new CropBlock(world, block, mature, new Vect(x, y, z)); + } + + @Override + public boolean isGermling(ItemStack itemstack) { + if (seed.getItem() != itemstack.getItem()) + return false; + + if (seed.getItemDamage() >= 0) + return seed.getItemDamage() == itemstack.getItemDamage(); + else + return true; + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + return germling.copy().tryPlaceItemIntoWorld(Utils.getForestryPlayer(world, x, y, z), world, x, y - 1, z, 1, 0, 0, 0); + } + + @Override + public boolean isWindfall(ItemStack itemstack) { + return false; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableGenericSapling.java b/forestry_common/farming/forestry/farming/logic/FarmableGenericSapling.java new file mode 100755 index 000000000..fab00af7b --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableGenericSapling.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmable; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; +import forestry.core.utils.Vect; + +public class FarmableGenericSapling implements IFarmable { + + final Block sapling; + final int saplingMeta; + + ItemStack[] windfall; + + public FarmableGenericSapling(Block sapling, int saplingMeta, ItemStack... windfall) { + this.sapling = sapling; + this.saplingMeta = saplingMeta; + this.windfall = windfall; + } + + @Override + public boolean isSaplingAt(World world, int x, int y, int z) { + + if (world.isAirBlock(x, y, z)) + return false; + + if (world.getBlock(x, y, z) == sapling) + return true; + + if (saplingMeta >= 0) + return world.getBlockMetadata(x, y, z) == saplingMeta; + else + return true; + + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + if (!block.isWood(world, x, y, z)) + return null; + + return new CropBlock(world, block, world.getBlockMetadata(x, y, z), new Vect(x, y, z)); + } + + @Override + public boolean isGermling(ItemStack itemstack) { + + if (!StackUtils.equals(sapling, itemstack)) + return false; + + if (saplingMeta >= 0) + return itemstack.getItemDamage() == saplingMeta; + else + return true; + } + + @Override + public boolean isWindfall(ItemStack itemstack) { + for (ItemStack drop : windfall) + if (drop.isItemEqual(itemstack)) + return true; + return false; + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + return germling.copy().tryPlaceItemIntoWorld(Utils.getForestryPlayer(world, x, y, z), world, x, y - 1, z, 1, 0, 0, 0); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableGourd.java b/forestry_common/farming/forestry/farming/logic/FarmableGourd.java new file mode 100755 index 000000000..ae95f7d77 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableGourd.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmable; +import forestry.core.config.Defaults; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; + +public class FarmableGourd implements IFarmable { + + public ItemStack seed; + public ItemStack stem; + public ItemStack fruit; + + public FarmableGourd(ItemStack seed, ItemStack stem, ItemStack fruit) { + this.seed = seed; + this.stem = stem; + this.fruit = fruit; + } + + @Override + public boolean isSaplingAt(World world, int x, int y, int z) { + if (world.isAirBlock(x, y, z)) + return false; + + if (!StackUtils.equals(world.getBlock(x, y, z), stem)) + return false; + + return true; + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + if (world.isAirBlock(x, y, z)) + return null; + + if (!StackUtils.equals(world.getBlock(x, y, z), fruit)) + return null; + + if (world.getBlockMetadata(x, y, z) != fruit.getItemDamage()) + return null; + + return new CropBlock(world, StackUtils.getBlock(fruit), fruit.getItemDamage(), new Vect(x, y, z)); + } + + @Override + public boolean isGermling(ItemStack itemstack) { + return seed.isItemEqual(itemstack); + } + + @Override + public boolean isWindfall(ItemStack itemstack) { + return false; + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + return world.setBlock(x, y, z, StackUtils.getBlock(stem), 0, Defaults.FLAG_BLOCK_SYNCH); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableStacked.java b/forestry_common/farming/forestry/farming/logic/FarmableStacked.java new file mode 100755 index 000000000..94721ee0f --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableStacked.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.api.farming.IFarmable; +import forestry.core.config.Defaults; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; + +public class FarmableStacked implements IFarmable { + + Block block; + int matureHeight; + + public FarmableStacked(Block block, int matureHeight) { + this.block = block; + this.matureHeight = matureHeight; + } + + @Override + public boolean isSaplingAt(World world, int x, int y, int z) { + return world.getBlock(x, y, z) == block; + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + if (world.getBlock(x, y + (matureHeight - 1), z) != block) + return null; + + return new CropBlock(world, block, 0, new Vect(x, y + (matureHeight - 1), z)); + } + + @Override + public boolean isGermling(ItemStack itemstack) { + return StackUtils.equals(block, itemstack); + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + return world.setBlock(x, y, z, block, 0, Defaults.FLAG_BLOCK_SYNCH); + } + + @Override + public boolean isWindfall(ItemStack itemstack) { + return false; + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableVanillaSapling.java b/forestry_common/farming/forestry/farming/logic/FarmableVanillaSapling.java new file mode 100755 index 000000000..8b82665b7 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableVanillaSapling.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import java.util.Map; + +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.arboriculture.ITree; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import forestry.core.config.Config; +import forestry.plugins.PluginArboriculture; + +public class FarmableVanillaSapling extends FarmableGenericSapling { + + int saplingId; + int saplingMeta; + + public FarmableVanillaSapling() { + super(Blocks.sapling, -1, new ItemStack(Items.apple), new ItemStack(FarmableCocoa.COCOA_SEED, 1, FarmableCocoa.COCOA_META)); + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + ITree tree = null; + for (Map.Entry entry : AlleleManager.ersatzSaplings.entrySet()) + if (entry.getKey().isItemEqual(germling) && entry.getValue() instanceof ITree) { + tree = (ITree) entry.getValue(); + break; + } + + if (tree == null) + return false; + + return PluginArboriculture.treeInterface.plantSapling(world, tree, Config.fakeUserLogin, x, y, z); + } + +} diff --git a/forestry_common/farming/forestry/farming/logic/FarmableVanillaShroom.java b/forestry_common/farming/forestry/farming/logic/FarmableVanillaShroom.java new file mode 100755 index 000000000..1c3292e58 --- /dev/null +++ b/forestry_common/farming/forestry/farming/logic/FarmableVanillaShroom.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.logic; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.farming.ICrop; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Vect; + +public class FarmableVanillaShroom extends FarmableGenericSapling { + + public FarmableVanillaShroom(Block sapling, int saplingMeta) { + super(sapling, saplingMeta); + } + + @Override + public ICrop getCropAt(World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + + if (block != Blocks.brown_mushroom_block && block != Blocks.red_mushroom_block) + return null; + + return new CropBlock(world, block, world.getBlockMetadata(x, y, z), new Vect(x, y, z)); + } + + @Override + public boolean plantSaplingAt(ItemStack germling, World world, int x, int y, int z) { + int meta = 0; + if (StackUtils.equals(Blocks.red_mushroom, germling)) + meta = 1; + + Proxies.common.addBlockPlaceEffects(world, x, y, z, Blocks.brown_mushroom, 0); + return world.setBlock(x, y, z, ForestryBlock.mushroom, meta, Defaults.FLAG_BLOCK_SYNCH); + } + +} diff --git a/forestry_common/farming/forestry/farming/proxy/ClientProxyFarming.java b/forestry_common/farming/forestry/farming/proxy/ClientProxyFarming.java new file mode 100755 index 000000000..235f31218 --- /dev/null +++ b/forestry_common/farming/forestry/farming/proxy/ClientProxyFarming.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.proxy; + +import net.minecraft.item.Item; + +import cpw.mods.fml.client.registry.RenderingRegistry; + +import net.minecraftforge.client.MinecraftForgeClient; + +import forestry.core.config.ForestryBlock; +import forestry.core.utils.Localization; +import forestry.farming.render.FarmItemRenderer; +import forestry.farming.render.FarmRenderingHandler; +import forestry.plugins.PluginFarming; + +public class ClientProxyFarming extends ProxyFarming { + + @Override + public void initializeRendering() { + PluginFarming.modelIdFarmBlock = RenderingRegistry.getNextAvailableRenderId(); + + RenderingRegistry.registerBlockHandler(new FarmRenderingHandler()); + MinecraftForgeClient.registerItemRenderer(Item.getItemFromBlock(ForestryBlock.farm), new FarmItemRenderer()); + } + + @Override + public void addLocalizations() { + Localization.instance.addLocalization("/lang/forestry/farming/"); + } + +} diff --git a/forestry_common/farming/forestry/farming/proxy/ProxyFarming.java b/forestry_common/farming/forestry/farming/proxy/ProxyFarming.java new file mode 100755 index 000000000..d305207e6 --- /dev/null +++ b/forestry_common/farming/forestry/farming/proxy/ProxyFarming.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.proxy; + +public class ProxyFarming { + + public void initializeRendering() { + } + + public void addLocalizations() { + } + +} diff --git a/forestry_common/farming/forestry/farming/render/FarmItemRenderer.java b/forestry_common/farming/forestry/farming/render/FarmItemRenderer.java new file mode 100755 index 000000000..3f319a852 --- /dev/null +++ b/forestry_common/farming/forestry/farming/render/FarmItemRenderer.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.render; + +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.client.IItemRenderer; + +import org.lwjgl.opengl.GL11; + +import forestry.core.utils.StackUtils; +import forestry.farming.gadgets.BlockFarm; +import forestry.farming.gadgets.TileFarm.EnumFarmBlock; + +public class FarmItemRenderer implements IItemRenderer { + + private void renderFarmBlock(RenderBlocks render, ItemStack item, float translateX, float translateY, float translateZ) { + + Tessellator tessellator = Tessellator.instance; + BlockFarm block = (BlockFarm) StackUtils.getBlock(item); + + block.setBlockBoundsForItemRender(); + render.setRenderBoundsFromBlock(block); + + EnumFarmBlock type = EnumFarmBlock.getFromCompound(item.getTagCompound()); + + GL11.glTranslatef(translateX, translateY, translateZ); + + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1F, 0.0F); + render.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, block.getBlockTextureFromSideAndMetadata(type, 0, item.getItemDamage())); + render.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, block.getOverlayTextureForBlock(0, item.getItemDamage())); + tessellator.draw(); + + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 1.0F, 0.0F); + render.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, block.getBlockTextureFromSideAndMetadata(type, 1, item.getItemDamage())); + render.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, block.getOverlayTextureForBlock(1, item.getItemDamage())); + tessellator.draw(); + + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, -1F); + render.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, block.getBlockTextureFromSideAndMetadata(type, 2, item.getItemDamage())); + render.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, block.getOverlayTextureForBlock(2, item.getItemDamage())); + tessellator.draw(); + + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, 1.0F); + render.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, block.getBlockTextureFromSideAndMetadata(type, 3, item.getItemDamage())); + render.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, block.getOverlayTextureForBlock(3, item.getItemDamage())); + tessellator.draw(); + + tessellator.startDrawingQuads(); + tessellator.setNormal(-1F, 0.0F, 0.0F); + render.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, block.getBlockTextureFromSideAndMetadata(type, 4, item.getItemDamage())); + render.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, block.getOverlayTextureForBlock(4, item.getItemDamage())); + tessellator.draw(); + + tessellator.startDrawingQuads(); + tessellator.setNormal(1.0F, 0.0F, 0.0F); + render.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, block.getBlockTextureFromSideAndMetadata(type, 5, item.getItemDamage())); + render.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, block.getOverlayTextureForBlock(5, item.getItemDamage())); + tessellator.draw(); + + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + + block.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + + } + + @Override + public boolean handleRenderType(ItemStack item, ItemRenderType type) { + switch (type) { + case ENTITY: + case EQUIPPED_FIRST_PERSON: + case EQUIPPED: + case INVENTORY: + return true; + default: + return false; + } + } + + @Override + public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) { + return true; + } + + @Override + public void renderItem(ItemRenderType type, ItemStack item, Object... data) { + switch (type) { + case ENTITY: + renderFarmBlock((RenderBlocks) data[0], item, -0.5f, -0.5f, -0.5f); + break; + case EQUIPPED: + case EQUIPPED_FIRST_PERSON: + renderFarmBlock((RenderBlocks) data[0], item, 0f, 0f, 0f); + break; + case INVENTORY: + renderFarmBlock((RenderBlocks) data[0], item, -0.5f, -0.5f, -0.5f); + break; + default: + } + } + +} diff --git a/forestry_common/farming/forestry/farming/render/FarmRenderingHandler.java b/forestry_common/farming/forestry/farming/render/FarmRenderingHandler.java new file mode 100755 index 000000000..5e1668a74 --- /dev/null +++ b/forestry_common/farming/forestry/farming/render/FarmRenderingHandler.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.render; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.world.IBlockAccess; + +import forestry.core.config.ForestryBlock; +import forestry.core.render.OverlayRenderingHandler; +import forestry.farming.gadgets.BlockFarm; +import forestry.plugins.PluginFarming; + +public class FarmRenderingHandler extends OverlayRenderingHandler { + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) { + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { + + // Render the plain block. + renderer.renderStandardBlock(block, x, y, z); + renderFarmOverlay(world, (BlockFarm) ForestryBlock.farm, x, y, z, renderer, 0xffffff); + + return true; + } + + private boolean renderFarmOverlay(IBlockAccess world, BlockFarm block, int x, int y, int z, RenderBlocks renderer, int multiplier) { + + float mR = (multiplier >> 16 & 255) / 255.0F; + float mG = (multiplier >> 8 & 255) / 255.0F; + float mB = (multiplier & 255) / 255.0F; + + if (EntityRenderer.anaglyphEnable) { + mR = (mR * 30.0F + mG * 59.0F + mB * 11.0F) / 100.0F; + mG = (mR * 30.0F + mG * 70.0F) / 100.0F; + mB = (mR * 30.0F + mB * 70.0F) / 100.0F; + } + + return renderFarmOverlayWithColourMultiplier(world, block, x, y, z, mR, mG, mB, renderer); + } + + private boolean renderFarmOverlayWithColourMultiplier(IBlockAccess world, BlockFarm block, int x, int y, int z, float r, float g, float b, + RenderBlocks renderer) { + + int mixedBrightness = block.getMixedBrightnessForBlock(world, x, y, z); + int metadata = world.getBlockMetadata(x, y, z); + + float adjR = 0.5f * r; + float adjG = 0.5f * g; + float adjB = 0.5f * b; + + // Bottom + renderBottomFace(world, block, x, y, z, renderer, block.getOverlayTextureForBlock(0, metadata), mixedBrightness, adjR, adjG, adjB); + renderTopFace(world, block, x, y, z, renderer, block.getOverlayTextureForBlock(1, metadata), mixedBrightness, adjR, adjG, adjB); + renderEastFace(world, block, x, y, z, renderer, block.getOverlayTextureForBlock(2, metadata), mixedBrightness, adjR, adjG, adjB); + renderWestFace(world, block, x, y, z, renderer, block.getOverlayTextureForBlock(3, metadata), mixedBrightness, adjR, adjG, adjB); + renderNorthFace(world, block, x, y, z, renderer, block.getOverlayTextureForBlock(4, metadata), mixedBrightness, adjR, adjG, adjB); + renderSouthFace(world, block, x, y, z, renderer, block.getOverlayTextureForBlock(5, metadata), mixedBrightness, adjR, adjG, adjB); + + return true; + } + + @Override + public boolean shouldRender3DInInventory(int modelId) { + return true; + } + + @Override + public int getRenderId() { + return PluginFarming.modelIdFarmBlock; + } + +} diff --git a/forestry_common/farming/forestry/farming/triggers/TriggerLowFertilizer.java b/forestry_common/farming/forestry/farming/triggers/TriggerLowFertilizer.java new file mode 100755 index 000000000..de4e44093 --- /dev/null +++ b/forestry_common/farming/forestry/farming/triggers/TriggerLowFertilizer.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.triggers; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.api.core.ITileStructure; +import forestry.core.triggers.Trigger; +import forestry.farming.gadgets.TileFarmPlain; +import forestry.farming.gadgets.TileHatch; + +public class TriggerLowFertilizer extends Trigger { + + private final float threshold; + + public TriggerLowFertilizer(String tag, float threshold) { + super(tag, "lowFertilizer"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + if (!(tile instanceof TileHatch)) + return false; + + ITileStructure central = ((TileHatch) tile).getCentralTE(); + if (central == null || !(central instanceof TileFarmPlain)) + return false; + + ItemStack fertilizer = central.getInventory().getStackInSlot(TileFarmPlain.SLOT_FERTILIZER); + if (fertilizer == null) + return true; + return ((float) fertilizer.stackSize / fertilizer.getMaxStackSize()) <= threshold; + } +} diff --git a/forestry_common/farming/forestry/farming/triggers/TriggerLowLiquid.java b/forestry_common/farming/forestry/farming/triggers/TriggerLowLiquid.java new file mode 100755 index 000000000..e58c6dc15 --- /dev/null +++ b/forestry_common/farming/forestry/farming/triggers/TriggerLowLiquid.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.api.core.ITileStructure; +import forestry.core.triggers.Trigger; +import forestry.core.utils.ForestryTank; +import forestry.farming.gadgets.TileFarmPlain; +import forestry.farming.gadgets.TileHatch; + +public class TriggerLowLiquid extends Trigger { + + private float threshold = 0.25F; + + public TriggerLowLiquid(String tag, float threshold) { + super(tag, "lowLiquid"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + /** + * Return true if the tile given in parameter activates the trigger, given + * the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + if (!(tile instanceof TileHatch)) + return false; + + ITileStructure central = ((TileHatch) tile).getCentralTE(); + if (central == null || !(central instanceof TileFarmPlain)) + return false; + + ForestryTank tank = ((TileFarmPlain) central).getTank(); + return ((float) tank.getFluidAmount() / tank.getCapacity()) <= threshold; + } +} diff --git a/forestry_common/farming/forestry/farming/triggers/TriggerLowSoil.java b/forestry_common/farming/forestry/farming/triggers/TriggerLowSoil.java new file mode 100755 index 000000000..9e5197fe2 --- /dev/null +++ b/forestry_common/farming/forestry/farming/triggers/TriggerLowSoil.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.farming.triggers; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.api.core.ITileStructure; +import forestry.core.triggers.Trigger; +import forestry.farming.gadgets.TileFarmPlain; +import forestry.farming.gadgets.TileHatch; + +public class TriggerLowSoil extends Trigger { + + private int threshold = 64; + + public TriggerLowSoil(int threshold) { + super("lowSoil." + threshold, "lowSoil"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold; + } + + @Override + public boolean hasParameter() { + return true; + } + + /** + * Return true if the tile given in parameter activates the trigger, given + * the parameters. + */ + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + if (!(tile instanceof TileHatch)) + return false; + + ITileStructure central = ((TileHatch) tile).getCentralTE(); + if (central == null || !(central instanceof TileFarmPlain)) + return false; + + ItemStack filter; + if (parameter == null || parameter.getItemStack() == null) + filter = new ItemStack(Blocks.air, threshold, -1); + else { + filter = parameter.getItemStack().copy(); + filter.stackSize = threshold; + } + + return !((TileFarmPlain) central).hasResources(new ItemStack[] { filter }); + } +} diff --git a/forestry_common/farming/forestry/farming/worldgen/WorldGenBigMushroom.java b/forestry_common/farming/forestry/farming/worldgen/WorldGenBigMushroom.java new file mode 100755 index 000000000..f2f3caf0c --- /dev/null +++ b/forestry_common/farming/forestry/farming/worldgen/WorldGenBigMushroom.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. +// Jad home page: http://www.kpdus.com/jad.html +// Decompiler options: packimports(3) braces deadcode fieldsfirst + +package forestry.farming.worldgen; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.WorldGenerator; + +import forestry.core.config.Defaults; + +// Referenced classes of package net.minecraft.src: +// WorldGenerator, World, Block, BlockLeaves, +// BlockGrass, BlockMycelium, BlockFlower + +public class WorldGenBigMushroom extends WorldGenerator { + private final Block mushroom; + + public WorldGenBigMushroom(Block block) { + mushroom = block; + } + + public WorldGenBigMushroom() { + mushroom = null; + } + + @Override + public boolean generate(World world, Random random, int x, int y, int z) { + Block type = mushroom; + + if (type == null) { + type = random.nextBoolean() ? Blocks.brown_mushroom_block : Blocks.red_mushroom_block; + } + + int height = random.nextInt(1) + 2; + boolean flag = true; + if (y < 1 || y + height + 1 > Defaults.WORLD_HEIGHT) + return false; + + for (int i = y; i <= y + 1 + height; i++) { + byte offset = 3; + if (i == y) + offset = 0; + + for (int j = x - offset; j <= x + offset && flag; j++) + for (int k = z - offset; k <= z + offset && flag; k++) + if (i >= 0 && i < Defaults.WORLD_HEIGHT) { + Block block = world.getBlock(j, i, k); + if (!block.isAir(world, j, i, k) && block != Blocks.leaves) + flag = false; + } else + flag = false; + } + + if (!flag) + return false; + + Block ground = world.getBlock(x, y - 1, z); + if (ground != Blocks.mycelium) + return false; + + if (!Blocks.brown_mushroom.canPlaceBlockAt(world, x, y, z)) + return false; + + func_150515_a(world, x, y - 1, z, Blocks.dirt); + + int capStartY = y + height; + if (type == Blocks.red_mushroom_block) + capStartY = (y + height) - 1; + + for (int i = capStartY; i <= y + height; i++) { + + int capRad = 1; + + if (type == Blocks.brown_mushroom_block) + capRad = 1; + + for (int j = x - capRad; j <= x + capRad; j++) + for (int k = z - capRad; k <= z + capRad; k++) { + int remain = 5; + if (j == x - capRad) + remain--; + + if (j == x + capRad) + remain++; + + if (k == z - capRad) + remain -= 3; + + if (k == z + capRad) + remain += 3; + + if (type == Blocks.brown_mushroom_block || i < y + height) { + + if (j == x - (capRad - 1) && k == z - capRad) + remain = 1; + + if (j == x - capRad && k == z - (capRad - 1)) + remain = 1; + + if (j == x + (capRad - 1) && k == z - capRad) + remain = 3; + + if (j == x + capRad && k == z - (capRad - 1)) + remain = 3; + + if (j == x - (capRad - 1) && k == z + capRad) + remain = 7; + + if (j == x - capRad && k == z + (capRad - 1)) + remain = 7; + + if (j == x + (capRad - 1) && k == z + capRad) + remain = 9; + + if (j == x + capRad && k == z + (capRad - 1)) + remain = 9; + + } + if (remain == 5 && i < y + height) + remain = 0; + + if ((remain != 0 || y >= (y + height) - 1) && !world.getBlock(j, i, k).isOpaqueCube()) + setBlockAndNotifyAdequately(world, j, i, k, type, remain); + + } + + } + + for (int i = 0; i < height; i++) { + Block block = world.getBlock(x, y + i, z); + if (!block.isOpaqueCube()) + setBlockAndNotifyAdequately(world, x, y + i, z, type, 10); + } + + return true; + } +} diff --git a/forestry_common/farming/forestry/plugins/PluginFarmCraftory.java b/forestry_common/farming/forestry/plugins/PluginFarmCraftory.java new file mode 100755 index 000000000..4e5ccbf9e --- /dev/null +++ b/forestry_common/farming/forestry/plugins/PluginFarmCraftory.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.lang.reflect.Method; +import java.util.HashMap; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.core.PluginInfo; +import forestry.api.farming.Farmables; +import forestry.core.config.Defaults; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.proxy.Proxies; +import forestry.farming.logic.FarmableFarmCraftory; + +@PluginInfo(pluginID = "FarmCraftory", name = "FarmCraftory", author = "SirSengir", url = Defaults.URL, description = "Enables compatibility with FarmCraftory. Adds crops and vegetables to farms.") +public class PluginFarmCraftory extends NativePlugin { + + public static Block blockSingle; + public static Block blockMulti; + + public static Class classSingle; + public static Class classMulti; + + public static Method methodGrowthSingle; + public static Method methodGrowthMulti; + + public static HashMap vegetableSeeds = new HashMap(); + public static final String[] seedIdentifiers = new String[] { "turnipSeedBag", "cabbageSeedBag", "onionSeedBag", "spinachSeedBag", "leekSeedBag", + "cucumberSeedBag", "tomatoSeedBag", "eggplantSeedBag", "greenPepperSeedBag", "yamSeedBag", "strawberrySeedBag", "pineappleSeedBag" }; + public static HashMap vegetableItems = new HashMap(); + public static final String[] vegetableIdentifiers = new String[] { "turnipItem", "cabbageItem", "onionItem", "spinachItem", "leekItem", "cucumberItem", + "tomatoItem", "eggplantItem", "greenPepperItem", "yamItem", "strawberryItem", "pineappleItem" }; + + public static HashMap cerealSeeds = new HashMap(); + public static final String[] cseedIdentifiers = new String[] { "cornSeedBag" }; + public static HashMap cerealItems = new HashMap(); + public static final String[] cerealIdentifiers = new String[] { "cornItem" }; + + @Override + public boolean isAvailable() { + return Proxies.common.isModLoaded("FarmCraftory"); + } + + @Override + public void doInit() { + super.doInit(); + + try { + + blockSingle = (Block) Class.forName("farmcraftory.FarmCraftory").getField("singleHarvest").get(null); + blockMulti = (Block) Class.forName("farmcraftory.FarmCraftory").getField("multiHarvest").get(null); + + classSingle = Class.forName("farmcraftory.TileEntitySingleHarvest"); + classMulti = Class.forName("farmcraftory.TileEntityMultiHarvest"); + + methodGrowthSingle = classSingle.getMethod("getGrowthStage"); + methodGrowthMulti = classMulti.getMethod("getGrowthStage"); + + for (String str : seedIdentifiers) + try { + vegetableSeeds.put(str, new ItemStack((Item) Class.forName("farmcraftory.FarmCraftory").getField(str).get(null))); + } catch (Exception ex) { + Proxies.log.info("FarmCraftory item '%s' could not be integrated.", str); + Proxies.log.info(ex.getMessage()); + } + + for (String str : vegetableIdentifiers) + try { + vegetableItems.put(str, new ItemStack((Item) Class.forName("farmcraftory.FarmCraftory").getField(str).get(null))); + } catch (Exception ex) { + Proxies.log.info("FarmCraftory item '%s' could not be integrated.", str); + Proxies.log.info(ex.getMessage()); + } + + for (String str : cseedIdentifiers) + try { + cerealSeeds.put(str, new ItemStack((Item) Class.forName("farmcraftory.FarmCraftory").getField(str).get(null))); + } catch (Exception ex) { + Proxies.log.info("FarmCraftory item '%s' could not be integrated.", str); + Proxies.log.info(ex.getMessage()); + } + + for (String str : cerealIdentifiers) + try { + cerealItems.put(str, new ItemStack((Item) Class.forName("farmcraftory.FarmCraftory").getField(str).get(null))); + } catch (Exception ex) { + Proxies.log.info("FarmCraftory item '%s' could not be integrated.", str); + Proxies.log.info(ex.getMessage()); + } + + if (blockMulti != null && blockSingle != null) { + Farmables.farmables.get("farmWheat").add(new FarmableFarmCraftory(cerealSeeds.values(), cerealItems.values())); + Farmables.farmables.get("farmVegetables").add(new FarmableFarmCraftory(vegetableSeeds.values(), vegetableItems.values())); + } + + } catch (Exception ex) { + Proxies.log.info("FarmCraftory plugin unexpectedly failed to load."); + Proxies.log.info(ex.getMessage()); + } + } + + public static int getGrowthStage(TileEntity tile) { + try { + if (classSingle.isInstance(tile)) + return (Integer) methodGrowthSingle.invoke(tile); + else if (classMulti.isInstance(tile)) + return (Integer) methodGrowthMulti.invoke(tile); + } catch (Exception ex) { + return 0; + } + + return 0; + } + + @Override + public IGuiHandler getGuiHandler() { + return null; + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } + + @Override + protected void registerItems() { + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerCrates() { + } + + @Override + protected void registerRecipes() { + } + +} diff --git a/forestry_common/farming/forestry/plugins/PluginFarming.java b/forestry_common/farming/forestry/plugins/PluginFarming.java new file mode 100755 index 000000000..3fc36428f --- /dev/null +++ b/forestry_common/farming/forestry/plugins/PluginFarming.java @@ -0,0 +1,359 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.common.registry.GameData; +import cpw.mods.fml.common.registry.GameRegistry; + +import net.minecraftforge.common.MinecraftForge; + +import forestry.api.circuits.ChipsetManager; +import forestry.api.circuits.ICircuitLayout; +import forestry.api.core.PluginInfo; +import forestry.api.farming.Farmables; +import forestry.api.farming.IFarmable; +import forestry.core.circuits.Circuit; +import forestry.core.circuits.CircuitLayout; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.proxy.Proxies; +import forestry.core.triggers.Trigger; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.farming.EventHandlerFarming; +import forestry.farming.FarmHelper; +import forestry.farming.GuiHandlerFarming; +import forestry.farming.circuits.CircuitFarmLogic; +import forestry.farming.gadgets.BlockFarm; +import forestry.farming.gadgets.BlockMushroom; +import forestry.farming.gadgets.TileControl; +import forestry.farming.gadgets.TileFarm.EnumFarmBlock; +import forestry.farming.gadgets.TileFarmPlain; +import forestry.farming.gadgets.TileGearbox; +import forestry.farming.gadgets.TileHatch; +import forestry.farming.gadgets.TileValve; +import forestry.farming.items.ItemFarmBlock; +import forestry.farming.logic.FarmLogicArboreal; +import forestry.farming.logic.FarmLogicCereal; +import forestry.farming.logic.FarmLogicCocoa; +import forestry.farming.logic.FarmLogicGourd; +import forestry.farming.logic.FarmLogicInfernal; +import forestry.farming.logic.FarmLogicOrchard; +import forestry.farming.logic.FarmLogicPeat; +import forestry.farming.logic.FarmLogicPoale; +import forestry.farming.logic.FarmLogicRubber; +import forestry.farming.logic.FarmLogicShroom; +import forestry.farming.logic.FarmLogicSucculent; +import forestry.farming.logic.FarmLogicVegetable; +import forestry.farming.logic.FarmableGE; +import forestry.farming.logic.FarmableGenericCrop; +import forestry.farming.logic.FarmableGenericSapling; +import forestry.farming.logic.FarmableGourd; +import forestry.farming.logic.FarmableStacked; +import forestry.farming.logic.FarmableVanillaSapling; +import forestry.farming.logic.FarmableVanillaShroom; +import forestry.farming.proxy.ProxyFarming; +import forestry.farming.triggers.TriggerLowFertilizer; +import forestry.farming.triggers.TriggerLowLiquid; +import forestry.farming.triggers.TriggerLowSoil; + +@PluginInfo(pluginID = "Farming", name = "Farming", author = "SirSengir", url = Defaults.URL, description = "Adds automatic farms and harvesters for a wide variety of products.") +public class PluginFarming extends NativePlugin { + + @SidedProxy(clientSide = "forestry.farming.proxy.ClientProxyFarming", serverSide = "forestry.farming.proxy.ProxyFarming") + public static ProxyFarming proxy; + public static int modelIdFarmBlock; + public static ItemStack farmFertilizer; + public static Trigger lowResourceLiquid50; + public static Trigger lowResourceLiquid25; + public static Trigger lowSoil128; + public static Trigger lowSoil64; + public static Trigger lowSoil32; + public static Trigger lowFertilizer50; + public static Trigger lowFertilizer25; + + @Override + public boolean isAvailable() { + return !Config.disableFarming; + } + + @Override + public void preInit() { + super.preInit(); + + Farmables.farmInterface = new FarmHelper(); + + ForestryBlock.mushroom = new BlockMushroom(); + + Farmables.farmables.put("farmArboreal", new ArrayList()); + Farmables.farmables.get("farmArboreal").add(new FarmableVanillaSapling()); + Farmables.farmables.get("farmArboreal").add(new FarmableGE()); + + Farmables.farmables.put("farmShroom", new ArrayList()); + Farmables.farmables.get("farmShroom").add(new FarmableVanillaShroom(Blocks.brown_mushroom, 0)); + Farmables.farmables.get("farmShroom").add(new FarmableVanillaShroom(Blocks.red_mushroom, 0)); + + Farmables.farmables.put("farmWheat", new ArrayList()); + Farmables.farmables.get("farmWheat").add(new FarmableGenericCrop(new ItemStack(Items.wheat_seeds), Blocks.wheat, 7)); + + Farmables.farmables.put("farmGourd", new ArrayList()); + Farmables.farmables.get("farmGourd").add( + new FarmableGourd(new ItemStack(Items.pumpkin_seeds), new ItemStack(Blocks.pumpkin_stem), new ItemStack(Blocks.pumpkin))); + Farmables.farmables.get("farmGourd").add(new FarmableGourd(new ItemStack(Items.melon_seeds), new ItemStack(Blocks.melon_stem), new ItemStack(Blocks.melon_block))); + + Farmables.farmables.put("farmInfernal", new ArrayList()); + Farmables.farmables.get("farmInfernal").add(new FarmableGenericCrop(new ItemStack(Items.nether_wart), Blocks.nether_wart, 3)); + + Farmables.farmables.put("farmPoales", new ArrayList()); + Farmables.farmables.get("farmPoales").add(new FarmableStacked(Blocks.reeds, 3)); + + Farmables.farmables.put("farmSucculentes", new ArrayList()); + Farmables.farmables.get("farmSucculentes").add(new FarmableStacked(Blocks.cactus, 3)); + + Farmables.farmables.put("farmVegetables", new ArrayList()); + Farmables.farmables.get("farmVegetables").add(new FarmableGenericCrop(new ItemStack(Items.potato), Blocks.potatoes, 7)); + Farmables.farmables.get("farmVegetables").add(new FarmableGenericCrop(new ItemStack(Items.carrot), Blocks.carrots, 7)); + + ForestryBlock.farm = new BlockFarm().setBlockName("ffarm"); + Proxies.common.registerBlock(ForestryBlock.farm, ItemFarmBlock.class); + /*Item.itemsList[ForestryBlock.farm] = null; + Item.itemsList[ForestryBlock.farm] = (new ItemFarmBlock(ForestryBlock.farm - 256, "ffarm"));*/ + ForestryBlock.farm.setHarvestLevel("pickaxe", 0); + + proxy.initializeRendering(); + + // Triggers + lowResourceLiquid50 = new TriggerLowLiquid("lowLiquid.50", 0.5f); + lowResourceLiquid25 = new TriggerLowLiquid("lowLiquid.25", 0.25f); + lowSoil128 = new TriggerLowSoil(128); + lowSoil64 = new TriggerLowSoil(64); + lowSoil32 = new TriggerLowSoil(32); + lowFertilizer50 = new TriggerLowFertilizer("lowFertilizer.50", 0.5f); + lowFertilizer25 = new TriggerLowFertilizer("lowFertilizer.25", 0.25f); + + // Layouts + ICircuitLayout layoutManaged = new CircuitLayout("farms.managed"); + ChipsetManager.circuitRegistry.registerLayout(layoutManaged); + ICircuitLayout layoutManual = new CircuitLayout("farms.manual"); + ChipsetManager.circuitRegistry.registerLayout(layoutManual); + } + + @Override + public void doInit() { + super.doInit(); + + proxy.addLocalizations(); + + GameRegistry.registerTileEntity(TileFarmPlain.class, "forestry.Farm"); + GameRegistry.registerTileEntity(TileGearbox.class, "forestry.FarmGearbox"); + GameRegistry.registerTileEntity(TileHatch.class, "forestry.FarmHatch"); + GameRegistry.registerTileEntity(TileValve.class, "forestry.FarmValve"); + GameRegistry.registerTileEntity(TileControl.class, "forestry.FarmControl"); + + Circuit.farmArborealManaged = new CircuitFarmLogic("managedArboreal", FarmLogicArboreal.class, new String[] { "Arboreal Plants" }); + Circuit.farmShroomManaged = new CircuitFarmLogic("managedShroom", FarmLogicShroom.class, new String[] { "Mushrooms" }); + Circuit.farmPeatManaged = new CircuitFarmLogic("managedPeat", FarmLogicPeat.class, new String[] { "Peat Bog" }); + Circuit.farmCerealManaged = new CircuitFarmLogic("managedCereal", FarmLogicCereal.class, new String[] { "Crops" }); + Circuit.farmVegetableManaged = new CircuitFarmLogic("managedVegetable", FarmLogicVegetable.class, new String[] { "Vegetables" }); + Circuit.farmInfernalManaged = new CircuitFarmLogic("managedInfernal", FarmLogicInfernal.class, new String[] { "Infernal Crops" }); + + Circuit.farmPeatManual = new CircuitFarmLogic("manualPeat", FarmLogicPeat.class, new String[] { "Peat Bog" }).setManual(); + Circuit.farmShroomManual = new CircuitFarmLogic("manualShroom", FarmLogicShroom.class, new String[] { "Mushrooms" }).setManual(); + Circuit.farmCerealManual = new CircuitFarmLogic("manualCereal", FarmLogicCereal.class, new String[] { "Crops" }).setManual(); + Circuit.farmVegetableManual = new CircuitFarmLogic("manualVegetable", FarmLogicVegetable.class, new String[] { "Vegetables" }).setManual(); + Circuit.farmSucculentManual = new CircuitFarmLogic("manualSucculent", FarmLogicSucculent.class, new String[] { "Succulents" }).setManual(); + Circuit.farmPoalesManual = new CircuitFarmLogic("manualPoales", FarmLogicPoale.class, new String[] { "Reeds" }).setManual(); + Circuit.farmGourdManual = new CircuitFarmLogic("manualGourd", FarmLogicGourd.class, new String[] { "Gourds" }).setManual(); + Circuit.farmCocoaManual = new CircuitFarmLogic("manualCocoa", FarmLogicCocoa.class, new String[] { "Cocoa Plantation" }).setManual(); + + Circuit.farmOrchardManual = new CircuitFarmLogic("manualOrchard", FarmLogicOrchard.class, new String[] { "Orchard" }); + Circuit.farmRubberManual = new CircuitFarmLogic("manualRubber", FarmLogicRubber.class, new String[] { "Rubber Plantation" }); + + MinecraftForge.EVENT_BUS.register(new EventHandlerFarming()); + } + + @Override + public void postInit() { + super.postInit(); + farmFertilizer = ForestryItem.fertilizerCompound.getItemStack(); + } + + @Override + public boolean processIMCMessage(IMCMessage message) { + + if (message.key.equals("add-farmable-sapling")) { + String[] tokens = message.getStringValue().split("@"); + String errormsg = String.format("Received an invalid 'add-farmable-sapling' request '%s' from mod %s", message.getStringValue(), + message.getSender()); + if (tokens.length != 2) { + Proxies.log.info(errormsg + "."); + return true; + } + + if (!Farmables.farmables.containsKey(tokens[0])) { + Proxies.log.info("%s for non-existent farm %s.", errormsg, tokens[0]); + return true; + } + + String[] items = tokens[1].split("[\\.]+"); + if (items.length != 2 && items.length != 4) { + Proxies.log.info("%s for farm '%s': id definitions did not match.", errormsg, tokens[0]); + return true; + } + + try { + Block sapling = GameData.blockRegistry.getObject(items[0]); + if (sapling == null || sapling == Blocks.air) throw new RuntimeException("can't find block for "+items[0]); + + if (items.length == 2) { + Farmables.farmables.get(tokens[0]).add(new FarmableGenericSapling(sapling, Integer.parseInt(items[1]))); + } else { + Item windfall = GameData.itemRegistry.getObject(items[2]); + if (windfall == null) throw new RuntimeException("can't find item for "+items[2]); + + Farmables.farmables.get(tokens[0]).add( + new FarmableGenericSapling(sapling, Integer.parseInt(items[1]), + new ItemStack(windfall, 1, Integer.parseInt(items[3])))); + } + } catch (Exception ex) { + Proxies.log.info("%s for farm '%s': ", errormsg, tokens[0], ex.getMessage()); + } + return true; + + } else if (message.key.equals("add-farmable-crop")) { + + String[] tokens = message.getStringValue().split("@"); + String errormsg = String.format("Received an invalid 'add-farmable-crop' request '%s' from mod %s", message.getStringValue(), message.getSender()); + if (tokens.length != 2) { + Proxies.log.info(errormsg + "."); + return true; + } + + if (!Farmables.farmables.containsKey(tokens[0])) { + Proxies.log.info("%s for non-existent farm %s.", errormsg, tokens[0]); + return true; + } + + String[] items = tokens[1].split("[\\.]+"); + if (items.length != 4) { + Proxies.log.info("%s for farm '%s': id definitions did not match.", errormsg, tokens[0]); + return true; + } + + try { + Item seed = GameData.itemRegistry.getObject(items[0]); + if (seed == null) throw new RuntimeException("can't find item for "+items[0]); + Block crop = GameData.blockRegistry.getObject(items[2]); + if (crop == null || crop == Blocks.air) throw new RuntimeException("can't find block for "+items[2]); + + Farmables.farmables.get(tokens[0]).add( + new FarmableGenericCrop(new ItemStack(seed, 1, Integer.parseInt(items[1])), + crop, + Integer.parseInt(items[3]))); + } catch (Exception ex) { + Proxies.log.info("%s for farm '%s': ", errormsg, tokens[0], ex.getMessage()); + } + + return true; + } + + return false; + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerFarming(); + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } + + @Override + protected void registerItems() { + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerCrates() { + } + + @Override + protected void registerRecipes() { + + ItemStack basic = new ItemStack(ForestryBlock.farm, 1, 0); + for (EnumFarmBlock block : EnumFarmBlock.values()) { + NBTTagCompound compound = new NBTTagCompound(); + block.saveToCompound(compound); + + basic.setTagCompound((NBTTagCompound) compound.copy()); + ShapedRecipeCustom.buildRecipe(basic.copy(), "I#I", "WCW", '#', block.getCraftingIngredient(), 'W', "slabWood", 'C', ForestryItem.tubes.getItemStack(1, 1), 'I', "ingotCopper"); + + } + + ItemStack gearbox = new ItemStack(ForestryBlock.farm, 1, 2); + ShapedRecipeCustom.buildRecipe(gearbox, " # ", "TTT", '#', basic, 'T', "gearTin").setPreserveNBT(); + + ItemStack hatch = new ItemStack(ForestryBlock.farm, 1, 3); + ShapedRecipeCustom.buildRecipe(hatch, " # ", "TDT", '#', basic, 'T', "gearTin", 'D', Blocks.trapdoor).setPreserveNBT(); + + ItemStack valve = new ItemStack(ForestryBlock.farm, 1, 4); + ShapedRecipeCustom.buildRecipe(valve, " # ", "XTX", '#', basic, 'T', "gearTin", 'X', Blocks.glass).setPreserveNBT(); + + ItemStack control = new ItemStack(ForestryBlock.farm, 1, 5); + ShapedRecipeCustom.buildRecipe(control, " # ", "XTX", '#', basic, 'T', ForestryItem.tubes.getItemStack(1, 4), 'X', Items.redstone).setPreserveNBT(); + + // Circuits + ICircuitLayout layoutManaged = ChipsetManager.circuitRegistry.getLayout("forestry.farms.managed"); + ICircuitLayout layoutManual = ChipsetManager.circuitRegistry.getLayout("forestry.farms.manual"); + + ChipsetManager.solderManager.addRecipe(layoutManaged, ForestryItem.tubes.getItemStack(1, 0), Circuit.farmArborealManaged); + ChipsetManager.solderManager.addRecipe(layoutManaged, ForestryItem.tubes.getItemStack(1, 1), Circuit.farmPeatManaged); + ChipsetManager.solderManager.addRecipe(layoutManaged, ForestryItem.tubes.getItemStack(1, 2), Circuit.farmCerealManaged); + ChipsetManager.solderManager.addRecipe(layoutManaged, ForestryItem.tubes.getItemStack(1, 3), Circuit.farmVegetableManaged); + ChipsetManager.solderManager.addRecipe(layoutManaged, ForestryItem.tubes.getItemStack(1, 7), Circuit.farmInfernalManaged); + ChipsetManager.solderManager.addRecipe(layoutManaged, ForestryItem.tubes.getItemStack(1, 10), Circuit.farmShroomManaged); + + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 0), Circuit.farmOrchardManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 1), Circuit.farmPeatManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 2), Circuit.farmCerealManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 3), Circuit.farmVegetableManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 4), Circuit.farmSucculentManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 5), Circuit.farmPoalesManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 6), Circuit.farmGourdManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 10), Circuit.farmShroomManual); + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 11), Circuit.farmCocoaManual); + + if (PluginIC2.resin != null && PluginIC2.rubberwood != null) + ChipsetManager.solderManager.addRecipe(layoutManual, ForestryItem.tubes.getItemStack(1, 8), Circuit.farmRubberManual); + } +} diff --git a/forestry_common/farming/forestry/plugins/PluginNatura.java b/forestry_common/farming/forestry/plugins/PluginNatura.java new file mode 100755 index 000000000..de9f585fc --- /dev/null +++ b/forestry_common/farming/forestry/plugins/PluginNatura.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.event.FMLInterModComms; +import cpw.mods.fml.common.registry.GameRegistry; + +import forestry.api.recipes.RecipeManagers; +import forestry.core.GameMode; +import forestry.core.config.Defaults; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; + +public class PluginNatura extends NativePlugin { + + private static final String NATURA = "Natura"; + + public static Block logNatura; + public static Block logWillow; + + public static Block leavesNatura; + public static Block saplingNatura; + + @Override + public boolean isAvailable() { + return Proxies.common.isModLoaded(NATURA); + } + + @Override + public void doInit() { + super.doInit(); + + logNatura = GameRegistry.findBlock(NATURA, "tree"); + logWillow = GameRegistry.findBlock(NATURA, "willow"); + leavesNatura = GameRegistry.findBlock(NATURA, "floraleaves"); + saplingNatura = GameRegistry.findBlock(NATURA, "florasapling"); + + if(saplingNatura != null) + FMLInterModComms.sendMessage(Defaults.MOD, "add-farmable-sapling", String.format("farmArboreal@%s.-1", saplingNatura)); + } + + @Override protected void registerItems() {} + @Override protected void registerBackpackItems() {} + @Override protected void registerCrates() {} + @Override + protected void registerRecipes() { + ItemStack seedBarley = GameRegistry.findItemStack(NATURA, "seedBarley", 1); + ItemStack seedCotton = GameRegistry.findItemStack(NATURA, "seedCotton", 1); + + ArrayList seedList = new ArrayList(); + if (seedBarley != null) + seedList.add(seedBarley); + if (seedCotton != null) + seedList.add(seedCotton); + + int amount = GameMode.getGameMode().getIntegerSetting("squeezer.liquid.seed"); + for (int i = 0; i < seedList.size(); ++i) { + RecipeManagers.squeezerManager.addRecipe(10, new ItemStack[] { seedList.get(i) }, + LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, amount)); + } + + ItemStack berryBlight = GameRegistry.findItemStack(NATURA, "berryBlight", 1); + ItemStack berryDusk = GameRegistry.findItemStack(NATURA, "berryDusk", 1); + ItemStack berrySky = GameRegistry.findItemStack(NATURA, "berrySting", 1); + ItemStack berrySting = GameRegistry.findItemStack(NATURA, "berrySting", 1); + ItemStack berryRasp = GameRegistry.findItemStack(NATURA, "berryRasp", 1); + ItemStack berryBlue = GameRegistry.findItemStack(NATURA, "berryBlue", 1); + ItemStack berryBlack = GameRegistry.findItemStack(NATURA, "berryBlack", 1); + ItemStack berryMalo = GameRegistry.findItemStack(NATURA, "berryMalo", 1); + + ArrayList berries = new ArrayList(); + if (berryBlight != null) + berries.add(berryBlight); + if (berryDusk != null) + berries.add(berryDusk); + if (berrySky != null) + berries.add(berrySky); + if (berrySting!= null) + berries.add(berrySting); + if (berryRasp != null) + berries.add(berryRasp); + if (berryBlue != null) + berries.add(berryBlue); + if (berryBlack != null) + berries.add(berryBlack); + if (berryMalo != null) + berries.add(berryMalo); + + amount = GameMode.getGameMode().getIntegerSetting("squeezer.liquid.apple") / 25; + amount = (amount > 1) ? amount : 1; // Produce at least 1 mb of juice. + for (int i = 0; i < berries.size(); ++i) { + RecipeManagers.squeezerManager.addRecipe(3, new ItemStack[] { berries.get(i) }, + LiquidHelper.getLiquid(Defaults.LIQUID_JUICE, amount)); + } + } + +} diff --git a/forestry_common/food/forestry/food/BeverageEffect.java b/forestry_common/food/forestry/food/BeverageEffect.java new file mode 100755 index 000000000..621f19684 --- /dev/null +++ b/forestry_common/food/forestry/food/BeverageEffect.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food; + +import forestry.api.food.BeverageManager; +import forestry.api.food.IBeverageEffect; +import forestry.core.utils.StringUtil; + +public abstract class BeverageEffect implements IBeverageEffect { + + public static final IBeverageEffect weakAlcoholic = new BeverageEffectDrunk(10, 0.2f); + public static final IBeverageEffect weakAntidote = new BeverageEffectAntidote(20, 0.5f); + public static final IBeverageEffect strongAntidote = new BeverageEffectAntidote(21, 1.0f); + + private int id; + protected String description; + + public BeverageEffect(int id) { + this.id = id; + + if (BeverageManager.effectList[id] != null) + throw new RuntimeException("Beverage effect slot " + id + " was already occupied by " + BeverageManager.effectList[id].toString() + + " when trying to add " + this.toString()); + else + BeverageManager.effectList[id] = this; + } + + public int getId() { + return this.id; + } + + public String getLevel() { + return null; + } + + @Override + public String getDescription() { + if (getLevel() != null) + return StringUtil.localize(description) + " " + getLevel(); + else + return StringUtil.localize(description); + } +} diff --git a/forestry_common/food/forestry/food/BeverageEffectAntidote.java b/forestry_common/food/forestry/food/BeverageEffectAntidote.java new file mode 100755 index 000000000..5db04f482 --- /dev/null +++ b/forestry_common/food/forestry/food/BeverageEffectAntidote.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.potion.Potion; +import net.minecraft.world.World; + +import forestry.core.proxy.Proxies; + +public class BeverageEffectAntidote extends BeverageEffect { + + private float chance = 0.2f; + + public BeverageEffectAntidote(int id, float chance) { + super(id); + this.chance = chance; + this.description = "beverage.effect.antidote"; + } + + @Override + public void doEffect(World world, EntityPlayer player) { + + if (world.rand.nextFloat() >= chance) + return; + + Proxies.common.removePotionEffect(player, Potion.poison); + } + + @Override + public String getLevel() { + if (chance > 0.5f) + return "III"; + else if (chance > 0.2f) + return "II"; + else + return "I"; + } + +} diff --git a/forestry_common/food/forestry/food/BeverageEffectDrunk.java b/forestry_common/food/forestry/food/BeverageEffectDrunk.java new file mode 100755 index 000000000..f99343cec --- /dev/null +++ b/forestry_common/food/forestry/food/BeverageEffectDrunk.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.world.World; + +public class BeverageEffectDrunk extends BeverageEffect { + + private PotionEffect drunkEffect; + private float chance = 0.2f; + + public BeverageEffectDrunk(int id, float chance) { + super(id); + this.chance = chance; + this.description = "beverage.effect.alcoholic"; + drunkEffect = new PotionEffect(Potion.confusion.id, 25 * 20, 0); + } + + @Override + public void doEffect(World world, EntityPlayer player) { + if (world.rand.nextFloat() < chance) + player.addPotionEffect(drunkEffect); + } + +} diff --git a/forestry_common/food/forestry/food/GuiHandlerFood.java b/forestry_common/food/forestry/food/GuiHandlerFood.java new file mode 100755 index 000000000..6b42608dd --- /dev/null +++ b/forestry_common/food/forestry/food/GuiHandlerFood.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; +import forestry.food.gui.ContainerInfuser; +import forestry.food.gui.GuiInfuser; +import forestry.food.items.ItemInfuser.InfuserInventory; + +public class GuiHandlerFood extends GuiHandlerBase { + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + + case InfuserGUI: + return new GuiInfuser(player.inventory, new InfuserInventory(player)); + + default: + return null; + } + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + + case InfuserGUI: + return new ContainerInfuser(player.inventory, new InfuserInventory(player)); + + default: + return null; + + } + } +} diff --git a/forestry_common/food/forestry/food/gui/ContainerInfuser.java b/forestry_common/food/forestry/food/gui/ContainerInfuser.java new file mode 100755 index 000000000..df819b1c0 --- /dev/null +++ b/forestry_common/food/forestry/food/gui/ContainerInfuser.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.proxy.Proxies; +import forestry.food.items.ItemBeverage; +import forestry.food.items.ItemInfuser.InfuserInventory; + +public class ContainerInfuser extends ContainerForestry { + + InfuserInventory inventory; + + public ContainerInfuser(InventoryPlayer inventoryplayer, InfuserInventory inventory) { + super(inventory); + this.inventory = inventory; + + // Input + this.addSlot(new SlotCustom(inventory, 0, 152, 12, ForestryItem.beverage.getItemStack())); + + // Output + this.addSlot(new SlotCustom(inventory, 1, 152, 72, ItemBeverage.class)); + + // Ingredients + this.addSlot(new Slot(inventory, 2, 12, 12)); + this.addSlot(new Slot(inventory, 3, 12, 32)); + this.addSlot(new Slot(inventory, 4, 12, 52)); + this.addSlot(new Slot(inventory, 5, 12, 72)); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSlot(new Slot(inventoryplayer, l1 + i1 * 9 + 9, 8 + l1 * 18, 103 + i1 * 18)); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSlot(new Slot(inventoryplayer, j1, 8 + j1 * 18, 161)); + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(entityplayer.worldObj)) + return; + + // Drop everything still in there. + for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + Proxies.common.dropItemPlayer(entityplayer, stack); + inventory.setInventorySlotContents(i, null); + } + + } +} diff --git a/forestry_common/food/forestry/food/gui/GuiInfuser.java b/forestry_common/food/forestry/food/gui/GuiInfuser.java new file mode 100755 index 000000000..133a6c490 --- /dev/null +++ b/forestry_common/food/forestry/food/gui/GuiInfuser.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.IInventory; + +import forestry.api.food.BeverageManager; +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.GuiForestry; +import forestry.food.items.ItemInfuser.InfuserInventory; + +public class GuiInfuser extends GuiForestry { + + private final IInventory inventory; + private int startX; + private int startY; + + public GuiInfuser(InventoryPlayer inventoryplayer, InfuserInventory inventory) { + super(Defaults.TEXTURE_PATH_GUI + "/infuser.png", new ContainerInfuser(inventoryplayer, inventory), inventory); + + this.inventory = inventory; + + xSize = 176; + ySize = 185; + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + for (int l = 2; l < inventory.getSizeInventory(); l++) { + String description = BeverageManager.ingredientManager.getDescription(inventory.getStackInSlot(l)); + if (description == null) + description = "(No effect)"; + + int row = (l - 2) * 20; + fontRendererObj.drawString(description, startX + 32, startY + 16 + row, fontColor.get("gui.screen")); + } + } + + @Override + public void initGui() { + super.initGui(); + + startX = (this.width - this.xSize) / 2; + startY = (this.height - this.ySize) / 2; + } +} diff --git a/forestry_common/food/forestry/food/items/ItemAmbrosia.java b/forestry_common/food/forestry/food/items/ItemAmbrosia.java new file mode 100755 index 000000000..a99fc552c --- /dev/null +++ b/forestry_common/food/forestry/food/items/ItemAmbrosia.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food.items; + +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; + +import forestry.core.config.Defaults; +import forestry.core.items.ItemForestryFood; + +public class ItemAmbrosia extends ItemForestryFood { + + public ItemAmbrosia() { + super(Defaults.FOOD_AMBROSIA_HEAL, 0.6f); + setAlwaysEdible(); + setPotionEffect(Potion.regeneration.id, 40, 0, 1.0F); + } + + @Override + public boolean hasEffect(ItemStack itemstack) { + return true; + } + +} diff --git a/forestry_common/food/forestry/food/items/ItemBeverage.java b/forestry_common/food/forestry/food/items/ItemBeverage.java new file mode 100755 index 000000000..4dbe5869d --- /dev/null +++ b/forestry_common/food/forestry/food/items/ItemBeverage.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food.items; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.food.BeverageManager; +import forestry.api.food.IBeverageEffect; +import forestry.core.CreativeTabForestry; +import forestry.core.config.Config; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; + +public class ItemBeverage extends Item { + + public static class BeverageInfo { + + public final String name; + private final String iconType; + public final int primaryColor; + public final int secondaryColor; + + @SideOnly(Side.CLIENT) + public IIcon iconBottle; + @SideOnly(Side.CLIENT) + public IIcon iconContents; + + public final int heal; + public final float saturation; + public final boolean isAlwaysEdible; + + public boolean isSecret = false; + + public BeverageInfo(String name, String iconType, int primaryColor, int secondaryColor, int heal, float saturation, boolean isAlwaysEdible) { + this.name = name; + this.iconType = iconType; + this.primaryColor = primaryColor; + this.secondaryColor = secondaryColor; + this.heal = heal; + this.saturation = saturation; + this.isAlwaysEdible = isAlwaysEdible; + } + + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister register) { + iconBottle = TextureManager.getInstance().registerTex(register, "liquids/" + iconType + ".bottle"); + iconContents = TextureManager.getInstance().registerTex(register, "liquids/" + iconType + ".contents"); + } + + public IBeverageEffect[] loadEffects(ItemStack stack) { + IBeverageEffect[] effects = new IBeverageEffect[0]; + + NBTTagCompound nbttagcompound = stack.getTagCompound(); + if (nbttagcompound == null) + return effects; + + if (nbttagcompound.hasKey("E")) { + int effectLength = nbttagcompound.getInteger("L"); + NBTTagList nbttaglist = nbttagcompound.getTagList("E", 10); + effects = new IBeverageEffect[effectLength]; + for (int i = 0; i < nbttaglist.tagCount(); i++) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); + byte byte0 = nbttagcompound1.getByte("S"); + if (byte0 >= 0 && byte0 < effects.length) + effects[byte0] = BeverageManager.effectList[nbttagcompound1.getInteger("ID")]; + } + } + + return effects; + } + + public void saveEffects(ItemStack stack, IBeverageEffect[] effects) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + + NBTTagList nbttaglist = new NBTTagList(); + nbttagcompound.setInteger("L", effects.length); + for (int i = 0; i < effects.length; i++) + if (effects[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("S", (byte) i); + nbttagcompound1.setInteger("ID", effects[i].getId()); + nbttaglist.appendTag(nbttagcompound1); + } + nbttagcompound.setTag("E", nbttaglist); + + stack.setTagCompound(nbttagcompound); + } + + } + + public BeverageInfo[] beverages; + + public ItemBeverage(BeverageInfo... beverages) { + super(); + setMaxStackSize(1); + this.beverages = beverages; + setCreativeTab(CreativeTabForestry.tabForestry); + } + + /** + * @return true if the item's stackTagCompound needs to be synchronized over SMP. + */ + @Override + public boolean getShareTag() { + return true; + } + + @Override + public ItemStack onEaten(ItemStack itemstack, World world, EntityPlayer entityplayer) { + + int meta = itemstack.getItemDamage(); + BeverageInfo beverage = beverages[meta]; + IBeverageEffect[] effects = beverage.loadEffects(itemstack); + + itemstack.stackSize--; + entityplayer.getFoodStats().addStats(beverage.heal, beverage.saturation); + world.playSoundAtEntity(entityplayer, "random.burp", 0.5F, world.rand.nextFloat() * 0.1F + 0.9F); + + if (!Proxies.common.isSimulating(world)) + return itemstack; + + for (IBeverageEffect effect : effects) + effect.doEffect(world, entityplayer); + + return itemstack; + } + + @Override + public int getMaxItemUseDuration(ItemStack itemstack) { + return 32; + } + + @Override + public EnumAction getItemUseAction(ItemStack itemstack) { + return EnumAction.drink; + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + + int meta = itemstack.getItemDamage(); + BeverageInfo beverage = beverages[meta]; + + if (entityplayer.canEat(beverage.isAlwaysEdible)) + entityplayer.setItemInUse(itemstack, getMaxItemUseDuration(itemstack)); + return itemstack; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + for (int i = 0; i < beverages.length; i++) + if (Config.isDebug || !beverages[i].isSecret) + itemList.add(new ItemStack(this, 1, i)); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + int meta = itemstack.getItemDamage(); + BeverageInfo beverage = beverages[meta]; + IBeverageEffect[] effects = beverage.loadEffects(itemstack); + + for (IBeverageEffect effect : effects) + if (effect.getDescription() != null) + list.add(effect.getDescription()); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + return StringUtil.localize("item.beverage." + beverages[itemstack.getItemDamage()].name); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + for (BeverageInfo info : beverages) + info.registerIcons(register); + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int i, int j) { + if (j > 0 && beverages[i].secondaryColor != 0) + return beverages[i].iconBottle; + else + return beverages[i].iconContents; + } + + // Return true to enable color overlay + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int j) { + + if (j == 0 || beverages[itemstack.getItemDamage()].secondaryColor == 0) + return beverages[itemstack.getItemDamage()].primaryColor; + else + return beverages[itemstack.getItemDamage()].secondaryColor; + } + +} diff --git a/forestry_common/food/forestry/food/items/ItemInfuser.java b/forestry_common/food/forestry/food/items/ItemInfuser.java new file mode 100755 index 000000000..1e26f6dc3 --- /dev/null +++ b/forestry_common/food/forestry/food/items/ItemInfuser.java @@ -0,0 +1,394 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.food.items; + +import java.util.ArrayList; +import java.util.Arrays; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.core.ForestryAPI; +import forestry.api.food.BeverageManager; +import forestry.api.food.IBeverageEffect; +import forestry.api.food.IInfuserManager; +import forestry.api.food.IIngredientManager; +import forestry.core.CreativeTabForestry; +import forestry.core.config.ForestryItem; +import forestry.core.items.ItemForestry; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.food.BeverageEffect; + +public class ItemInfuser extends ItemForestry { + + // / RECIPE MANAGMENT + /** + * Mixture describes the itemstacks required to achieve a certain effect. + */ + public static class Mixture { + + private final int meta; + private final ItemStack[] ingredients; + private final IBeverageEffect effect; + + public Mixture(int meta, ItemStack ingredient, IBeverageEffect effect) { + this(meta, new ItemStack[] { ingredient }, effect); + } + + public Mixture(int meta, ItemStack ingredients[], IBeverageEffect effect) { + this.meta = meta; + this.ingredients = ingredients; + this.effect = effect; + } + + public ItemStack[] getIngredients() { + return ingredients; + } + + public boolean isIngredient(ItemStack itemstack) { + for (ItemStack ingredient : ingredients) { + if (ingredient.getItemDamage() < 0 && ingredient.getItem() == itemstack.getItem()) + return true; + else if (ingredient.getItemDamage() >= 0 && ingredient.isItemEqual(itemstack)) + return true; + } + + return false; + } + + public boolean matches(ItemStack[] res) { + + // No recipe without resource! + if (res == null || res.length <= 0) + return false; + + boolean matchedAll = true; + + for (ItemStack stack : ingredients) { + boolean matched = false; + for (ItemStack matchStack : res) { + if (matchStack == null) + continue; + + // Check item matching + if (stack.getItemDamage() < 0 && stack.getItem() == matchStack.getItem()) { + if (stack.stackSize <= matchStack.stackSize) { + matched = true; + break; + } + } else if (stack.getItemDamage() >= 0 && stack.isItemEqual(matchStack)) + if (stack.stackSize <= matchStack.stackSize) { + matched = true; + break; + } + } + if (!matched) + matchedAll = false; + } + return matchedAll; + + } + + public IBeverageEffect getEffect() { + return this.effect; + } + + public int getMeta() { + return meta; + } + + public int getWeight() { + return ingredients.length; + } + } + + /** + * MixtureManager contains the available mixtures. + */ + public static class MixtureManager implements IInfuserManager { + + private final ArrayList mixtures = new ArrayList(); + + @Override + public void addMixture(int meta, ItemStack ingredient, IBeverageEffect effect) { + this.mixtures.add(new Mixture(meta, ingredient, effect)); + } + + @Override + public void addMixture(int meta, ItemStack[] ingredients, IBeverageEffect effect) { + this.mixtures.add(new Mixture(meta, ingredients, effect)); + } + + public boolean isIngredient(ItemStack itemstack) { + for (Mixture ingredient : mixtures) { + if (ingredient.isIngredient(itemstack)) + return true; + } + + return false; + } + + private Mixture[] getMatchingMixtures(ItemStack[] ingredients) { + + ArrayList matches = new ArrayList(); + + for (Mixture mixture : mixtures) { + if (mixture.matches(ingredients)) + matches.add(mixture); + } + + return matches.toArray(new Mixture[0]); + } + + @Override + public boolean hasMixtures(ItemStack[] ingredients) { + return getMatchingMixtures(ingredients).length > 0; + } + + @Override + public ItemStack[] getRequired(ItemStack[] ingredients) { + Mixture[] mixtures = getMatchingMixtures(ingredients); + ArrayList required = new ArrayList(); + + for (Mixture mixture : mixtures) { + required.addAll(Arrays.asList(mixture.getIngredients())); + } + + return required.toArray(new ItemStack[0]); + } + + @Override + public ItemStack getSeasoned(ItemStack base, ItemStack[] ingredients) { + Mixture[] mixtures = getMatchingMixtures(ingredients); + ArrayList effects = new ArrayList(); + effects.addAll(Arrays.asList(((ItemBeverage) base.getItem()).beverages[base.getItemDamage()].loadEffects(base))); + + int weight = 0; + int meta = 0; + for (Mixture mixture : mixtures) { + effects.add(mixture.getEffect()); + if (mixture.getWeight() > weight) { + weight = mixture.getWeight(); + meta = mixture.getMeta(); + } + } + + ItemStack seasoned = base.copy(); + seasoned.setItemDamage(meta); + ((ItemBeverage) base.getItem()).beverages[meta].saveEffects(seasoned, effects.toArray(new IBeverageEffect[0])); + return seasoned; + } + } + + public static class Ingredient { + + public final ItemStack ingredient; + public final String description; + + public Ingredient(ItemStack ingredient, String description) { + this.ingredient = ingredient; + this.description = description; + } + } + + public static class IngredientManager implements IIngredientManager { + + private final ArrayList ingredients = new ArrayList(); + + @Override + public void addIngredient(ItemStack ingredient, String description) { + this.ingredients.add(new Ingredient(ingredient, description)); + } + + @Override + public String getDescription(ItemStack itemstack) { + if (itemstack == null) + return null; + + for (Ingredient ingredient : ingredients) { + if (ingredient.ingredient.getItemDamage() < 0 && ingredient.ingredient.getItem() == itemstack.getItem()) + return ingredient.description; + else if (ingredient.ingredient.getItemDamage() >= 0 && ingredient.ingredient.isItemEqual(itemstack)) + return ingredient.description; + } + + return null; + } + } + + // / INVENTORY MANAGMENT + public static class InfuserInventory implements IInventory { + + private final ItemStack[] inventoryStacks = new ItemStack[6]; + private final short inputSlot = 0; + private final short outputSlot = 1; + private final short ingredientSlot1 = 2; + EntityPlayer player; + + public InfuserInventory(EntityPlayer player) { + this.player = player; + } + + private void trySeasoning() { + + // Need input + if (inventoryStacks[inputSlot] == null) + return; + + // Output slot may not be occupied + if (inventoryStacks[outputSlot] != null) + return; + + // Need a valid base + if (!inventoryStacks[inputSlot].isItemEqual(ForestryItem.beverage.getItemStack())) + return; + + // Create the seasoned item + ItemStack[] ingredients = new ItemStack[4]; + System.arraycopy(inventoryStacks, ingredientSlot1, ingredients, 0, 4); + + // Only continue if there is anything to season + if (!BeverageManager.infuserManager.hasMixtures(ingredients)) + return; + + ItemStack seasoned = BeverageManager.infuserManager.getSeasoned(inventoryStacks[inputSlot], ingredients); + if (seasoned == null) + return; + + // Remove required ingredients. + ItemStack[] toRemove = BeverageManager.infuserManager.getRequired(ingredients); + for (ItemStack templ : toRemove) { + ItemStack ghost = templ.copy(); + + for (int i = ingredientSlot1; i < this.getSizeInventory(); i++) { + if (inventoryStacks[i] == null) + continue; + if (ghost.stackSize <= 0) + break; + + if ((ghost.getItemDamage() >= 0 && inventoryStacks[i].isItemEqual(ghost)) + || (ghost.getItemDamage() < 0 && ghost.getItem() == inventoryStacks[i].getItem())) { + ItemStack removed = decrStackSize(i, 1); + ghost.stackSize -= removed.stackSize; + } + } + } + decrStackSize(inputSlot, 1); + inventoryStacks[outputSlot] = seasoned; + + } + + @Override + public ItemStack decrStackSize(int i, int j) { + if (inventoryStacks[i] == null) + return null; + + ItemStack product; + if (inventoryStacks[i].stackSize <= j) { + product = inventoryStacks[i]; + inventoryStacks[i] = null; + return product; + } else { + product = inventoryStacks[i].splitStack(j); + if (inventoryStacks[i].stackSize == 0) + inventoryStacks[i] = null; + + return product; + } + } + + @Override + public void markDirty() { + if (!Proxies.common.isSimulating(player.worldObj)) + return; + trySeasoning(); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventoryStacks[i] = itemstack; + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventoryStacks[i]; + } + + @Override + public int getSizeInventory() { + return inventoryStacks.length; + } + + @Override + public String getInventoryName() { + return "Infuser"; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + if (inventoryStacks[slot] == null) + return null; + ItemStack toReturn = inventoryStacks[slot]; + inventoryStacks[slot] = null; + return toReturn; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return true; + } + } + + public ItemInfuser() { + super(); + setMaxStackSize(1); + setCreativeTab(CreativeTabForestry.tabForestry); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) + entityplayer.openGui(ForestryAPI.instance, GuiId.InfuserGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + + return itemstack; + } + + public static void initialize() { + BeverageManager.ingredientManager.addIngredient(ForestryItem.pollen.getItemStack(1, 0), "Strong Curative"); + BeverageManager.ingredientManager.addIngredient(ForestryItem.pollen.getItemStack(1, 1), "Weak Curative"); + BeverageManager.infuserManager.addMixture(1, ForestryItem.pollen.getItemStack(1, 0), BeverageEffect.strongAntidote); + BeverageManager.infuserManager.addMixture(1, ForestryItem.pollen.getItemStack(1, 1), BeverageEffect.weakAntidote); + } +} diff --git a/forestry_common/food/forestry/plugins/PluginFood.java b/forestry_common/food/forestry/plugins/PluginFood.java new file mode 100755 index 000000000..21ba551b1 --- /dev/null +++ b/forestry_common/food/forestry/plugins/PluginFood.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.core.PluginInfo; +import forestry.api.food.BeverageManager; +import forestry.api.food.IBeverageEffect; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.items.ItemForestryFood; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.food.BeverageEffect; +import forestry.food.GuiHandlerFood; +import forestry.food.items.ItemAmbrosia; +import forestry.food.items.ItemBeverage; +import forestry.food.items.ItemBeverage.BeverageInfo; +import forestry.food.items.ItemInfuser; + +@PluginInfo(pluginID = "Food", name = "Food", author = "SirSengir", url = Defaults.URL, description = "Adds food.") +public class PluginFood extends NativePlugin { + + @Override + public boolean isAvailable() { + return !Config.disableFood; + } + + @Override + public void preInit() { + super.preInit(); + + // Init seasoner + BeverageManager.infuserManager = new ItemInfuser.MixtureManager(); + BeverageManager.ingredientManager = new ItemInfuser.IngredientManager(); + } + + @Override + public void postInit() { + super.postInit(); + + ItemInfuser.initialize(); + } + + @Override + protected void registerItems() { + // / FOOD ITEMS + ForestryItem.honeyedSlice.registerItem(new ItemForestryFood(8, 0.6f), "honeyedSlice"); + ForestryItem.beverage.registerItem(new ItemBeverage( + new BeverageInfo("meadShort", "glass", 0xec9a19, 0xffffff, 1, 0.2f, true), + new BeverageInfo("meadCurative", "glass", 0xc5feff, 0xffffff, 1, 0.2f, true)), + "shortMead"); + ForestryItem.ambrosia.registerItem(new ItemAmbrosia().setIsDrink(), "ambrosia"); + ForestryItem.honeyPot.registerItem(new ItemForestryFood(2, 0.2f).setIsDrink(), "honeyPot"); + + // / SEASONER + ForestryItem.infuser.registerItem(new ItemInfuser(), "infuser"); + + // Mead + ItemStack meadBottle = ForestryItem.beverage.getItemStack(); + ((ItemBeverage) ForestryItem.beverage.item()).beverages[0].saveEffects(meadBottle, new IBeverageEffect[] { BeverageEffect.weakAlcoholic }); + + LiquidHelper.getOrCreateLiquid(Defaults.LIQUID_MEAD); + LiquidHelper.injectLiquidContainer(Defaults.LIQUID_MEAD, Defaults.BUCKET_VOLUME, meadBottle, new ItemStack(Items.glass_bottle)); + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerRecipes() { + // INFUSER + Proxies.common.addRecipe(ForestryItem.infuser.getItemStack(), + "X", "#", "X", + '#', Items.iron_ingot, + 'X', "ingotBronze"); + } + + @Override + protected void registerCrates() { + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerFood(); + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/ButterflySpawner.java b/forestry_common/lepidopterology/forestry/lepidopterology/ButterflySpawner.java new file mode 100755 index 000000000..148157231 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/ButterflySpawner.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology; + +import net.minecraft.world.World; + +import forestry.api.arboriculture.ILeafTickHandler; +import forestry.api.arboriculture.ITree; +import forestry.api.lepidopterology.IButterfly; +import forestry.core.proxy.Proxies; +import forestry.lepidopterology.entities.EntityButterfly; +import forestry.plugins.PluginLepidopterology; + +public class ButterflySpawner implements ILeafTickHandler { + + @Override + public boolean onRandomLeafTick(ITree tree, World world, int biomeId, int x, int y, int z, boolean isDestroyed) { + + if(world.rand.nextFloat() >= tree.getGenome().getSappiness() * tree.getGenome().getYield()) + return false; + + IButterfly spawn = PluginLepidopterology.butterflyInterface.getIndividualTemplates().get(world.rand.nextInt(PluginLepidopterology.butterflyInterface.getIndividualTemplates().size())); + if(world.rand.nextFloat() >= spawn.getGenome().getPrimary().getRarity() * 0.5f) + return false; + + if(world.countEntities(EntityButterfly.class) > PluginLepidopterology.spawnConstraint) + return false; + + if(!spawn.canSpawn(world, x, y, z)) + return false; + + if(world.isAirBlock(x - 1, y, z)) { + attemptButterflySpawn(world, spawn, x - 1, y, z); + } else if(world.isAirBlock(x + 1, y, z)) { + attemptButterflySpawn(world, spawn, x + 1, y, z); + } else if(world.isAirBlock(x, y, z - 1)) { + attemptButterflySpawn(world, spawn, x, y, z - 1); + } else if(world.isAirBlock(x, y, z + 1)) { + attemptButterflySpawn(world, spawn, x, y, z + 1); + } + + return false; + } + + private void attemptButterflySpawn(World world, IButterfly butterfly, double x, double y, double z) { + if(PluginLepidopterology.butterflyInterface.spawnButterflyInWorld(world, butterfly.copy(), x, y + 0.1f, z) != null) + Proxies.log.finest("Spawned a butterfly '%s' at %s/%s/%s.", butterfly.getDisplayName(), x, y, z); + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/GuiHandlerLepidopterology.java b/forestry_common/lepidopterology/forestry/lepidopterology/GuiHandlerLepidopterology.java new file mode 100755 index 000000000..64c5475f7 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/GuiHandlerLepidopterology.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; +import forestry.lepidopterology.genetics.ButterflyHelper; +import forestry.lepidopterology.gui.ContainerFlutterlyzer; +import forestry.lepidopterology.gui.GuiFlutterlyzer; +import forestry.lepidopterology.items.ItemFlutterlyzer.FlutterlyzerInventory; + +public class GuiHandlerLepidopterology extends GuiHandlerBase { + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + int guiData = decodeGuiData(id); + + if (cleanId >= GuiId.values().length) + return null; + + switch (GuiId.values()[cleanId]) { + case FlutterlyzerGUI: + ItemStack equipped = getEquippedItem(player); + if (equipped == null) + return null; + + return new ContainerFlutterlyzer(player.inventory, new FlutterlyzerInventory(player, equipped)); + + case LepidopteristChestGUI: + return getNaturalistChestContainer(ButterflyHelper.UID, player, world, x, y, z, guiData); + + default: + return null; + + } + } + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + int guiData = decodeGuiData(id); + + if (cleanId >= GuiId.values().length) + return null; + + switch (GuiId.values()[cleanId]) { + case FlutterlyzerGUI: + ItemStack equipped = getEquippedItem(player); + if (equipped == null) + return null; + + return new GuiFlutterlyzer(player, new FlutterlyzerInventory(player, equipped)); + + case LepidopteristChestGUI: + return getNaturalistChestGui(ButterflyHelper.UID, player, world, x, y, z, guiData); + + default: + return null; + + } + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/MatingRecipe.java b/forestry_common/lepidopterology/forestry/lepidopterology/MatingRecipe.java new file mode 100755 index 000000000..7db9e1848 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/MatingRecipe.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.world.World; + +import forestry.api.lepidopterology.EnumFlutterType; +import forestry.api.lepidopterology.IButterfly; +import forestry.plugins.PluginLepidopterology; + +public class MatingRecipe implements IRecipe { + + ItemStack unknown; + ItemStack cached; + + public MatingRecipe() { + unknown = PluginLepidopterology.butterflyInterface.getMemberStack(PluginLepidopterology.butterflyInterface.getIndividualTemplates().get(0), EnumFlutterType.BUTTERFLY.ordinal()); + } + + @Override + public boolean matches(InventoryCrafting crafting, World world) { + + boolean mated = true; + int butterflies = 0; + int sera = 0; + + for(int i = 0; i < crafting.getSizeInventory(); i++) { + if(PluginLepidopterology.butterflyInterface.isMember(crafting.getStackInSlot(i), EnumFlutterType.BUTTERFLY.ordinal())) { + butterflies++; + mated = PluginLepidopterology.butterflyInterface.isMated(crafting.getStackInSlot(i)); + cached = crafting.getStackInSlot(i); + } else if(PluginLepidopterology.butterflyInterface.isMember(crafting.getStackInSlot(i), EnumFlutterType.SERUM.ordinal())) + sera++; + } + + return !mated && butterflies == 1 && sera == 1; + } + + @Override + public ItemStack getRecipeOutput() { + if(cached != null) + return cached; + else + return unknown; + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting crafting) { + IButterfly butterfly = null; + IButterfly serum = null; + for(int i = 0; i < crafting.getSizeInventory(); i++) { + if(PluginLepidopterology.butterflyInterface.isMember(crafting.getStackInSlot(i), EnumFlutterType.BUTTERFLY.ordinal())) { + butterfly = PluginLepidopterology.butterflyInterface.getMember(crafting.getStackInSlot(i)); + } else if(PluginLepidopterology.butterflyInterface.isMember(crafting.getStackInSlot(i), EnumFlutterType.SERUM.ordinal())) + serum = PluginLepidopterology.butterflyInterface.getMember(crafting.getStackInSlot(i)); + } + + IButterfly mated = butterfly.copy(); + mated.mate(serum); + return PluginLepidopterology.butterflyInterface.getMemberStack(mated, EnumFlutterType.BUTTERFLY.ordinal()); + } + + @Override + public int getRecipeSize() { + return 2; + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyBase.java b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyBase.java new file mode 100755 index 000000000..c0c805b34 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyBase.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.entities; + +import net.minecraft.entity.ai.EntityAIBase; +import net.minecraft.entity.ai.RandomPositionGenerator; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.Vec3; + +public abstract class AIButterflyBase extends EntityAIBase { + + protected EntityButterfly entity; + + public AIButterflyBase(EntityButterfly entity) { + this.entity = entity; + } + + protected ChunkCoordinates getRandomDestination() { + if(entity.isInWater()) + return getRandomDestinationUpwards(); + + Vec3 randomTarget = RandomPositionGenerator.findRandomTargetBlockAwayFrom(entity, 16, 7, + entity.worldObj.getWorldVec3Pool().getVecFromPool(entity.posX, entity.posY, entity.posZ)); + + if (randomTarget == null) + return null; + + ChunkCoordinates dest = new ChunkCoordinates((int)randomTarget.xCoord, (int)randomTarget.yCoord, (int)randomTarget.zCoord); + if(validateDestination(dest)) + return dest; + else + return null; + } + + protected ChunkCoordinates getRandomDestinationUpwards() { + ChunkCoordinates dest = new ChunkCoordinates((int)entity.posX, (int)entity.posY + entity.worldObj.rand.nextInt(10) + 2, (int)entity.posZ); + if(validateDestination(dest)) + return dest; + else + return null; + } + + protected boolean validateDestination(ChunkCoordinates dest) { + if(!entity.worldObj.isAirBlock(dest.posX, dest.posY, dest.posZ) || dest.posY < 1) + return false; + if(!entity.getButterfly().isAcceptedEnvironment(entity.worldObj, dest.posX, dest.posY, dest.posZ)) + return false; + + return true; + } + + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyFlee.java b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyFlee.java new file mode 100755 index 000000000..8e271537a --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyFlee.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.entities; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ChunkCoordinates; + +import forestry.lepidopterology.entities.EntityButterfly.EnumButterflyState; + + +public class AIButterflyFlee extends AIButterflyBase { + + private EntityPlayer player; + private ChunkCoordinates flightTarget; + + public AIButterflyFlee(EntityButterfly entity) { + super(entity); + setMutexBits(3); + } + + @Override + public boolean shouldExecute() { + + player = entity.worldObj.getClosestPlayerToEntity(entity, entity.getButterfly().getGenome().getPrimary().getFlightDistance()); + + if (player == null || player.isSneaking()) + return false; + + if (!entity.getEntitySenses().canSee(player)) + return false; + + flightTarget = getRandomDestination(); + if(flightTarget == null) + return false; + + if (player.getDistanceSq(flightTarget.posX, flightTarget.posY, flightTarget.posZ) < player.getDistanceSqToEntity(entity)) + return false; + + entity.setDestination(flightTarget); + entity.setState(EnumButterflyState.FLYING); + return true; + } + + @Override + public boolean continueExecuting() { + if(entity.getState() != EnumButterflyState.FLYING) + return false; + if(flightTarget == null) + return false; + // Abort if the flight target changed on us. + if(entity.getDestination() == null || !entity.getDestination().equals(flightTarget)) + return false; + + // Continue if we have not yet reached the destination. + if(entity.getDestination().getDistanceSquared((int)entity.posX, (int)entity.posY, (int)entity.posZ) > 2.0f) + return true; + + entity.setDestination(null); + return false; + } + + @Override + public void startExecuting() { + } + + @Override + public void resetTask() { + flightTarget = null; + } + + @Override + public void updateTask() { + // Reset destination if we did collide. + if(entity.isInWater()) { + flightTarget = getRandomDestinationUpwards(); + entity.setDestination(flightTarget); + } if(entity.isCollided || entity.worldObj.rand.nextInt(300) == 0) { + flightTarget = getRandomDestination(); + entity.setDestination(flightTarget); + } + + entity.changeExhaustion(1); + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyInteract.java b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyInteract.java new file mode 100755 index 000000000..8851dd0e1 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyInteract.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.entities; + +import java.util.Map; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; + +import forestry.api.arboriculture.ITreeRoot; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IPollinatable; +import forestry.api.lepidopterology.IButterflyNursery; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; +import forestry.core.utils.Utils; +import forestry.lepidopterology.entities.EntityButterfly.EnumButterflyState; + +public class AIButterflyInteract extends AIButterflyBase { + + private ChunkCoordinates rest; + + private boolean canLayEgg = false; + private boolean canPollinate = false; + + private boolean hasLayedEgg = false; + private boolean hasPollinated = false; + + public AIButterflyInteract(EntityButterfly entity) { + super(entity); + setMutexBits(3); + } + + @Override + public boolean shouldExecute() { + if(entity.getState() != EnumButterflyState.RESTING) + return false; + + rest = new ChunkCoordinates((int)entity.posX, ((int)Math.floor(entity.posY)) - 1, (int)entity.posZ); + if(entity.worldObj.isAirBlock(rest.posX, rest.posY, rest.posZ)) + return false; + + canLayEgg = canLayEgg(); + canPollinate = canPollinate(); + + return canLayEgg || canPollinate; + } + + private boolean canLayEgg() { + if(entity.cooldownEgg > 0) + return false; + + if(entity.getButterfly().getMate() == null) + return false; + + TileEntity tile = entity.worldObj.getTileEntity(rest.posX, rest.posY, rest.posZ); + IButterflyNursery nursery = null; + + if(tile instanceof IButterflyNursery) + nursery = (IButterflyNursery)tile; + else { + for (Map.Entry entry : AlleleManager.ersatzSpecimen.entrySet()) { + + if (!StackUtils.equals(entity.worldObj.getBlock(rest.posX, rest.posY, rest.posZ), entry.getKey())) + continue; + + int meta = entity.worldObj.getBlockMetadata(rest.posX, rest.posY, rest.posZ); + if (StackUtils.equals(Blocks.leaves, entry.getKey())) + meta = meta & 3; + if (entry.getKey().getItemDamage() != meta) + continue; + + // We matched, replace the leaf block with ours and set the ersatz genome + ((ITreeRoot)AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees")).setLeaves(entity.worldObj, entry.getValue(), "", rest.posX, rest.posY, rest.posZ); + // Now let's pollinate + nursery = (IButterflyNursery)entity.worldObj.getTileEntity(rest.posX, rest.posY, rest.posZ); + } + } + if(nursery == null) + return false; + + return nursery.canNurse(entity.getButterfly()); + } + + private boolean canPollinate() { + if(entity.cooldownPollination > 0) + return false; + + IPollinatable pollinatable = Utils.getOrCreatePollinatable("", entity.worldObj, rest.posX, rest.posY, rest.posZ); + if(pollinatable == null) + return false; + + if(!entity.getButterfly().getGenome().getFlowerProvider().isAcceptedPollinatable(entity.worldObj, pollinatable)) + return false; + + if(entity.getPollen() != null && !pollinatable.canMateWith(entity.getPollen())) + return false; + + return true; + } + + @Override + public boolean continueExecuting() { + return (canLayEgg && !hasLayedEgg) || (canPollinate && !hasPollinated); + } + + @Override + public void startExecuting() { + } + + @Override + public void resetTask() { + hasLayedEgg = false; + hasPollinated = false; + + canLayEgg = false; + canPollinate = false; + + rest = null; + } + + @Override + public void updateTask() { + if(canLayEgg && !hasLayedEgg) { + IButterflyNursery tile = (IButterflyNursery)entity.worldObj.getTileEntity(rest.posX, rest.posY, rest.posZ); + if(tile.canNurse(entity.getButterfly())) { + tile.setCaterpillar(entity.getButterfly().spawnCaterpillar(tile)); + Proxies.log.finest("A butterfly '%s' laid an egg at %s/%s/%s.", entity.getButterfly().getIdent(), rest.posX, rest.posY, rest.posZ); + if(entity.getRNG().nextFloat() < 1.0f / entity.getButterfly().getGenome().getFertility()) + entity.setHealth(0); + } + hasLayedEgg = true; + entity.cooldownEgg = EntityButterfly.COOLDOWNS; + } + + if(canPollinate && !hasPollinated) { + IPollinatable pollinatable = (IPollinatable)entity.worldObj.getTileEntity(rest.posX, rest.posY, rest.posZ); + if(entity.getPollen() == null) { + entity.setPollen(pollinatable.getPollen()); + //Proxies.log.finest("A butterfly '%s' grabbed a pollen '%s' at %s/%s/%s.", entity.getButterfly().getIdent(), entity.getPollen().getIdent(), rest.posX, rest.posY, rest.posZ); + } else if(pollinatable.canMateWith(entity.getPollen())) { + pollinatable.mateWith(entity.getPollen()); + //Proxies.log.finest("A butterfly '%s' unloaded pollen '%s' at %s/%s/%s.", entity.getButterfly().getIdent(), entity.getPollen().getIdent(), rest.posX, rest.posY, rest.posZ); + entity.setPollen(null); + } + hasPollinated = true; + entity.cooldownPollination = EntityButterfly.COOLDOWNS; + } + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyRest.java b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyRest.java new file mode 100755 index 000000000..fcbd30a98 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyRest.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.entities; + +import net.minecraft.util.ChunkCoordinates; + +import forestry.core.utils.Utils; +import forestry.lepidopterology.entities.EntityButterfly.EnumButterflyState; + +public class AIButterflyRest extends AIButterflyBase { + + public AIButterflyRest(EntityButterfly entity) { + super(entity); + setMutexBits(3); + } + + @Override + public boolean shouldExecute() { + + if(entity.getExhaustion() < EntityButterfly.EXHAUSTION_REST + && entity.canFly()) + return false; + + if(!entity.worldObj.isAirBlock((int)entity.posX, ((int)Math.floor(entity.posY)), (int)entity.posZ)) + return false; + + ChunkCoordinates rest = new ChunkCoordinates((int)entity.posX, ((int)Math.floor(entity.posY)) - 1, (int)entity.posZ); + if(entity.worldObj.isAirBlock(rest.posX, rest.posY, rest.posZ)) + return false; + if(Utils.isLiquidBlock(entity.worldObj, rest.posX, rest.posY, rest.posZ)) + return false; + if(!entity.getButterfly().isAcceptedEnvironment(entity.worldObj, rest.posX, rest.posY, rest.posZ)) + return false; + + entity.setDestination(null); + entity.setState(EnumButterflyState.RESTING); + return true; + } + + @Override + public boolean continueExecuting() { + if(entity.getExhaustion() <= 0 && entity.canFly()) + return false; + if(entity.isInWater()) + return false; + + return true; + } + + @Override + public void startExecuting() { + } + + @Override + public void resetTask() { + } + + @Override + public void updateTask() { + entity.changeExhaustion(-1); + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyWander.java b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyWander.java new file mode 100755 index 000000000..4a97cfae4 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/entities/AIButterflyWander.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.entities; + +import net.minecraft.util.ChunkCoordinates; + +import forestry.lepidopterology.entities.EntityButterfly.EnumButterflyState; + +public class AIButterflyWander extends AIButterflyBase { + + private ChunkCoordinates flightTarget; + + public AIButterflyWander(EntityButterfly entity) { + super(entity); + setMutexBits(1); + } + + @Override + public boolean shouldExecute() { + + if(entity.getDestination() != null) + return false; + + flightTarget = getRandomDestination(); + if(flightTarget == null) { + if(entity.getState().doesMovement) + entity.setState(EnumButterflyState.HOVER); + return false; + } + + entity.setDestination(flightTarget); + entity.setState(EnumButterflyState.FLYING); + return true; + } + + @Override + public boolean continueExecuting() { + if(entity.getState() != EnumButterflyState.FLYING) + return false; + if(flightTarget == null) + return false; + // Abort if the flight target changed on us. + if(entity.getDestination() == null || !entity.getDestination().equals(flightTarget)) + return false; + + // Continue if we have not yet reached the destination. + if(entity.getDestination().getDistanceSquared((int)entity.posX, (int)entity.posY, (int)entity.posZ) > 2.0f) + return true; + + entity.setDestination(null); + return false; + } + + @Override + public void startExecuting() { + } + + @Override + public void resetTask() { + flightTarget = null; + } + + @Override + public void updateTask() { + // Reset destination if we did collide. + if(entity.isInWater()) { + flightTarget = getRandomDestinationUpwards(); + entity.setDestination(flightTarget); + } if(entity.isCollided || entity.worldObj.rand.nextInt(300) == 0) { + flightTarget = getRandomDestination(); + entity.setDestination(flightTarget); + } + + entity.changeExhaustion(1); + + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/entities/EntityButterfly.java b/forestry_common/lepidopterology/forestry/lepidopterology/entities/EntityButterfly.java new file mode 100755 index 000000000..7f99f2b47 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/entities/EntityButterfly.java @@ -0,0 +1,397 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.entities; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.DamageSource; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.core.IToolScoop; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IIndividual; +import forestry.api.lepidopterology.EnumFlutterType; +import forestry.api.lepidopterology.IAlleleButterflySpecies; +import forestry.api.lepidopterology.IButterfly; +import forestry.api.lepidopterology.IEntityButterfly; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StackUtils; +import forestry.lepidopterology.genetics.Butterfly; +import forestry.lepidopterology.render.ButterflyItemRenderer; +import forestry.plugins.PluginLepidopterology; + +public class EntityButterfly extends EntityCreature implements IEntityButterfly { + + public enum EnumButterflyState { + FLYING(true), GLIDING(true), RESTING(false), HOVER(false); + + public static final EnumButterflyState[] VALUES = values(); + + public final boolean doesMovement; + + private EnumButterflyState(boolean doesMovement) { + this.doesMovement = doesMovement; + } + + public float getWingFlap(EntityButterfly entity, float partialTicktime) { + if(this == RESTING || this == HOVER) { + long systemTime = System.currentTimeMillis(); + long flapping = systemTime + entity.contained.getIdent().hashCode(); + float flap = (float) (flapping % 1000) / 1000; // 0 to 1 + + return ButterflyItemRenderer.getIrregularWingYaw(flapping, flap); + } else + return entity.ticksExisted + partialTicktime; + } + } + + /* CONSTANTS */ + public static final int COOLDOWNS = 1000; + + private static final int DATAWATCHER_ID_SPECIES = 16; + private static final int DATAWATCHER_ID_SCALE = 17; + private static final int DATAWATCHER_ID_STATE = 18; + + //private static final String DEFAULT_TEXTURE = Defaults.TEXTURE_PATH_ENTITIES + "/butterflies/mothBrimstone.png"; + public static final float DEFAULT_BUTTERFLY_SCALE = 0.75f; + private static final EnumButterflyState DEFAULT_STATE = EnumButterflyState.FLYING; + + public static final int EXHAUSTION_REST = 1000; + public static final int EXHAUSTION_CONSUMPTION = 100 * EXHAUSTION_REST; + + private ChunkCoordinates flightTarget; + private int exhaustion; + + private IAlleleButterflySpecies species; + private IButterfly contained; + + private IIndividual pollen; + + private EnumButterflyState state = DEFAULT_STATE; + private float scale = DEFAULT_BUTTERFLY_SCALE; + private String mothTexture; + + private long lastUpdate; + + public int cooldownPollination = 0; + public int cooldownEgg = 0; + + /* CONSTRUCTOR */ + public EntityButterfly(World world) { + super(world); + setDefaults(PluginLepidopterology.butterflyInterface.templateAsIndividual(PluginLepidopterology.butterflyInterface.getRandomTemplate(rand))); + } + + public EntityButterfly(World world, IButterfly butterfly) { + super(world); + setDefaults(butterfly); + } + + private void setDefaults(IButterfly butterfly) { + contained = butterfly; + tasks.addTask(10, new AIButterflyWander(this)); + tasks.addTask(9, new AIButterflyRest(this)); + tasks.addTask(8, new AIButterflyInteract(this)); + tasks.addTask(8, new AIButterflyFlee(this)); + } + + @Override + public EntityCreature getEntity() { + return this; + } + + /* SAVING & LOADING */ + @Override + public void writeEntityToNBT(NBTTagCompound nbttagcompound) { + super.writeEntityToNBT(nbttagcompound); + + NBTTagCompound bio = new NBTTagCompound(); + contained.writeToNBT(bio); + nbttagcompound.setTag("BTFLY", bio); + + if(pollen != null) { + NBTTagCompound pln = new NBTTagCompound(); + pollen.writeToNBT(pln); + nbttagcompound.setTag("PLN", pln); + } + + nbttagcompound.setByte("STATE", (byte)state.ordinal()); + nbttagcompound.setInteger("EXH", exhaustion); + } + + @Override + public void readEntityFromNBT(NBTTagCompound nbttagcompound) { + super.readEntityFromNBT(nbttagcompound); + + if(nbttagcompound.hasKey("BTFLY")) { + contained = new Butterfly((NBTTagCompound)nbttagcompound.getTag("BTFLY")); + } + setIndividual(contained); + + if(nbttagcompound.hasKey("PLN")) { + pollen = AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees").getMember((NBTTagCompound)nbttagcompound.getTag("PLN")); + } + + state = EnumButterflyState.VALUES[nbttagcompound.getByte("STATE")]; + exhaustion = nbttagcompound.getInteger("EXH"); + } + + public float getWingFlap(float partialTicktime) { + return state.getWingFlap(this, partialTicktime); + } + + public float getScale() { + return scale; + } + + // Client side helper to set size for rendering if necessary. + public void setScale(float size) { + scale = size; + } + + public float getSpeed() { + return contained.getGenome().getSpeed(); + } + + /* DESTINATION */ + public ChunkCoordinates getDestination() { + return flightTarget; + } + + public void setDestination(ChunkCoordinates destination) { + flightTarget = destination; + } + + /* POLLEN */ + @Override + public IIndividual getPollen() { + return pollen; + } + + @Override + public void setPollen(IIndividual pollen) { + this.pollen = pollen; + } + + /* STATE - Used for rendering */ + public EnumButterflyState getState() { + return state; + } + + public void setState(EnumButterflyState state) { + if(state != this.state) { + this.state = state; + dataWatcher.updateObject(DATAWATCHER_ID_STATE, (byte)state.ordinal()); + } + } + + public boolean isRenderable() { + return species != null; + } + + /* EXHAUSTION */ + @Override + public void changeExhaustion(int change) { + exhaustion = exhaustion + change > 0 ? exhaustion + change : 0; + } + + @Override + public int getExhaustion() { + return exhaustion; + } + + /* FLYING ABILITY */ + public boolean canFly() { + return contained.canTakeFlight(worldObj, posX, posY, posZ); + } + + /* SETTING GENETIC INDIVIDUAL */ + private void resetAppearance() { + mothTexture = species.getEntityTexture(); + setSize(getScale(), 0.2f); + } + + public EntityButterfly setIndividual(IButterfly butterfly) { + if(butterfly != null) + contained = butterfly; + else + contained = PluginLepidopterology.butterflyInterface.templateAsIndividual(PluginLepidopterology.butterflyInterface.getDefaultTemplate()); + + isImmuneToFire = contained.getGenome().getFireResist(); + setSpecies(contained.getGenome().getPrimary()); + dataWatcher.updateObject(DATAWATCHER_ID_SPECIES, species.getUID()); + dataWatcher.updateObject(DATAWATCHER_ID_SCALE, (int)(contained.getSize() * 100)); + return this; + } + + @Override + public IButterfly getButterfly() { + return contained; + } + + public EntityButterfly setSpecies(IAlleleButterflySpecies butterfly) { + species = butterfly; + resetAppearance(); + lastUpdate = worldObj.getTotalWorldTime(); + return this; + } + + @Override + public IEntityLivingData onSpawnWithEgg(IEntityLivingData data) { + if(Proxies.common.isSimulating(worldObj)) + setIndividual(contained); + return data; + } + @Override public boolean getCanSpawnHere() { return true; } + + @Override + protected void entityInit() { + super.entityInit(); + + if(state == null) + state = DEFAULT_STATE; + + dataWatcher.addObject(DATAWATCHER_ID_SPECIES, ""); + dataWatcher.addObject(DATAWATCHER_ID_SCALE, 75); + dataWatcher.addObject(DATAWATCHER_ID_STATE, (byte)state.ordinal()); + } + + @Override + public int getMaxInPortalTime() { + return 1000; + } + + @SideOnly(Side.CLIENT) + private ResourceLocation textureResource; + private long lastTextureUpdate; + @SideOnly(Side.CLIENT) + public ResourceLocation getTexture() { + if(textureResource == null || lastTextureUpdate != lastUpdate) + textureResource = new ResourceLocation(mothTexture); + + return textureResource; + } + + @Override public boolean canBePushed() { return false; } + @Override protected void collideWithEntity(Entity other) {} + @Override protected boolean isAIEnabled() { return true; } + @Override protected boolean canDespawn() { return false; } + + /* INTERACTION */ + @Override + public boolean interact(EntityPlayer player) { + if(isDead) + return false; + if(player.getHeldItem() == null) + return false; + if(!(player.getHeldItem().getItem() instanceof IToolScoop)) + return false; + + if(Proxies.common.isSimulating(worldObj)) { + contained.getGenome().getPrimary().getRoot().getBreedingTracker(worldObj, player.getGameProfile().getId()).registerCatch(contained); + StackUtils.dropItemStackAsEntity(PluginLepidopterology.butterflyInterface.getMemberStack(contained.copy(), EnumFlutterType.BUTTERFLY.ordinal()), worldObj, posX, posY, posZ); + setDead(); + } else + player.swingItem(); + return true; + } + + /* LOOT */ + @Override + protected void dropFewItems(boolean playerKill, int lootLevel) { + for(ItemStack stack : contained.getLootDrop(this, playerKill, lootLevel)) + StackUtils.dropItemStackAsEntity(stack, worldObj, posX, posY, posZ); + + // Drop pollen if any + if(getPollen() != null) { + StackUtils.dropItemStackAsEntity(AlleleManager.alleleRegistry.getSpeciesRoot(getPollen().getClass()).getMemberStack(getPollen(), EnumGermlingType.POLLEN.ordinal()), worldObj, posX, posY, posZ); + } + } + + /* UPDATING */ + @Override + public void onUpdate() { + super.onUpdate(); + + // Update stuff client side + if(!Proxies.common.isSimulating(worldObj)) { + if (species == null || dataWatcher.hasChanges()) { + scale = (float)dataWatcher.getWatchableObjectInt(DATAWATCHER_ID_SCALE) / 100; + String uid = dataWatcher.getWatchableObjectString(DATAWATCHER_ID_SPECIES); + if(species == null || !species.getUID().equals(uid)) { + IAllele allele = AlleleManager.alleleRegistry.getAllele(uid); + if(allele instanceof IAlleleButterflySpecies) { + setSpecies((IAlleleButterflySpecies)allele); + } + } + } + state = EnumButterflyState.VALUES[dataWatcher.getWatchableObjectByte(DATAWATCHER_ID_STATE)]; + } + + motionY *= 0.6000000238418579d; + + // Make sure we die if the butterfly hasn't rested in a long, long time. + if(exhaustion > EXHAUSTION_CONSUMPTION && getRNG().nextInt(20) == 0) + attackEntityFrom(DamageSource.generic, 1); + + // Reduce cooldowns + if(cooldownEgg > 0) cooldownEgg--; + if(cooldownPollination > 0) cooldownPollination--; + } + + @Override + protected void updateAITasks() { + super.updateAITasks(); + + if(state.doesMovement && flightTarget != null) { + double diffX = flightTarget.posX + 0.5d - posX; + double diffY = flightTarget.posY + 0.1d - posY; + double diffZ = flightTarget.posZ + 0.5d - posZ; + + motionX += (Math.signum(diffX) * 0.5d - motionX) * 0.10000000149011612d; + motionY += (Math.signum(diffY) * 0.699999988079071d - motionY) * 0.10000000149011612d; + motionZ += (Math.signum(diffZ) * 0.5d - motionZ) * 0.10000000149011612d; + + //float f = (float)(Math.atan2(motionZ, motionX) * 180.0d / Math.PI) - 90f; + //rotationYaw += MathHelper.wrapAngleTo180_float(f - rotationYaw); + float horizontal = (float)((Math.atan2(motionZ, motionX) * 180d) / Math.PI) - 90f; + rotationYaw += MathHelper.wrapAngleTo180_float(horizontal - rotationYaw); + + setMoveForward(contained.getGenome().getSpeed()); + } + + } + + @Override protected boolean canTriggerWalking() { return false; } + @Override protected void fall(float par1) {} + @Override protected void updateFallState(double par1, boolean par3) {} + @Override public boolean doesEntityNotTriggerPressurePlate() { return true; } + + @Override + public float getSwingProgress(float partialTicktime) { + float flap = swingProgress - prevSwingProgress; + if (flap < 0.0F) + ++flap; + + return prevSwingProgress + flap * partialTicktime; + + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/gadgets/TileLepidopteristChest.java b/forestry_common/lepidopterology/forestry/lepidopterology/gadgets/TileLepidopteristChest.java new file mode 100755 index 000000000..227cce120 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/gadgets/TileLepidopteristChest.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.gadgets; + +import forestry.api.genetics.AlleleManager; +import forestry.core.gadgets.TileNaturalistChest; +import forestry.core.network.GuiId; + +public class TileLepidopteristChest extends TileNaturalistChest { + + public TileLepidopteristChest() { + super(AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies"), GuiId.LepidopteristChestGUI.ordinal()); + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleButterflySpecies.java b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleButterflySpecies.java new file mode 100755 index 000000000..1a263a734 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleButterflySpecies.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.genetics; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.core.IIconProvider; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IIndividual; +import forestry.api.lepidopterology.EnumFlutterType; +import forestry.api.lepidopterology.IAlleleButterflySpecies; +import forestry.api.lepidopterology.IButterflyRoot; +import forestry.core.config.Defaults; +import forestry.core.genetics.AlleleSpecies; + +public class AlleleButterflySpecies extends AlleleSpecies implements IAlleleButterflySpecies { + + private final IButterflyRoot root; + + private final String texture; + private final int serumColour; + private float rarity = 0.1f; + private float flightDistance = 5.0f; + private boolean isActualNocturnal = false; + + private final EnumSet spawnBiomes = EnumSet.noneOf(BiomeDictionary.Type.class); + + private final Map butterflyLoot = new HashMap(); + private final Map caterpillarLoot = new HashMap(); + + public AlleleButterflySpecies(String uid, boolean isDominant, String name, IClassification branch, String binomial, int serumColour) { + super(uid, isDominant, name, branch, binomial); + this.root = (IButterflyRoot)AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies"); + this.serumColour = serumColour; + texture = "forestry:" + Defaults.TEXTURE_PATH_ENTITIES + "/butterflies/" + uid + ".png"; + } + + @Override + public IButterflyRoot getRoot() { + return root; + } + + public AlleleButterflySpecies setRarity(float rarity) { + this.rarity = rarity; + return this; + } + + public AlleleButterflySpecies setFlightDistance(float flightDistance) { + this.flightDistance = flightDistance; + return this; + } + + public AlleleButterflySpecies setNocturnal(boolean isActualNocturnal) { + this.isActualNocturnal = isActualNocturnal; + return this; + } + + public AlleleButterflySpecies addSpawnBiomes(EnumSet biomeTags) { + spawnBiomes.addAll(biomeTags); + return this; + } + + public AlleleButterflySpecies addSpawnBiome(BiomeDictionary.Type biomeTag) { + spawnBiomes.add(biomeTag); + return this; + } + + @Override + @SideOnly(Side.CLIENT) + public IIconProvider getIconProvider() { + return null; + } + + @Override + public String getEntityTexture() { + return texture; + } + + @Override + public EnumSet getSpawnBiomes() { + return spawnBiomes; + } + + @Override + public boolean strictSpawnMatch() { + return false; + } + + /* RESEARCH */ + @Override + public int getComplexity() { + return (int)((1.35f/rarity)*1.5); + } + + @Override + public float getResearchSuitability(ItemStack itemstack) { + if(itemstack == null) + return 0f; + + if(itemstack.getItem() == Items.glass_bottle) + return 0.9f; + + for(ItemStack stack : butterflyLoot.keySet()) + if(stack.isItemEqual(itemstack)) + return 1.0f; + for(ItemStack stack : caterpillarLoot.keySet()) + if(stack.isItemEqual(itemstack)) + return 1.0f; + + return super.getResearchSuitability(itemstack); + } + + @Override + public ItemStack[] getResearchBounty(World world, String researcher, IIndividual individual, int bountyLevel) { + return new ItemStack[] { getRoot().getMemberStack(individual.copy(), EnumFlutterType.SERUM.ordinal()) }; + } + + /* OTHER */ + @Override + public boolean isSecret() { + return rarity < 0.8f; + } + + @Override + public float getRarity() { + return rarity; + } + + @Override + public float getFlightDistance() { + return flightDistance; + } + + @Override + public boolean isNocturnal() { + return isActualNocturnal; + } + + @Override + public Map getButterflyLoot() { + return butterflyLoot; + } + + @Override + public Map getCaterpillarLoot() { + return caterpillarLoot; + } + + @Override + public int getIconColour(int renderPass) { + if(renderPass > 0) + return 0xffffff; + return serumColour; + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleEffectNone.java b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleEffectNone.java new file mode 100755 index 000000000..731d6231c --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/AlleleEffectNone.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.genetics; + +import forestry.api.genetics.IEffectData; +import forestry.api.lepidopterology.IAlleleButterflyEffect; +import forestry.api.lepidopterology.IEntityButterfly; +import forestry.core.genetics.Allele; + +public class AlleleEffectNone extends Allele implements IAlleleButterflyEffect { + + public AlleleEffectNone(String uid, boolean isDominant) { + super(uid, isDominant, false); + } + + @Override + public boolean isCombinable() { + return true; + } + + @Override + public IEffectData validateStorage(IEffectData storedData) { + return null; + } + + @Override + public String getName() { + return "None"; + } + + @Override + public IEffectData doEffect(IEntityButterfly butterfly, IEffectData storedData) { + return storedData; + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/genetics/Butterfly.java b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/Butterfly.java new file mode 100755 index 000000000..0d9ba7cf5 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/Butterfly.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.genetics; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import net.minecraft.entity.EntityCreature; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IGenome; +import forestry.api.genetics.IIndividual; +import forestry.api.lepidopterology.EnumButterflyChromosome; +import forestry.api.lepidopterology.IAlleleButterflySpecies; +import forestry.api.lepidopterology.IButterfly; +import forestry.api.lepidopterology.IButterflyGenome; +import forestry.api.lepidopterology.IButterflyMutation; +import forestry.api.lepidopterology.IButterflyNursery; +import forestry.api.lepidopterology.IEntityButterfly; +import forestry.core.genetics.Chromosome; +import forestry.core.genetics.ClimateHelper; +import forestry.core.genetics.GenericRatings; +import forestry.core.genetics.IndividualLiving; +import forestry.core.utils.StackUtils; +import forestry.core.utils.StringUtil; +import forestry.core.utils.Utils; +import forestry.plugins.PluginLepidopterology; + +public class Butterfly extends IndividualLiving implements IButterfly { + + public IButterflyGenome genome; + public IButterflyGenome mate; + + /* CONSTRUCTOR */ + public Butterfly(NBTTagCompound nbttagcompound) { + readFromNBT(nbttagcompound); + } + + public Butterfly(IButterflyGenome genome) { + this(genome, true, 0); + } + + public Butterfly(IButterflyGenome genome, boolean isNatural, int generation) { + super(genome.getLifespan(), isNatural, generation); + this.genome = genome; + } + + @Override + public void addTooltip(List list) { + IAlleleButterflySpecies primary = genome.getPrimary(); + IAlleleButterflySpecies secondary = genome.getSecondary(); + if (!isPureBred(EnumButterflyChromosome.SPECIES.ordinal())) + list.add("\u00A79" + StringUtil.localize("gui.hybrid") + ":" + primary.getName() + "-" + secondary.getName()); + + if(getMate() != null) + list.add("\u00A7c" + StringUtil.localize("gui.fecundated").toUpperCase(Locale.ENGLISH)); + list.add("\u00A7e" + genome.getActiveAllele(EnumButterflyChromosome.SIZE.ordinal()).getName()); + list.add("\u00A7f" + genome.getActiveAllele(EnumButterflyChromosome.SPEED.ordinal()).getName() + " " + StringUtil.localize("gui.flyer")); + list.add(genome.getActiveAllele(EnumButterflyChromosome.LIFESPAN.ordinal()).getName() + " " + StringUtil.localize("gui.life")); + list.add("\u00A7aT: " + ClimateHelper.toDisplay(genome.getPrimary().getTemperature()) + " / " + + StringUtil.capitalize(genome.getToleranceTemp().name())); + list.add("\u00A7aH: " + ClimateHelper.toDisplay(genome.getPrimary().getHumidity()) + " / " + + StringUtil.capitalize(genome.getToleranceHumid().name())); + list.add("\u00A7c" + GenericRatings.rateActivityTime(genome.getNocturnal(), genome.getPrimary().isNocturnal())); + } + + /* SAVING & LOADING */ + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + if (nbttagcompound == null) { + this.genome = PluginLepidopterology.butterflyInterface.templateAsGenome(PluginLepidopterology.butterflyInterface.getDefaultTemplate()); + return; + } + + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("Genome")) + genome = new ButterflyGenome(nbttagcompound.getCompoundTag("Genome")); + else + genome = PluginLepidopterology.butterflyInterface.templateAsGenome(PluginLepidopterology.butterflyInterface.getDefaultTemplate()); + if (nbttagcompound.hasKey("Mate")) + mate = new ButterflyGenome(nbttagcompound.getCompoundTag("Mate")); + + } + + + @Override + public IButterfly copy() { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + this.writeToNBT(nbttagcompound); + return new Butterfly(nbttagcompound); + } + + @Override + public IButterflyGenome getGenome() { + return genome; + } + + @Override + public IButterflyGenome getMate() { + return mate; + } + + @Override + public boolean canSpawn(World world, double x, double y, double z) { + if(!canFly(world)) + return false; + + BiomeGenBase biome = Utils.getBiomeAt(world, (int)x, (int)z); + if(getGenome().getPrimary().getSpawnBiomes().size() > 0) { + boolean noneMatched = true; + + if(getGenome().getPrimary().strictSpawnMatch()) { + BiomeDictionary.Type[] types = BiomeDictionary.getTypesForBiome(biome); + if(types.length == 1 && getGenome().getPrimary().getSpawnBiomes().contains(types[0])) + noneMatched = false; + } else { + for(BiomeDictionary.Type type : getGenome().getPrimary().getSpawnBiomes()) { + if(BiomeDictionary.isBiomeOfType(biome, type)) { + noneMatched = false; + break; + } + } + } + + if(noneMatched) + return false; + } + + return isAcceptedEnvironment(biome); + } + + @Override + public boolean canTakeFlight(World world, double x, double y, double z) { + if(!canFly(world)) + return false; + return isAcceptedEnvironment(Utils.getBiomeAt(world, (int)x, (int)z)); + } + + private boolean canFly(World world) { + if(world.isRaining() && !getGenome().getTolerantFlyer()) + return false; + if(!isActiveThisTime(world.isDaytime())) + return false; + return true; + } + + @Override + public boolean isAcceptedEnvironment(World world, double x, double y, double z) { + return isAcceptedEnvironment(Utils.getBiomeAt(world, (int)x, (int)z)); + } + + private boolean isAcceptedEnvironment(BiomeGenBase biome) { + return ClimateHelper.isWithinLimits(EnumTemperature.getFromValue(biome.temperature), + EnumHumidity.getFromValue(biome.rainfall), + getGenome().getPrimary().getTemperature(), getGenome().getToleranceTemp(), + getGenome().getPrimary().getHumidity(), getGenome().getToleranceHumid()); + } + + @Override + public IButterfly spawnCaterpillar(IButterflyNursery nursery) { + // We need a mated queen to produce offspring. + if (mate == null) + return null; + + World world = nursery.getWorld(); + + IChromosome[] chromosomes = new IChromosome[genome.getChromosomes().length]; + IChromosome[] parent1 = genome.getChromosomes(); + IChromosome[] parent2 = mate.getChromosomes(); + + // Check for mutation. Replace one of the parents with the mutation + // template if mutation occured. + IChromosome[] mutated1 = mutateSpecies(nursery, genome, mate); + if (mutated1 != null) + parent1 = mutated1; + IChromosome[] mutated2 = mutateSpecies(nursery, mate, genome); + if (mutated2 != null) + parent2 = mutated2; + + for (int i = 0; i < parent1.length; i++) + if (parent1[i] != null && parent2[i] != null) + chromosomes[i] = Chromosome.inheritChromosome(world.rand, parent1[i], parent2[i]); + + return new Butterfly(new ButterflyGenome(chromosomes), true, generation); + } + + private IChromosome[] mutateSpecies(IButterflyNursery nursery, IGenome genomeOne, IGenome genomeTwo) { + + World world = nursery.getWorld(); + + IChromosome[] parent1 = genomeOne.getChromosomes(); + IChromosome[] parent2 = genomeTwo.getChromosomes(); + + IGenome genome0; + IGenome genome1; + IAllele allele0; + IAllele allele1; + + if (world.rand.nextBoolean()) { + allele0 = parent1[EnumButterflyChromosome.SPECIES.ordinal()].getPrimaryAllele(); + allele1 = parent2[EnumButterflyChromosome.SPECIES.ordinal()].getSecondaryAllele(); + + genome0 = genomeOne; + genome1 = genomeTwo; + } else { + allele0 = parent2[EnumButterflyChromosome.SPECIES.ordinal()].getPrimaryAllele(); + allele1 = parent1[EnumButterflyChromosome.SPECIES.ordinal()].getSecondaryAllele(); + + genome0 = genomeTwo; + genome1 = genomeOne; + } + + for (IButterflyMutation mutation : PluginLepidopterology.butterflyInterface.getMutations(true)) { + float chance = 0; + + if ((chance = mutation.getChance(nursery, allele0, allele1, genome0, genome1)) > 0) + if (world.rand.nextFloat()*100 < chance) { + //IApiaristTracker breedingTracker = PluginApiculture.beeInterface.getBreedingTracker(world, housing.getOwnerName()); + //breedingTracker.registerMutation(mutation); + return PluginLepidopterology.butterflyInterface.templateAsChromosomes(mutation.getTemplate()); + } + } + + return null; + } + + private boolean isActiveThisTime(boolean isDayTime) { + if(getGenome().getNocturnal()) + return true; + + return isDayTime ? !getGenome().getPrimary().isNocturnal() : getGenome().getPrimary().isNocturnal(); + } + + @Override + public float getSize() { + return getGenome().getSize(); + } + + @Override + public void mate(IIndividual individual) { + if(!(individual instanceof IButterfly)) + return; + + mate = ((IButterfly)individual).getGenome(); + } + + @Override + public ItemStack[] getLootDrop(IEntityButterfly entity, boolean playerKill, int lootLevel) { + ArrayList drop = new ArrayList(); + + EntityCreature creature = entity.getEntity(); + float metabolism = (float)getGenome().getMetabolism() / 10; + + for (Map.Entry entry : getGenome().getPrimary().getButterflyLoot().entrySet()) + if (creature.worldObj.rand.nextFloat() < entry.getValue() * metabolism) + drop.add(entry.getKey().copy()); + + return drop.toArray(StackUtils.EMPTY_STACK_ARRAY); + } + + @Override + public ItemStack[] getCaterpillarDrop(IButterflyNursery nursery, boolean playerKill, int lootLevel) { + ArrayList drop = new ArrayList(); + float metabolism = (float)getGenome().getMetabolism() / 10; + + for (Map.Entry entry : getGenome().getPrimary().getCaterpillarLoot().entrySet()) + if (nursery.getWorld().rand.nextFloat() < entry.getValue() * metabolism) + drop.add(entry.getKey().copy()); + + return drop.toArray(StackUtils.EMPTY_STACK_ARRAY); + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyGenome.java b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyGenome.java new file mode 100755 index 000000000..847013306 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyGenome.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.genetics; + +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.genetics.EnumTolerance; +import forestry.api.genetics.IAlleleFloat; +import forestry.api.genetics.IAlleleFlowers; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IChromosome; +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.ISpeciesRoot; +import forestry.api.lepidopterology.EnumButterflyChromosome; +import forestry.api.lepidopterology.IAlleleButterflyEffect; +import forestry.api.lepidopterology.IAlleleButterflySpecies; +import forestry.api.lepidopterology.IButterflyGenome; +import forestry.core.genetics.AlleleBoolean; +import forestry.core.genetics.AlleleTolerance; +import forestry.core.genetics.Genome; +import forestry.plugins.PluginLepidopterology; + +public class ButterflyGenome extends Genome implements IButterflyGenome { + + /* CONSTRUCTOR */ + public ButterflyGenome(NBTTagCompound nbttagcompound) { + super(nbttagcompound); + } + + public ButterflyGenome(IChromosome[] chromosomes) { + super(chromosomes); + } + + /* SPECIES */ + @Override + public IAlleleButterflySpecies getPrimary() { + return (IAlleleButterflySpecies) getActiveAllele(EnumButterflyChromosome.SPECIES.ordinal()); + } + + @Override + public IAlleleButterflySpecies getSecondary() { + return (IAlleleButterflySpecies) getInactiveAllele(EnumButterflyChromosome.SPECIES.ordinal()); + } + + @Override + public float getSize() { + return ((IAlleleFloat) getActiveAllele(EnumButterflyChromosome.SIZE.ordinal())).getValue(); + } + + @Override + public int getLifespan() { + return ((IAlleleInteger) getActiveAllele(EnumButterflyChromosome.LIFESPAN.ordinal())).getValue(); + } + + @Override + public float getSpeed() { + return ((IAlleleFloat) getActiveAllele(EnumButterflyChromosome.SPEED.ordinal())).getValue(); + } + + @Override + public int getMetabolism() { + return ((IAlleleInteger) getActiveAllele(EnumButterflyChromosome.METABOLISM.ordinal())).getValue(); + } + + @Override + public int getFertility() { + return ((IAlleleInteger) getActiveAllele(EnumButterflyChromosome.FERTILITY.ordinal())).getValue(); + } + + @Override + public EnumTolerance getToleranceTemp() { + return ((AlleleTolerance) getActiveAllele(EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal())).getValue(); + } + + @Override + public EnumTolerance getToleranceHumid() { + return ((AlleleTolerance) getActiveAllele(EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal())).getValue(); + } + + @Override + public boolean getNocturnal() { + return ((AlleleBoolean) getActiveAllele(EnumButterflyChromosome.NOCTURNAL.ordinal())).getValue(); + } + + @Override + public boolean getTolerantFlyer() { + return ((AlleleBoolean) getActiveAllele(EnumButterflyChromosome.TOLERANT_FLYER.ordinal())).getValue(); + } + + @Override + public boolean getFireResist() { + return ((AlleleBoolean) getActiveAllele(EnumButterflyChromosome.FIRE_RESIST.ordinal())).getValue(); + } + + @Override + public IFlowerProvider getFlowerProvider() { + return ((IAlleleFlowers) getActiveAllele(EnumButterflyChromosome.FLOWER_PROVIDER.ordinal())).getProvider(); + } + + @Override + public IAlleleButterflyEffect getEffect() { + return (IAlleleButterflyEffect) getActiveAllele(EnumButterflyChromosome.EFFECT.ordinal()); + } + + @Override + public ISpeciesRoot getSpeciesRoot() { + return PluginLepidopterology.butterflyInterface; + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyHelper.java b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyHelper.java new file mode 100755 index 000000000..17295b99d --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyHelper.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.genetics; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map.Entry; + +import net.minecraft.entity.EntityLiving; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.IMutation; +import forestry.api.lepidopterology.EnumButterflyChromosome; +import forestry.api.lepidopterology.EnumFlutterType; +import forestry.api.lepidopterology.IAlleleButterflySpecies; +import forestry.api.lepidopterology.IButterfly; +import forestry.api.lepidopterology.IButterflyGenome; +import forestry.api.lepidopterology.IButterflyMutation; +import forestry.api.lepidopterology.IButterflyRoot; +import forestry.api.lepidopterology.ILepidopteristTracker; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.SpeciesRoot; +import forestry.core.utils.Utils; +import forestry.lepidopterology.entities.EntityButterfly; +import forestry.plugins.PluginLepidopterology; + +public class ButterflyHelper extends SpeciesRoot implements IButterflyRoot { + + public static int butterflySpeciesCount = -1; + public static final String UID = "rootButterflies"; + + @Override + public String getUID() { + return UID; + } + + @Override + public Class getMemberClass() { + return IButterfly.class; + } + + @Override + public int getSpeciesCount() { + if (butterflySpeciesCount < 0) { + butterflySpeciesCount = 0; + for (Entry entry : AlleleManager.alleleRegistry.getRegisteredAlleles().entrySet()) { + if (entry.getValue() instanceof IAlleleButterflySpecies) + if (((IAlleleButterflySpecies) entry.getValue()).isCounted()) + butterflySpeciesCount++; + } + } + + return butterflySpeciesCount; + } + + @Override + public boolean isMember(ItemStack stack) { + return getType(stack) != EnumFlutterType.NONE; + } + + private EnumFlutterType getType(ItemStack stack) { + if(stack == null) + return EnumFlutterType.NONE; + + if(ForestryItem.butterflyGE.isItemEqual(stack)) + return EnumFlutterType.BUTTERFLY; + else if(ForestryItem.serumGE.isItemEqual(stack)) + return EnumFlutterType.SERUM; + else if(ForestryItem.caterpillarGE.isItemEqual(stack)) + return EnumFlutterType.CATERPILLAR; + else + return EnumFlutterType.NONE; + } + + @Override + public boolean isMember(ItemStack stack, int type) { + return getType(stack).ordinal() == type; + } + + @Override + public boolean isMember(IIndividual individual) { + return individual instanceof IButterfly; + } + + @Override + public IButterfly getMember(ItemStack stack) { + if(!stack.hasTagCompound()) + return null; + if(!isMember(stack)) + return null; + + return new Butterfly(stack.getTagCompound()); + } + + @Override + public IButterfly getMember(NBTTagCompound compound) { + return new Butterfly(compound); + } + + @Override + public ItemStack getMemberStack(IIndividual butterfly, int type) { + + Item butterflyItem; + switch(EnumFlutterType.VALUES[type]) { + case SERUM: + butterflyItem = ForestryItem.serumGE.item(); + break; + case CATERPILLAR: + butterflyItem = ForestryItem.caterpillarGE.item(); + break; + case BUTTERFLY: + default: + butterflyItem = ForestryItem.butterflyGE.item(); + break; + } + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + butterfly.writeToNBT(nbttagcompound); + ItemStack stack = new ItemStack(butterflyItem); + stack.setTagCompound(nbttagcompound); + return stack; + + } + + @Override + public EntityLiving spawnButterflyInWorld(World world, IButterfly butterfly, double x, double y, double z) { + return (EntityButterfly)Utils.spawnEntity(world, new EntityButterfly(world, butterfly), x, y, z); + } + + @Override + public boolean isMated(ItemStack stack) { + IButterfly butterfly = getMember(stack); + if(butterfly == null) + return false; + + return butterfly.getMate() != null; + } + + /* GENOME CONVERSIONS */ + @Override + public IButterfly templateAsIndividual(IAllele[] template) { + return new Butterfly(templateAsGenome(template)); + } + + @Override + public IButterfly templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive) { + return new Butterfly(templateAsGenome(templateActive, templateInactive)); + } + + @Override + public IButterflyGenome templateAsGenome(IAllele[] template) { + return new ButterflyGenome(templateAsChromosomes(template)); + } + + @Override + public IButterflyGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive) { + return new ButterflyGenome(templateAsChromosomes(templateActive, templateInactive)); + } + + /* TEMPLATES */ + public static ArrayList butterflyTemplates = new ArrayList(); + + @Override + public ArrayList getIndividualTemplates() { + return butterflyTemplates; + } + + @Override + public IAllele[] getDefaultTemplate() { + return ButterflyTemplates.getDefaultTemplate(); + } + + @Override + public void registerTemplate(String identifier, IAllele[] template) { + butterflyTemplates.add(PluginLepidopterology.butterflyInterface.templateAsIndividual(template)); + speciesTemplates.put(identifier, template); + } + + /* MUTATIONS */ + private static ArrayList butterflyMutations = new ArrayList(); + + @Override + public void registerMutation(IMutation mutation) { + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getTemplate()[0].getUID())) + return; + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getAllele0().getUID())) + return; + if (AlleleManager.alleleRegistry.isBlacklisted(mutation.getAllele1().getUID())) + return; + + butterflyMutations.add((IButterflyMutation)mutation); + } + + @Override + public Collection getMutations(boolean shuffle) { + if (shuffle) + Collections.shuffle(butterflyMutations); + return butterflyMutations; + } + + /* BREEDING TRACKER */ + @Override + public ILepidopteristTracker getBreedingTracker(World world, String player) { + String filename = "LepidopteristTracker." + player; + LepidopteristTracker tracker = (LepidopteristTracker) world.loadItemData(LepidopteristTracker.class, filename); + + // Create a tracker if there is none yet. + if (tracker == null) { + tracker = new LepidopteristTracker(filename, player); + world.setItemData(filename, tracker); + } + + return tracker; + } + + @Override + public IChromosomeType[] getKaryotype() { + return EnumButterflyChromosome.values(); + } + + @Override + public IChromosomeType getKaryotypeKey() { + return EnumButterflyChromosome.SPECIES; + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyTemplates.java b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyTemplates.java new file mode 100755 index 000000000..a305a8d4a --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/ButterflyTemplates.java @@ -0,0 +1,304 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.genetics; + +import forestry.api.genetics.IAllele; +import forestry.api.lepidopterology.EnumButterflyChromosome; +import forestry.core.genetics.Allele; + +public class ButterflyTemplates { + + public static IAllele[] getDefaultTemplate() { + IAllele[] alleles = new IAllele[EnumButterflyChromosome.values().length]; + + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiCabbageWhite; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeSmall; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlowest; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShorter; + alleles[EnumButterflyChromosome.METABOLISM.ordinal()] = Allele.int3; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int3; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceNone; + alleles[EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceNone; + alleles[EnumButterflyChromosome.NOCTURNAL.ordinal()] = Allele.boolFalse; + alleles[EnumButterflyChromosome.TOLERANT_FLYER.ordinal()] = Allele.boolFalse; + alleles[EnumButterflyChromosome.FIRE_RESIST.ordinal()] = Allele.boolFalse; + alleles[EnumButterflyChromosome.FLOWER_PROVIDER.ordinal()] = Allele.flowersVanilla; + alleles[EnumButterflyChromosome.EFFECT.ordinal()] = Allele.butterflyNone; + + return alleles; + } + + public static IAllele[] getCabbageWhiteTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeAverage; + return alleles; + } + + public static IAllele[] getGlasswingTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiGlasswing; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeSmaller; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int5; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceDown1; + return alleles; + } + + public static IAllele[] getEmeraldPeacockTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiEmeraldPeacock; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarge; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanNormal; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int5; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceDown1; + alleles[EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceDown1; + return alleles; + } + + public static IAllele[] getCitrusSwallowTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiCitrusSwallow; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarge; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int10; + alleles[EnumButterflyChromosome.METABOLISM.ordinal()] = Allele.int8; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShorter; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceDown1; + alleles[EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceDown1; + return alleles; + } + + public static IAllele[] getBlackSwallowTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiBlackSwallow; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlow; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarge; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShorter; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceDown1; + alleles[EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceDown1; + return alleles; + } + + public static IAllele[] getBrimstoneMothTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.mothBrimstone; + return alleles; + } + + public static IAllele[] getSpeckledWoodTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiSpeckledWood; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getMadeiranSpeckledWoodTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiMadeiranSpeckledWood; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getCanarySpeckledWoodTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiCanarySpeckledWood; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getMenelausBlueMorphoTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiMenelausBlueMorpho; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarger; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShortest; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getRhetenorBlueMorphoTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiRhetenorBlueMorpho; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarger; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShortest; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getPeleidesBlueMorphoTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiPeleidesBlueMorpho; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarger; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShortest; + alleles[EnumButterflyChromosome.FERTILITY.ordinal()] = Allele.int2; + return alleles; + } + + public static IAllele[] getBrimstoneTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiBrimstone; + return alleles; + } + + public static IAllele[] getAuroraTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiAurora; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeSmaller; + return alleles; + } + + public static IAllele[] getPostillionTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiPostillion; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlow; + return alleles; + } + + public static IAllele[] getPalaenoSulphurTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiPalaenoSulphur; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlower; + return alleles; + } + + public static IAllele[] getResedaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiReseda; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlower; + return alleles; + } + + public static IAllele[] getSpringAzureTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiSpringAzure; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeSmaller; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + return alleles; + } + + public static IAllele[] getGozoraAzureTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiGozoraAzure; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeSmaller; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShort; + return alleles; + } + + public static IAllele[] getCommaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiComma; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlower; + return alleles; + } + + public static IAllele[] getBatesiaTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiBatesia; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarge; + return alleles; + } + + public static IAllele[] getBlueWingTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiBlueWing; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeAverage; + alleles[EnumButterflyChromosome.METABOLISM.ordinal()] = Allele.int5; + return alleles; + } + + public static IAllele[] getBlueDukeTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiBlueDuke; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceBoth1; + return alleles; + } + + public static IAllele[] getGlassyTigerTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiGlassyTiger; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeAverage; + return alleles; + } + + public static IAllele[] getPostmanTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiPostman; + return alleles; + } + + public static IAllele[] getSpicebushTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiSpicebush; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeAverage; + return alleles; + } + + public static IAllele[] getMalachiteTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiMalachite; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeAverage; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceDown1; + alleles[EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceDown1; + return alleles; + } + + public static IAllele[] getLeopardLacewingTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiLLacewing; + alleles[EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()] = Allele.toleranceUp1; + alleles[EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()] = Allele.toleranceUp1; + return alleles; + } + + public static IAllele[] getMonarchTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiMonarch; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeAverage; + return alleles; + } + + public static IAllele[] getThoasSwallowTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiThoasSwallow; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLarge; + alleles[EnumButterflyChromosome.LIFESPAN.ordinal()] = Allele.lifespanShortest; + return alleles; + } + + public static IAllele[] getZebraSwallowTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiZebraSwallow; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeAverage; + return alleles; + } + + public static IAllele[] getDianaFritTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.lepiDianaFrit; + alleles[EnumButterflyChromosome.SPEED.ordinal()] = Allele.speedSlower; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeSmaller; + return alleles; + } + + public static IAllele[] getLatticedHeathTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.mothLatticedHeath; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeSmallest; + return alleles; + } + + public static IAllele[] getAtlasMothTemplate() { + IAllele[] alleles = getDefaultTemplate(); + alleles[EnumButterflyChromosome.SPECIES.ordinal()] = Allele.mothAtlas; + alleles[EnumButterflyChromosome.SIZE.ordinal()] = Allele.sizeLargest; + return alleles; + } + + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/genetics/LepidopteristTracker.java b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/LepidopteristTracker.java new file mode 100755 index 000000000..62a6e8a20 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/genetics/LepidopteristTracker.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.genetics; + +import net.minecraft.entity.player.EntityPlayer; + +import forestry.api.genetics.IBreedingTracker; +import forestry.api.genetics.IIndividual; +import forestry.api.lepidopterology.IButterfly; +import forestry.api.lepidopterology.ILepidopteristTracker; +import forestry.core.genetics.BreedingTracker; +import forestry.plugins.PluginLepidopterology; + +public class LepidopteristTracker extends BreedingTracker implements ILepidopteristTracker { + + public LepidopteristTracker(String s) { + this(s, ""); + } + + public LepidopteristTracker(String s, String player) { + super(s, player); + } + + @Override + protected IBreedingTracker getCommonTracker(EntityPlayer player) { + return PluginLepidopterology.butterflyInterface.getBreedingTracker(player.worldObj, "__COMMON_"); + } + + @Override + protected String getPacketTag() { + return ButterflyHelper.UID; + } + + @Override + public void registerPickup(IIndividual individual) { + } + + @Override + public void registerCatch(IButterfly butterfly) { + registerSpecies(butterfly.getGenome().getPrimary()); + registerSpecies(butterfly.getGenome().getSecondary()); + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/gui/ContainerFlutterlyzer.java b/forestry_common/lepidopterology/forestry/lepidopterology/gui/ContainerFlutterlyzer.java new file mode 100755 index 000000000..ca170dd2d --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/gui/ContainerFlutterlyzer.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; + +import forestry.core.config.ForestryItem; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.proxy.Proxies; +import forestry.lepidopterology.items.ItemButterflyGE; +import forestry.lepidopterology.items.ItemFlutterlyzer.FlutterlyzerInventory; + +public class ContainerFlutterlyzer extends ContainerItemInventory { + + FlutterlyzerInventory inventory; + + public ContainerFlutterlyzer(InventoryPlayer inventoryplayer, FlutterlyzerInventory inventory) { + super(inventory, inventoryplayer.player); + + this.inventory = inventory; + + // Energy + this.addSlot(new SlotCustom(inventory, FlutterlyzerInventory.SLOT_ENERGY, 172, 8, new Object[] { ForestryItem.honeydew, ForestryItem.honeyDrop })); + + // Bee to analyze + this.addSlot(new SlotCustom(inventory, FlutterlyzerInventory.SLOT_SPECIMEN, 172, 26, new Object[] { ItemButterflyGE.class, Blocks.sapling })); + + // Analyzed bee + this.addSlot(new SlotCustom(inventory, FlutterlyzerInventory.SLOT_ANALYZE_1, 172, 57, new Object[] { ItemButterflyGE.class })); + this.addSlot(new SlotCustom(inventory, FlutterlyzerInventory.SLOT_ANALYZE_2, 172, 75, new Object[] { ItemButterflyGE.class })); + this.addSlot(new SlotCustom(inventory, FlutterlyzerInventory.SLOT_ANALYZE_3, 172, 93, new Object[] { ItemButterflyGE.class })); + this.addSlot(new SlotCustom(inventory, FlutterlyzerInventory.SLOT_ANALYZE_4, 172, 111, new Object[] { ItemButterflyGE.class })); + this.addSlot(new SlotCustom(inventory, FlutterlyzerInventory.SLOT_ANALYZE_5, 172, 129, new Object[] { ItemButterflyGE.class })); + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) + for (int l1 = 0; l1 < 9; l1++) + addSecuredSlot(inventoryplayer, l1 + i1 * 9 + 9, 18 + l1 * 18, 156 + i1 * 18); + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) + addSecuredSlot(inventoryplayer, j1, 18 + j1 * 18, 214); + + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + + if (!Proxies.common.isSimulating(entityplayer.worldObj)) + return; + + // Last slot is the energy slot, so we don't save that one. + for (int i = 0; i < inventory.getSizeInventory(); i++) { + if (i == FlutterlyzerInventory.SLOT_ENERGY) + continue; + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + Proxies.common.dropItemPlayer(entityplayer, stack); + inventory.setInventorySlotContents(i, null); + } + + inventory.onGuiSaved(entityplayer); + + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + return true; + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/gui/GuiFlutterlyzer.java b/forestry_common/lepidopterology/forestry/lepidopterology/gui/GuiFlutterlyzer.java new file mode 100755 index 000000000..7562d274b --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/gui/GuiFlutterlyzer.java @@ -0,0 +1,332 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.gui; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleEffect; +import forestry.api.genetics.IAlleleFlowers; +import forestry.api.genetics.IAlleleInteger; +import forestry.api.genetics.IMutation; +import forestry.api.lepidopterology.EnumButterflyChromosome; +import forestry.api.lepidopterology.IButterfly; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.AlleleBoolean; +import forestry.core.genetics.AlleleTolerance; +import forestry.core.genetics.ClimateHelper; +import forestry.core.genetics.GenericRatings; +import forestry.core.gui.GuiAlyzer; +import forestry.core.utils.StackUtils; +import forestry.core.utils.StringUtil; +import forestry.lepidopterology.items.ItemButterflyGE; +import forestry.lepidopterology.items.ItemFlutterlyzer.FlutterlyzerInventory; +import forestry.plugins.PluginLepidopterology; + +public class GuiFlutterlyzer extends GuiAlyzer { + + private ItemStack[] tempProductList; + + public GuiFlutterlyzer(EntityPlayer player, FlutterlyzerInventory inventory) { + super(AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies"), player, + new ContainerFlutterlyzer(player.inventory, inventory), inventory, 1, inventory.getSizeInventory()); + + xSize = 196; + ySize = 238; + + ArrayList butterflyList = new ArrayList(); + ((ItemButterflyGE) ForestryItem.butterflyGE.item()).addCreativeItems(butterflyList, false); + for (ItemStack butterflyStack : butterflyList) + iconStacks.put(PluginLepidopterology.butterflyInterface.getMember(butterflyStack).getIdent(), butterflyStack); + + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + int page = 0; + IButterfly butterfly = null; + for (int k = 1; k < FlutterlyzerInventory.SLOT_ANALYZE_5 + 1; k++) { + if (k == FlutterlyzerInventory.SLOT_ENERGY) + continue; + + if (inventory.getStackInSlot(k) == null) + continue; + butterfly = PluginLepidopterology.butterflyInterface.getMember(inventory.getStackInSlot(k)); + if (butterfly == null || !butterfly.isAnalyzed()) + continue; + + page = k; + break; + } + + switch (page) { + case 1: + drawAnalyticsPage1(butterfly); + break; + case 2: + drawAnalyticsPage2(butterfly); + break; + case 3: + drawAnalyticsPage3(butterfly); + break; + case 4: + drawAnalyticsPage4(butterfly); + break; + case 6: + drawAnalyticsPageClassification(butterfly); + break; + default: + drawAnalyticsOverview(); + } + + } + + private void drawAnalyticsOverview() { + + startPage(); + + newLine(); + String title = StringUtil.localize("item.flutterlyzer").toUpperCase(); + drawCenteredLine(title, 8, 158); + newLine(); + + fontRendererObj.drawSplitString(StringUtil.localize("gui.flutterlyzer.help"), (int) ((guiLeft + COLUMN_0 + 4) * (1 / factor)), + (int) ((guiTop + 42) * (1 / factor)), (int) (158 * (1 / factor)), fontColor.get("gui.screen")); + newLine(); + newLine(); + newLine(); + newLine(); + + drawLine(StringUtil.localize("gui.beealyzer.overview") + ":", COLUMN_0 + 4); + newLine(); + drawLine("I : " + StringUtil.localize("gui.general"), COLUMN_0 + 4); + newLine(); + drawLine("II : " + StringUtil.localize("gui.environment"), COLUMN_0 + 4); + newLine(); + drawLine("III: " + StringUtil.localize("gui.produce"), COLUMN_0 + 4); + newLine(); + drawLine("IV : " + StringUtil.localize("gui.evolution"), COLUMN_0 + 4); + + endPage(); + } + + private void drawAnalyticsPage1(IButterfly butterfly) { + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.active"), COLUMN_1); + drawLine(StringUtil.localize("gui.inactive"), COLUMN_2); + + newLine(); + newLine(); + + drawSpeciesRow(StringUtil.localize("gui.species"), butterfly, EnumButterflyChromosome.SPECIES); + newLine(); + + drawRow(StringUtil.localize("gui.size"), butterfly.getGenome().getActiveAllele(EnumButterflyChromosome.SIZE.ordinal()).getName(), + butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.SIZE.ordinal()).getName(), butterfly, EnumButterflyChromosome.SPEED); + + drawRow(StringUtil.localize("gui.lifespan"), butterfly.getGenome().getActiveAllele(EnumButterflyChromosome.LIFESPAN.ordinal()).getName(), + butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.LIFESPAN.ordinal()).getName(), butterfly, + EnumButterflyChromosome.LIFESPAN); + + drawRow(StringUtil.localize("gui.speed"), butterfly.getGenome().getActiveAllele(EnumButterflyChromosome.SPEED.ordinal()).getName(), + butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.SPEED.ordinal()).getName(), butterfly, EnumButterflyChromosome.SPEED); + + drawRow(StringUtil.localize("gui.metabolism"), GenericRatings.rateMetabolism(butterfly.getGenome().getMetabolism()), + GenericRatings.rateMetabolism(((IAlleleInteger) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.METABOLISM.ordinal())).getValue()), butterfly, EnumButterflyChromosome.METABOLISM); + + drawLine(StringUtil.localize("gui.fertility"), COLUMN_0); + drawFertilityInfo(butterfly.getGenome().getFertility(), COLUMN_1, getColorCoding(butterfly.getGenome().getActiveAllele(EnumButterflyChromosome.FERTILITY.ordinal()) + .isDominant()), 8); + drawFertilityInfo(((IAlleleInteger) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.FERTILITY.ordinal())).getValue(), COLUMN_2, getColorCoding(butterfly + .getGenome().getInactiveAllele(EnumButterflyChromosome.FERTILITY.ordinal()).isDominant()), 8); + + newLine(); + + drawRow(StringUtil.localize("gui.flowers"), StringUtil.localize(butterfly.getGenome().getFlowerProvider().getDescription()), + StringUtil.localize(((IAlleleFlowers) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.FLOWER_PROVIDER.ordinal())).getProvider() + .getDescription()), butterfly, EnumButterflyChromosome.FLOWER_PROVIDER); + + drawRow(StringUtil.localize("gui.effect"), StringUtil.localize(butterfly.getGenome().getEffect().getName()), + StringUtil.localize(((IAlleleEffect) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.EFFECT.ordinal())).getName()), butterfly, + EnumButterflyChromosome.EFFECT); + + newLine(); + + + endPage(); + + } + private void drawAnalyticsPage2(IButterfly butterfly) { + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.active"), COLUMN_1); + drawLine(StringUtil.localize("gui.inactive"), COLUMN_2); + + newLine(); + newLine(); + + drawRow(StringUtil.localize("gui.climate"), ClimateHelper.toDisplay(butterfly.getGenome().getPrimary().getTemperature()), + ClimateHelper.toDisplay(butterfly.getGenome().getPrimary().getTemperature()), butterfly, EnumButterflyChromosome.SPECIES); + + drawLine(StringUtil.localize("gui.temptol"), COLUMN_0); + drawToleranceInfo(butterfly.getGenome().getToleranceTemp(), COLUMN_1, + getColorCoding(butterfly.getGenome().getActiveAllele(EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()).isDominant())); + drawToleranceInfo(((AlleleTolerance) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal())).getValue(), COLUMN_2, + getColorCoding(butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.TEMPERATURE_TOLERANCE.ordinal()).isDominant())); + + newLine(); + + drawRow(StringUtil.localize("gui.humidity"), ClimateHelper.toDisplay(butterfly.getGenome().getPrimary().getHumidity()), + ClimateHelper.toDisplay(butterfly.getGenome().getPrimary().getHumidity()), butterfly, EnumButterflyChromosome.SPECIES); + + drawLine(StringUtil.localize("gui.humidtol"), COLUMN_0); + drawToleranceInfo(butterfly.getGenome().getToleranceHumid(), COLUMN_1, + getColorCoding(butterfly.getGenome().getActiveAllele(EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()).isDominant())); + drawToleranceInfo(((AlleleTolerance) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal())).getValue(), COLUMN_2, + getColorCoding(butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.HUMIDITY_TOLERANCE.ordinal()).isDominant())); + + newLine(); + newLine(); + + String yes = StringUtil.localize("yes"); + String no = StringUtil.localize("no"); + + String diurnal0, diurnal1, nocturnal0, nocturnal1; + if(butterfly.getGenome().getNocturnal()) { + nocturnal0 = diurnal0 = yes; + } else { + nocturnal0 = butterfly.getGenome().getPrimary().isNocturnal() ? yes : no; + diurnal0 = !butterfly.getGenome().getPrimary().isNocturnal() ? yes : no; + } + if(((AlleleBoolean) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.NOCTURNAL.ordinal())).getValue()) { + nocturnal1 = diurnal1 = yes; + } else { + nocturnal1 = butterfly.getGenome().getSecondary().isNocturnal() ? yes : no; + diurnal1 = !butterfly.getGenome().getSecondary().isNocturnal() ? yes : no; + } + + drawLine(StringUtil.localize("gui.diurnal"), COLUMN_0); + drawLine(diurnal0, COLUMN_1, getColorCoding(false)); + drawLine(diurnal1, COLUMN_2, getColorCoding(false)); + newLine(); + + drawLine(StringUtil.localize("gui.nocturnal"), COLUMN_0); + drawLine(nocturnal0, COLUMN_1, getColorCoding(false)); + drawLine(nocturnal1, COLUMN_2, getColorCoding(false)); + newLine(); + + String primary = StringUtil.readableBoolean(butterfly.getGenome().getTolerantFlyer(), yes, no); + String secondary = StringUtil.readableBoolean(((AlleleBoolean) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.TOLERANT_FLYER.ordinal())).getValue(), yes, + no); + + drawRow(StringUtil.localize("gui.flyer"), primary, secondary, butterfly, EnumButterflyChromosome.TOLERANT_FLYER); + + primary = StringUtil.readableBoolean(butterfly.getGenome().getFireResist(), yes, no); + secondary = StringUtil.readableBoolean(((AlleleBoolean) butterfly.getGenome().getInactiveAllele(EnumButterflyChromosome.FIRE_RESIST.ordinal())).getValue(), yes, + no); + + drawRow(StringUtil.localize("gui.fireresist"), primary, secondary, butterfly, EnumButterflyChromosome.FIRE_RESIST); + + endPage(); + + } + private void drawAnalyticsPage3(IButterfly butterfly) { + + tempProductList = butterfly.getGenome().getPrimary().getButterflyLoot().keySet().toArray(StackUtils.EMPTY_STACK_ARRAY); + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + + drawLine(StringUtil.localize("gui.loot.butterfly") + ":", COLUMN_0); + newLine(); + + int x = COLUMN_0; + for (ItemStack stack : tempProductList) { + itemRender.renderItemIntoGUI(fontRendererObj, mc.renderEngine, stack, (int) ((guiLeft + x) * (1 / factor)), + (int) ((guiTop + getLineY()) * (1 / factor))); + x += 18; + if (x > adjustToFactor(148)) { + x = COLUMN_0; + newLine(); + } + } + + newLine(); + newLine(); + + drawLine(StringUtil.localize("gui.loot.caterpillar") + ":", COLUMN_0); + newLine(); + + x = COLUMN_0; + for (ItemStack stack : butterfly.getGenome().getPrimary().getCaterpillarLoot().keySet().toArray(StackUtils.EMPTY_STACK_ARRAY)) { + itemRender.renderItemIntoGUI(fontRendererObj, mc.renderEngine, stack, (int) ((guiLeft + x) * (1 / factor)), + (int) ((guiTop + getLineY()) * (1 / factor))); + x += 18; + if (x > adjustToFactor(148)) { + x = COLUMN_0; + newLine(); + } + } + + endPage(); + } + private void drawAnalyticsPage4(IButterfly butterfly) { + + startPage(COLUMN_0, COLUMN_1, COLUMN_2); + drawLine(StringUtil.localize("gui.beealyzer.mutations") + ":", COLUMN_0); + newLine(); + newLine(); + + RenderHelper.enableGUIStandardItemLighting(); + + HashMap combinations = new HashMap(); + + /* + for (IMutation mutation : TreeTemplates.getCombinations(butterfly.getGenome().getPrimary())) + combinations.put(mutation, butterfly.getGenome().getPrimary()); + + for (IMutation mutation : TreeTemplates.getCombinations(butterfly.getGenome().getSecondary())) + combinations.put(mutation, butterfly.getGenome().getSecondary()); + */ + + int columnWidth = 50; + int x = 0; + + for (Map.Entry mutation : combinations.entrySet()) { + + //if (breedingTracker.isDiscovered(mutation.getKey())) + drawMutationInfo(mutation.getKey(), mutation.getValue(), COLUMN_0 + x); + /*else { + // Do not display secret undiscovered mutations. + if (mutation.getKey().isSecret()) + continue; + + drawUnknownMutation(mutation.getKey(), mutation.getValue(), COLUMN_0 + x); + } */ + + x += columnWidth; + if (x > 150) { + x = 0; + newLine(); + newLine(); + } + } + + endPage(); + + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/items/ItemButterflyGE.java b/forestry_common/lepidopterology/forestry/lepidopterology/items/ItemButterflyGE.java new file mode 100755 index 000000000..155736415 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/items/ItemButterflyGE.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.items; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.Tabs; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAlleleSpecies; +import forestry.api.genetics.IIndividual; +import forestry.api.lepidopterology.EnumFlutterType; +import forestry.api.lepidopterology.IButterfly; +import forestry.api.lepidopterology.IButterflyNursery; +import forestry.core.config.Config; +import forestry.core.genetics.ItemGE; +import forestry.core.network.PacketFXSignal; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.Utils; +import forestry.lepidopterology.entities.EntityButterfly; +import forestry.plugins.PluginLepidopterology; + +public class ItemButterflyGE extends ItemGE { + + EnumFlutterType type; + + public ItemButterflyGE(EnumFlutterType type) { + super(); + setCreativeTab(Tabs.tabLepidopterology); + this.type = type; + } + + @Override + protected int getDefaultPrimaryColour() { + return 0; + } + + @Override + protected int getDefaultSecondaryColour() { + return 0; + } + + @Override + protected IIndividual getIndividual(ItemStack itemstack) { + return PluginLepidopterology.butterflyInterface.getMember(itemstack); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + + if (itemstack.getTagCompound() == null) + return "???"; + + IButterfly butterfly = PluginLepidopterology.butterflyInterface.getMember(itemstack); + if(butterfly == null) + return "???"; + + return butterfly.getDisplayName(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { + addCreativeItems(itemList, true); + } + + public void addCreativeItems(List itemList, boolean hideSecrets) { + + for (IIndividual individual : PluginLepidopterology.butterflyInterface.getIndividualTemplates()) { + // Don't show secret butterflies unless ordered to. + if (hideSecrets && individual.isSecret() && !Config.isDebug) + continue; + + itemList.add(PluginLepidopterology.butterflyInterface.getMemberStack(individual, type.ordinal())); + } + } + + @Override + public boolean onEntityItemUpdate(EntityItem entityItem) { + if(type != EnumFlutterType.BUTTERFLY) + return false; + if(!Proxies.common.isSimulating(entityItem.worldObj) || entityItem.ticksExisted < 80) + return false; + if(entityItem.worldObj.getTotalWorldTime() % 24 != 0) + return false; + + IButterfly butterfly = PluginLepidopterology.butterflyInterface.getMember(entityItem.getEntityItem()); + if(butterfly == null) + return false; + + if(!butterfly.canTakeFlight(entityItem.worldObj, entityItem.posX, entityItem.posY, entityItem.posZ)) + return false; + + if(entityItem.worldObj.countEntities(EntityButterfly.class) > PluginLepidopterology.entityConstraint) + return false; + + if(Utils.spawnEntity(entityItem.worldObj, new EntityButterfly(entityItem.worldObj, butterfly), entityItem.posX, entityItem.posY, entityItem.posZ) != null) { + if(entityItem.getEntityItem().stackSize > 1) + entityItem.getEntityItem().stackSize--; + else + entityItem.setDead(); + return true; + } + + return false; + } + + /* ICONS FOR SERUMS */ + @Override + public int getColorFromItemStack(ItemStack itemstack, int renderPass) { + if (!itemstack.hasTagCompound()) + return super.getColorFromItemStack(itemstack, renderPass); + + return getColourFromSpecies(AlleleManager.alleleRegistry.getIndividual(itemstack).getGenome().getPrimary(), renderPass); + } + + @Override + public int getColourFromSpecies(IAlleleSpecies species, int renderPass) { + if (species != null) + return species.getIconColour(renderPass); + else + return 0xffffff; + + } + + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getRenderPasses(int metadata) { + return 2; + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + icons = new IIcon[2]; + switch(this.type) { + case CATERPILLAR: + icons[0] = TextureManager.getInstance().registerTex(register, "caterpillar.body"); + icons[1] = TextureManager.getInstance().registerTex(register, "caterpillar.body2"); + break; + default: + icons[0] = TextureManager.getInstance().registerTex(register, "liquids/jar.contents"); + icons[1] = TextureManager.getInstance().registerTex(register, "liquids/jar.bottle"); + } + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int i, int j) { + if (j > 0) + return icons[1]; + else + return icons[0]; + } + + @Override + public boolean onItemUse(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int par7, float facingX, float facingY, float facingZ) { + + if (!Proxies.common.isSimulating(world)) + return false; + + IButterfly flutter = PluginLepidopterology.butterflyInterface.getMember(itemstack); + if(flutter == null) + return false; + + if(type == EnumFlutterType.CATERPILLAR) { + + TileEntity target = world.getTileEntity(x, y, z); + if(!(target instanceof IButterflyNursery)) + return false; + + IButterflyNursery pollinatable = (IButterflyNursery)target; + if(!pollinatable.canNurse(flutter)) + return false; + + pollinatable.setCaterpillar(flutter); + Proxies.common.sendFXSignal(PacketFXSignal.VisualFXType.BLOCK_DESTROY, PacketFXSignal.SoundFXType.LEAF, world, x, y, z, + world.getBlock(x, y, z), 0); + if (!player.capabilities.isCreativeMode) + itemstack.stackSize--; + return true; + + } else + return false; + } + + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/items/ItemFlutterlyzer.java b/forestry_common/lepidopterology/forestry/lepidopterology/items/ItemFlutterlyzer.java new file mode 100755 index 000000000..5bbab580a --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/items/ItemFlutterlyzer.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.world.World; + +import forestry.api.core.ForestryAPI; +import forestry.api.core.Tabs; +import forestry.api.lepidopterology.IButterfly; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.IHintSource; +import forestry.core.items.ItemInventoried; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ItemInventory; +import forestry.plugins.PluginLepidopterology; + +public class ItemFlutterlyzer extends ItemInventoried { + + public static class FlutterlyzerInventory extends ItemInventory implements IErrorSource, IHintSource { + + public final static int SLOT_SPECIMEN = 0; + public final static int SLOT_ANALYZE_1 = 1; + public final static int SLOT_ANALYZE_2 = 2; + public final static int SLOT_ANALYZE_3 = 3; + public final static int SLOT_ANALYZE_4 = 4; + public final static int SLOT_ANALYZE_5 = 6; + public final static int SLOT_ENERGY = 5; + EntityPlayer player; + + public FlutterlyzerInventory(EntityPlayer player) { + super(ItemFlutterlyzer.class, 7); + this.player = player; + } + + public FlutterlyzerInventory(EntityPlayer player, ItemStack itemStack) { + super(ItemFlutterlyzer.class, 7, itemStack); + this.player = player; + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + NBTTagList nbttaglist = new NBTTagList(); + for (int i = SLOT_ENERGY; i < SLOT_ENERGY + 1; i++) { + if (inventoryStacks[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("Slot", (byte) i); + inventoryStacks[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + } + nbttagcompound.setTag("Items", nbttaglist); + + } + + private boolean isEnergy(ItemStack itemstack) { + if (itemstack == null || itemstack.stackSize <= 0) + return false; + + return ForestryItem.honeyDrop.isItemEqual(itemstack) || ForestryItem.honeydew.isItemEqual(itemstack); + } + + private void tryAnalyze() { + + // Analyzed slot occupied, abort + if (inventoryStacks[SLOT_ANALYZE_1] != null || inventoryStacks[SLOT_ANALYZE_2] != null || inventoryStacks[SLOT_ANALYZE_3] != null + || inventoryStacks[SLOT_ANALYZE_4] != null || inventoryStacks[SLOT_ANALYZE_5] != null) + return; + + // Source slot to analyze empty + if (getStackInSlot(SLOT_SPECIMEN) == null) + return; + + IButterfly butterfly = PluginLepidopterology.butterflyInterface.getMember(getStackInSlot(SLOT_SPECIMEN)); + // No tree, abort + if (butterfly == null) { + return; + } + + // Analyze if necessary + if (!butterfly.isAnalyzed()) { + + // Requires energy + if (!isEnergy(getStackInSlot(SLOT_ENERGY))) + return; + + butterfly.analyze(); + if (player != null) { + PluginLepidopterology.butterflyInterface.getBreedingTracker(player.worldObj, player.getGameProfile().getId()).registerSpecies(butterfly.getGenome().getPrimary()); + PluginLepidopterology.butterflyInterface.getBreedingTracker(player.worldObj, player.getGameProfile().getId()).registerSpecies(butterfly.getGenome().getSecondary()); + } + NBTTagCompound nbttagcompound = new NBTTagCompound(); + butterfly.writeToNBT(nbttagcompound); + getStackInSlot(SLOT_SPECIMEN).setTagCompound(nbttagcompound); + + // Decrease energy + decrStackSize(SLOT_ENERGY, 1); + } + + setInventorySlotContents(SLOT_ANALYZE_1, getStackInSlot(SLOT_SPECIMEN)); + setInventorySlotContents(SLOT_SPECIMEN, null); + } + + @Override + public void markDirty() { + tryAnalyze(); + } + + /* IHINTSOURCE */ + @Override + public boolean hasHints() { + return Config.hints.get("flutterlyzer") != null && Config.hints.get("flutterlyzer").length > 0; + } + + @Override + public String[] getHints() { + return Config.hints.get("flutterlyzer"); + } + + /* IERRORSOURCE */ + @Override + public boolean throwsErrors() { + return true; + } + + @Override + public EnumErrorCode getErrorState() { + if (PluginLepidopterology.butterflyInterface.isMember(inventoryStacks[SLOT_SPECIMEN]) && !isEnergy(getStackInSlot(SLOT_ENERGY))) + return EnumErrorCode.NOHONEY; + + return EnumErrorCode.OK; + } + } + + public ItemFlutterlyzer() { + super(); + setMaxStackSize(1); + setCreativeTab(Tabs.tabLepidopterology); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) + entityplayer.openGui(ForestryAPI.instance, GuiId.FlutterlyzerGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + + return itemstack; + } +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/proxy/ClientProxyLepidopterology.java b/forestry_common/lepidopterology/forestry/lepidopterology/proxy/ClientProxyLepidopterology.java new file mode 100755 index 000000000..ad039ab06 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/proxy/ClientProxyLepidopterology.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.proxy; + +import cpw.mods.fml.client.registry.RenderingRegistry; + +import net.minecraftforge.client.MinecraftForgeClient; + +import forestry.core.config.ForestryItem; +import forestry.core.utils.Localization; +import forestry.lepidopterology.entities.EntityButterfly; +import forestry.lepidopterology.render.ButterflyItemRenderer; +import forestry.lepidopterology.render.RenderButterfly; + +public class ClientProxyLepidopterology extends ProxyLepidopterology { + + @Override + public void initializeRendering() { + RenderingRegistry.registerEntityRenderingHandler(EntityButterfly.class, new RenderButterfly()); + MinecraftForgeClient.registerItemRenderer(ForestryItem.butterflyGE.item(), new ButterflyItemRenderer()); + } + + @Override + public void addLocalizations() { + Localization.instance.addLocalization("/lang/forestry/lepidopterology/"); + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/proxy/ProxyLepidopterology.java b/forestry_common/lepidopterology/forestry/lepidopterology/proxy/ProxyLepidopterology.java new file mode 100755 index 000000000..9279faa5a --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/proxy/ProxyLepidopterology.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.proxy; + +public class ProxyLepidopterology { + + public void initializeRendering() { + } + + public void addLocalizations() { + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/render/ButterflyItemRenderer.java b/forestry_common/lepidopterology/forestry/lepidopterology/render/ButterflyItemRenderer.java new file mode 100755 index 000000000..06ba00ba9 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/render/ButterflyItemRenderer.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.render; + +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.item.ItemStack; + +import net.minecraftforge.client.IItemRenderer; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import forestry.api.lepidopterology.IButterfly; +import forestry.core.proxy.Proxies; +import forestry.lepidopterology.entities.EntityButterfly; +import forestry.plugins.PluginLepidopterology; + +public class ButterflyItemRenderer implements IItemRenderer { + + ModelButterfly model; + EntityButterfly entity; + + public ButterflyItemRenderer() { + model = new ModelButterfly(); + } + + private static float getWingYaw(IButterfly butterfly) { + float wingYaw = 1f; + + if(butterfly.isAlive()) { + long systemTime = System.currentTimeMillis(); + long flapping = systemTime + butterfly.getIdent().hashCode(); + float flap = (float) (flapping % 1000) / 1000; // 0 to 1 + + wingYaw = getIrregularWingYaw(flapping, flap); + + } + + return wingYaw; + } + + public static float getIrregularWingYaw(long flapping, float flap) { + long irregular = (long)(flapping / 1000); + float wingYaw = 1f; + + if(irregular % 11 == 0) { + wingYaw = 0.75f; + } else { + if(irregular % 7 == 0) { + flap *= 4; + flap = flap % 1; + } else if(irregular % 19 == 0) { + flap *= 6; + flap = flap % 1; + } + wingYaw = getRegularWingYaw(flap); + } + + return wingYaw; + } + + public static float getRegularWingYaw(float flap) { + return flap < 0.5 ? 0.75f + flap : 1.75f - flap; + } + + private IButterfly initButterfly(ItemStack item, boolean scaled) { + IButterfly butterfly = PluginLepidopterology.butterflyInterface.getMember(item); + if(butterfly == null) + butterfly = PluginLepidopterology.butterflyInterface.templateAsIndividual(PluginLepidopterology.butterflyInterface.getDefaultTemplate()); + + if(entity == null) { + entity = new EntityButterfly(Proxies.common.getClientInstance().theWorld); + } + entity.setSpecies(butterfly.getGenome().getPrimary()); + if(scaled) + entity.setScale(butterfly.getSize()); + else + entity.setScale(EntityButterfly.DEFAULT_BUTTERFLY_SCALE); + + return butterfly; + } + + private void renderButterflyItem(IButterfly butterfly, float translateX, float translateY, float translateZ) { + float yaw = 1; + float pitch = 1; + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL11.GL_COLOR_MATERIAL); + + GL11.glPushMatrix(); + + if(RenderItem.renderInFrame) { + //GL11.glScalef(-2.0f, 2.0f, 2.0f); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glRotatef(-90.0F, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(-90.0F, 1.0F, 0.0F, 0.0F); + GL11.glScalef(1.1f, 1f, 1f); + + GL11.glTranslatef(0, -0.7f, 0.2f); + + entity.renderYawOffset = 0; + entity.rotationYaw = 0; + entity.rotationPitch = 0; + entity.rotationYawHead = entity.rotationYaw; + + RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0f); + + } else { + GL11.glTranslatef(translateX, translateY, translateZ); + + GL11.glScalef(-2.0f, 2.0f, 2.0f); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glRotatef(-135.0F, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(-((float) Math.atan((double) (pitch / 40.0F))) * 20.0F, 1.0F, 0.0F, 0.0F); + + entity.renderYawOffset = (float) Math.atan((double) (yaw / 40.0F)) * 20.0F; + entity.rotationYaw = (float) Math.atan((double) (yaw / 40.0F)) * 40.0F; + entity.rotationPitch = -((float) Math.atan((double) (pitch / 40.0F))) * 20.0F; + entity.rotationYawHead = entity.rotationYaw; + + RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, getWingYaw(butterfly)); + + } + + GL11.glPopMatrix(); + + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + GL11.glDisable(GL11.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + GL11.glPopAttrib(); + + } + + private void renderButterflyInInventory(IButterfly butterfly) { + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL11.GL_COLOR_MATERIAL); + RenderHelper.enableStandardItemLighting(); + GL11.glPushMatrix(); + + GL11.glTranslatef(0f, -0.75f, 0f); + GL11.glScalef(-2.0f, 2.0f, 2.0f); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glRotatef(135.0F, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(-35.0F, 1.0F, 0.0F, 0.0F); + GL11.glScalef(1.1f, 1f, 1f); + + entity.renderYawOffset = 0; + entity.rotationYaw = 0; + entity.rotationPitch = 0; + entity.rotationYawHead = entity.rotationYaw; + + RenderManager.instance.renderEntityWithPosYaw(entity, 0.0D, 0.0D, 0.0D, 0.0F, getWingYaw(butterfly)); + + GL11.glPopMatrix(); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + GL11.glDisable(GL11.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + GL11.glPopAttrib(); + + } + + @Override + public boolean handleRenderType(ItemStack item, ItemRenderType type) { + switch (type) { + case ENTITY: + case EQUIPPED: + case EQUIPPED_FIRST_PERSON: + case INVENTORY: + return true; + default: + return false; + } + } + + @Override + public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) { + switch(helper) { + case ENTITY_BOBBING: + case ENTITY_ROTATION: + return false; + default: + return true; + } + } + + @Override + public void renderItem(ItemRenderType type, ItemStack item, Object... data) { + + switch (type) { + case ENTITY: + renderButterflyItem(initButterfly(item, true), 0f, -1.0f, 0f); + break; + case EQUIPPED: + renderButterflyItem(initButterfly(item, true), 0.5f, -0.9f, 1.0f); + break; + case EQUIPPED_FIRST_PERSON: + renderButterflyItem(initButterfly(item, true), 0.5f, -0.9f, 1.0f); + break; + case INVENTORY: + renderButterflyInInventory(initButterfly(item, false)); + break; + default: + } + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/render/ModelButterfly.java b/forestry_common/lepidopterology/forestry/lepidopterology/render/ModelButterfly.java new file mode 100755 index 000000000..9e1b01c86 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/render/ModelButterfly.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.util.MathHelper; + +import org.lwjgl.opengl.GL11; + +public class ModelButterfly extends ModelBase { + + ModelRenderer wingRight; + ModelRenderer eyeRight; + ModelRenderer eyeLeft; + ModelRenderer wingLeft; + ModelRenderer body; + + private float scale; + + public ModelButterfly() { + textureWidth = 64; + textureHeight = 32; + + wingRight = new ModelRenderer(this, 0, 0); + wingRight.addBox(-7F, 0F, -6F, 7, 1, 13); + wingRight.setRotationPoint(-0.5F, 0.5F, 0F); + wingRight.setTextureSize(64, 32); + wingRight.mirror = true; + setRotation(wingRight, 0F, 0F, 0F); + eyeRight = new ModelRenderer(this, 40, 9); + eyeRight.addBox(0F, 0F, 0F, 1, 1, 1); + eyeRight.setRotationPoint(-1.1F, -0.5F, -4.5F); + eyeRight.setTextureSize(64, 32); + eyeRight.mirror = true; + setRotation(eyeRight, 0F, 0F, 0F); + eyeLeft = new ModelRenderer(this, 40, 7); + eyeLeft.addBox(0F, 0F, 0F, 1, 1, 1); + eyeLeft.setRotationPoint(0.1F, -0.5F, -4.5F); + eyeLeft.setTextureSize(64, 32); + eyeLeft.mirror = true; + setRotation(eyeLeft, 0F, 0F, 0F); + wingLeft = new ModelRenderer(this, 0, 14); + wingLeft.addBox(0F, 0F, -6F, 7, 1, 13); + wingLeft.setRotationPoint(0.5F, 0.5F, 0F); + wingLeft.setTextureSize(64, 32); + wingLeft.mirror = true; + setRotation(wingLeft, 0F, 0F, 0F); + body = new ModelRenderer(this, 40, 0); + body.addBox(0F, 0F, -4F, 1, 1, 6); + body.setRotationPoint(0F, 0F, 0F); + body.setTextureSize(64, 32); + body.mirror = true; + setRotation(body, 0F, 0F, 0.7853982F); + } + + public void setScale(float scale) { + this.scale = scale; + } + + @Override + public void render(Entity entity, float f, float f1, float swing, float f3, float f4, float f5) { + super.render(entity, f, f1, swing, f3, f4, f5); + + //body.rotateAngleX = ((float)Math.PI / 4F) + MathHelper.cos(swing * 0.1F) * 0.15F; + //body.rotateAngleY = 0.0F; + wingRight.rotateAngleZ = MathHelper.cos(swing * 1.3F) * (float)Math.PI * 0.25F; + wingLeft.rotateAngleZ = -wingRight.rotateAngleZ; + + GL11.glPushMatrix(); + GL11.glScalef(scale, scale, scale); + GL11.glTranslatef(0.0F, (12.0f / scale) * f5, 0.0F); + wingRight.render(f5); + eyeRight.render(f5); + eyeLeft.render(f5); + wingLeft.render(f5); + body.render(f5); + GL11.glPopMatrix(); + + } + + private void setRotation(ModelRenderer model, float x, float y, float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + + @Override + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity) { + super.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + } + +} diff --git a/forestry_common/lepidopterology/forestry/lepidopterology/render/RenderButterfly.java b/forestry_common/lepidopterology/forestry/lepidopterology/render/RenderButterfly.java new file mode 100755 index 000000000..0b9eda596 --- /dev/null +++ b/forestry_common/lepidopterology/forestry/lepidopterology/render/RenderButterfly.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.lepidopterology.render; + +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; + +import forestry.lepidopterology.entities.EntityButterfly; + +public class RenderButterfly extends RenderLiving { + + ModelButterfly butterflyModel; + + public RenderButterfly() { + super(new ModelButterfly(), 0.25f); + butterflyModel = (ModelButterfly)mainModel; + } + + public void renderButterfly(EntityButterfly entity, double x, double y, double z, float par8, float par9) { + if(!entity.isRenderable()) + return; + + butterflyModel.setScale(entity.getScale()); + super.doRender(entity, x, y, z, par8, entity.getWingFlap(par9)); + } + + @Override + public void doRender(Entity entity, double x, double y, double z, float par8, float par9) { + this.renderButterfly((EntityButterfly)entity, x, y, z, par8, par9); + } + + @Override + protected ResourceLocation getEntityTexture(Entity entity) { + return ((EntityButterfly)entity).getTexture(); + } + +} diff --git a/forestry_common/lepidopterology/forestry/plugins/PluginLepidopterology.java b/forestry_common/lepidopterology/forestry/plugins/PluginLepidopterology.java new file mode 100755 index 000000000..a4a4a39ff --- /dev/null +++ b/forestry_common/lepidopterology/forestry/plugins/PluginLepidopterology.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.Locale; + +import net.minecraft.block.material.Material; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; + +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.arboriculture.ITreeRoot; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.PluginInfo; +import forestry.api.core.Tabs; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IClassification; +import forestry.api.genetics.IClassification.EnumClassLevel; +import forestry.api.lepidopterology.EnumFlutterType; +import forestry.api.lepidopterology.IButterflyRoot; +import forestry.api.recipes.RecipeManagers; +import forestry.core.config.Configuration; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.config.Property; +import forestry.core.gadgets.BlockBase; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.genetics.Allele; +import forestry.core.genetics.Branch; +import forestry.core.items.ItemForestryBlock; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.core.utils.Utils; +import forestry.lepidopterology.ButterflySpawner; +import forestry.lepidopterology.GuiHandlerLepidopterology; +import forestry.lepidopterology.MatingRecipe; +import forestry.lepidopterology.entities.EntityButterfly; +import forestry.lepidopterology.gadgets.TileLepidopteristChest; +import forestry.lepidopterology.genetics.AlleleButterflySpecies; +import forestry.lepidopterology.genetics.AlleleEffectNone; +import forestry.lepidopterology.genetics.ButterflyHelper; +import forestry.lepidopterology.genetics.ButterflyTemplates; +import forestry.lepidopterology.items.ItemButterflyGE; +import forestry.lepidopterology.items.ItemFlutterlyzer; +import forestry.lepidopterology.proxy.ProxyLepidopterology; + +@PluginInfo(pluginID = "Lepidopterology", name = "Lepidopterology", author = "SirSengir", url = Defaults.URL, description = "Butterflies. Shiny.") +public class PluginLepidopterology extends NativePlugin { + + @SidedProxy(clientSide = "forestry.lepidopterology.proxy.ClientProxyLepidopterology", serverSide = "forestry.lepidopterology.proxy.ProxyLepidopterology") + public static ProxyLepidopterology proxy; + private static final String CONFIG_CATEGORY = "lepidopterology"; + private Configuration config; + public static int spawnConstraint = 100; + public static int entityConstraint = 1000; + public static IClassification geometridae; + public static IClassification saturniidae; + public static IClassification pieridae; + public static IClassification nymphalidae; + public static IClassification lycaenidae; + public static IClassification papilionidae; + public static IClassification notchidae; + /** + * See {@link IButterflyRoot} for details. + */ + public static IButterflyRoot butterflyInterface; + public static MachineDefinition definitionChest; + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public void preInit() { + super.preInit(); + + proxy.addLocalizations(); + + ForestryBlock.lepidopterology = new BlockBase(Material.iron); + ForestryBlock.lepidopterology.setBlockName("for.lepidopterology").setCreativeTab(Tabs.tabLepidopterology); + Proxies.common.registerBlock(ForestryBlock.lepidopterology, ItemForestryBlock.class); + + definitionChest = ForestryBlock.lepidopterology.addDefinition((new MachineDefinition(Defaults.DEFINITION_LEPICHEST_META, "forestry.LepiChest", TileLepidopteristChest.class, + ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.lepidopterology, 1, Defaults.DEFINITION_LEPICHEST_META), new Object[] { " # ", "XYX", "XXX", Character.valueOf('#'), Blocks.glass, Character.valueOf('X'), + ForestryItem.butterflyGE.getItemStack(1, Defaults.WILDCARD), Character.valueOf('Y'), Blocks.chest })) + .setFaces(0, 1, 2, 3, 4, 4, 0, 7))); + + + AlleleManager.alleleRegistry.registerSpeciesRoot(PluginLepidopterology.butterflyInterface = new ButterflyHelper()); + createAlleles(); + } + + @Override + public void doInit() { + super.doInit(); + + config = new Configuration(); + + Property property = config.get("entities.spawn.limit", CONFIG_CATEGORY, spawnConstraint); + property.Comment = "determines the global butterfly entity count above which natural spawning of butterflies ceases."; + spawnConstraint = Integer.parseInt(property.Value); + + property = config.get("entities.maximum.allowed", CONFIG_CATEGORY, entityConstraint); + property.Comment = "determines the global butterfly entity count above which butterflies will stay in item form and will not take flight anymore."; + entityConstraint = Integer.parseInt(property.Value); + + config.save(); + + Utils.registerEntity(EntityButterfly.class, "butterflyGE", 0, 0x000000, 0xffffff, 50, 1, true); + proxy.initializeRendering(); + registerTemplates(); + + definitionChest.register(); + + ((ITreeRoot) AlleleManager.alleleRegistry.getSpeciesRoot("rootTrees")).registerLeafTickHandler(new ButterflySpawner()); + } + + @Override + protected void registerItems() { + ForestryItem.flutterlyzer.registerItem(new ItemFlutterlyzer(), "flutterlyzer"); + ForestryItem.butterflyGE.registerItem(new ItemButterflyGE(EnumFlutterType.BUTTERFLY), "butterflyGE"); + ForestryItem.serumGE.registerItem(new ItemButterflyGE(EnumFlutterType.SERUM), "serumGE"); + ForestryItem.caterpillarGE.registerItem(new ItemButterflyGE(EnumFlutterType.CATERPILLAR), "caterpillarGE"); + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerCrates() { + } + + @SuppressWarnings("unchecked") + @Override + protected void registerRecipes() { + CraftingManager.getInstance().getRecipeList().add(new MatingRecipe()); + + RecipeManagers.carpenterManager.addRecipe(100, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 2000), null, ForestryItem.flutterlyzer.getItemStack(), + new Object[] { "X#X", "X#X", "RDR", Character.valueOf('#'), Blocks.glass_pane, Character.valueOf('X'), "ingotBronze", Character.valueOf('R'), + Items.redstone, Character.valueOf('D'), Items.diamond }); + } + + private void createAlleles() { + + IClassification lepidoptera = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.ORDER, "lepidoptera", "Lepidoptera"); + AlleleManager.alleleRegistry.getClassification("class.insecta").addMemberGroup(lepidoptera); + + geometridae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "geometridae", "Geometridae"); + lepidoptera.addMemberGroup(geometridae); + saturniidae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "saturniidae", "Saturniidae"); + lepidoptera.addMemberGroup(saturniidae); + + pieridae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "pieridae", "Pieridae"); + lepidoptera.addMemberGroup(pieridae); + nymphalidae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "nymphalidae", "Nymphalidae"); + lepidoptera.addMemberGroup(nymphalidae); + lycaenidae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "lycaenidae", "Lycaenidae"); + lepidoptera.addMemberGroup(lycaenidae); + papilionidae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "papilionidae", "Papilionidae"); + lepidoptera.addMemberGroup(papilionidae); + notchidae = AlleleManager.alleleRegistry.createAndRegisterClassification(EnumClassLevel.FAMILY, "notchidae", "Notchidae"); + lepidoptera.addMemberGroup(notchidae); + + /* GEOMETRIDAE */ + IClassification opisthograptis = createButterflyBranch(geometridae, "Opisthograptis"); + IClassification chiasmia = createButterflyBranch(geometridae, "Chiasmia"); + + Allele.mothBrimstone = new AlleleButterflySpecies("mothBrimstone", true, "Brimstone", opisthograptis, "luteolata", 0xffea40).setNocturnal(true).setRarity(1.0f); + Allele.mothLatticedHeath = new AlleleButterflySpecies("mothLatticedHeath", true, "Latticed Heath", chiasmia, "clathrata", 0xf2f0be).setNocturnal(true).setRarity(0.5f); + + /* SATURNIIDAE */ + IClassification attacus = createButterflyBranch(saturniidae, "Attacus"); + + Allele.mothAtlas = new AlleleButterflySpecies("mothAtlas", false, "Atlas", attacus, "atlas", 0xd96e3d).setNocturnal(true); + + /* PIERIDAE */ + IClassification pieris = createButterflyBranch(pieridae, "Pieris"); + IClassification gonepteryx = createButterflyBranch(pieridae, "Gonepteryx"); + IClassification anthocharis = createButterflyBranch(pieridae, "Anthocharis"); + IClassification colias = createButterflyBranch(pieridae, "Colias"); + IClassification pontia = createButterflyBranch(pieridae, "Pontia"); + IClassification celastrina = createButterflyBranch(pieridae, "Celastrina"); + + Allele.lepiCabbageWhite = new AlleleButterflySpecies("lepiCabbageWhite", true, "Cabbage White", pieris, "rapae", 0xccffee).setRarity(1.0f); + Allele.lepiBrimstone = new AlleleButterflySpecies("lepiBrimstone", true, "Brimstone", gonepteryx, "rhamni", 0xf0ee38).setRarity(1.0f); + Allele.lepiAurora = new AlleleButterflySpecies("lepiAurora", true, "Orange Tip", anthocharis, "cardamines", 0xe34f05).setRarity(0.5f); + Allele.lepiPostillion = new AlleleButterflySpecies("lepiPostillion", true, "Postillion", colias, "croceus", 0xd77e04).setRarity(0.5f); + Allele.lepiPalaenoSulphur = new AlleleButterflySpecies("lepiPalaenoSulphur", true, "Palaeno Sulphur", colias, "palaeno", 0xf8fba3).setRarity(0.4f); + Allele.lepiReseda = new AlleleButterflySpecies("lepiReseda", true, "Reseda", pontia, "edusa", 0x747d48).setRarity(0.3f); + + Allele.lepiSpringAzure = new AlleleButterflySpecies("lepiSpringAzure", true, "Spring Azure", celastrina, "argiolus", 0xb8cae2).setRarity(0.3f); + Allele.lepiGozoraAzure = new AlleleButterflySpecies("lepiGozoraAzure", true, "Gozora Azure", celastrina, "gozora", 0x6870e7).setRarity(0.2f); + + /* PAPILIONIDAE */ + IClassification papilio = createButterflyBranch(papilionidae, "Papilio"); + IClassification protographium = createButterflyBranch(papilionidae, "Protographium"); + + Allele.lepiCitrusSwallow = new AlleleButterflySpecies("lepiCitrusSwallow", false, "Citrus Swallowtail", papilio, "demodocus", 0xeae389).setRarity(1.0f) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.lepiEmeraldPeacock = new AlleleButterflySpecies("lepiEmeraldPeacock", true, "Emerald Peacock", papilio, "palinurus", 0x7cfe80) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.lepiThoasSwallow = new AlleleButterflySpecies("lepiThoasSwallow", false, "Thoas Swallowtail", papilio, "thoas", 0xeac783).setRarity(0.2f) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.lepiSpicebush = new AlleleButterflySpecies("lepiSpicebush", true, "Spicebush Swallowtail", papilio, "troilus", 0xeefeff).setRarity(0.5f); + Allele.lepiBlackSwallow = new AlleleButterflySpecies("lepiBlackSwallow", true, "Black Swallowtail", papilio, "polyxenes", 0xeac783).setRarity(1.0f); + + Allele.lepiZebraSwallow = new AlleleButterflySpecies("lepiZebraSwallow", true, "Zebra Swallowtail", protographium, "marcellus", 0xeafeff).setRarity(0.5f); + Allele.lepiDianaFrit = new AlleleButterflySpecies("lepiDianaFrit", true, "Diana Fritillary", protographium, "diana", 0xffac05).setRarity(0.6f); + + /* NYMPHALIDAE */ + IClassification pararge = createButterflyBranch(nymphalidae, "Pararge"); + IClassification polygonia = createButterflyBranch(nymphalidae, "Polygonia"); + IClassification morpho = createButterflyBranch(nymphalidae, "Morpho"); + IClassification greta = createButterflyBranch(nymphalidae, "Greta"); + IClassification batesia = createButterflyBranch(nymphalidae, "Batesia"); + IClassification myscelia = createButterflyBranch(nymphalidae, "Myscelia"); + IClassification danaus = createButterflyBranch(nymphalidae, "Danaus"); + IClassification bassarona = createButterflyBranch(nymphalidae, "Bassarona"); + IClassification parantica = createButterflyBranch(nymphalidae, "Parantica"); + IClassification heliconius = createButterflyBranch(nymphalidae, "Heliconius"); + IClassification siproeta = createButterflyBranch(nymphalidae, "Siproeta"); + IClassification cethosia = createButterflyBranch(nymphalidae, "Cethosia"); + + Allele.lepiGlasswing = new AlleleButterflySpecies("lepiGlasswing", true, "Glasswing", greta, "oto", 0x583732) + .setTemperature(EnumTemperature.WARM); + + Allele.lepiSpeckledWood = new AlleleButterflySpecies("lepiSpeckledWood", true, "Speckled Wood", pararge, "aegeria", 0x947245).setRarity(1.0f); + Allele.lepiMadeiranSpeckledWood = new AlleleButterflySpecies("lepiMSpeckledWood", true, "Madeiran Speckled Wood", pararge, "xiphia", 0x402919).setRarity(0.5f); + Allele.lepiCanarySpeckledWood = new AlleleButterflySpecies("lepiCSpeckledWood", true, "Canary Speckled Wood", pararge, "xiphioides", 0x51372a).setRarity(0.5f); + + Allele.lepiMenelausBlueMorpho = new AlleleButterflySpecies("lepiMBlueMorpho", true, "Menelaus Blue Morpho", morpho, "menelaus", 0x72e1fd).setRarity(0.5f) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.lepiPeleidesBlueMorpho = new AlleleButterflySpecies("lepiPBlueMorpho", true, "Peleides Blue Morpho", morpho, "peleides", 0x6ecce8).setRarity(0.25f) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.lepiRhetenorBlueMorpho = new AlleleButterflySpecies("lepiRBlueMorpho", true, "Rhetenor Blue Morpho", morpho, "rhetenor", 0x00bef8) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + + Allele.lepiComma = new AlleleButterflySpecies("lepiComma", true, "Comma", polygonia, "c-album", 0xf89505).setRarity(0.3f); + Allele.lepiBatesia = new AlleleButterflySpecies("lepiBatesia", true, "Painted Beauty", batesia, "hypochlora", 0xfe7763).setRarity(0.3f) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.lepiBlueWing = new AlleleButterflySpecies("lepiBlueWing", true, "Blue Wing", myscelia, "ethusa", 0x3a93cc).setRarity(0.3f); + + Allele.lepiMonarch = new AlleleButterflySpecies("lepiMonarch", true, "Monarch", danaus, "plexippus", 0xffa722).setRarity(0.2f); + Allele.lepiBlueDuke = new AlleleButterflySpecies("lepiBlueDuke", true, "Blue Duke", bassarona, "durga", 0x304240).setRarity(0.5f) + .setTemperature(EnumTemperature.COLD); + Allele.lepiGlassyTiger = new AlleleButterflySpecies("lepiGlassyTiger", true, "Glassy Tiger", parantica, "aglea", 0x5b3935).setRarity(0.3f); + Allele.lepiPostman = new AlleleButterflySpecies("lepiPostman", true, "Postman", heliconius, "melpmene", 0xf7302d).setRarity(0.3f); + Allele.lepiMalachite = new AlleleButterflySpecies("lepiMalachite", true, "Malachite", siproeta, "stelenes", 0xbdff53).setRarity(0.5f) + .setTemperature(EnumTemperature.WARM).setHumidity(EnumHumidity.DAMP); + Allele.lepiLLacewing = new AlleleButterflySpecies("lepiLLacewing", true, "Leopard Lacewing", cethosia, "cyane", 0xfb8a06).setRarity(0.7f); + + Allele.butterflyNone = new AlleleEffectNone("bfNone", false); + } + + private void registerTemplates() { + butterflyInterface.registerTemplate(ButterflyTemplates.getBrimstoneMothTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getLatticedHeathTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getAtlasMothTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getCabbageWhiteTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getGlasswingTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getEmeraldPeacockTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getThoasSwallowTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getCitrusSwallowTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getBlackSwallowTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getZebraSwallowTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getDianaFritTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getSpeckledWoodTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getMadeiranSpeckledWoodTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getCanarySpeckledWoodTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getMenelausBlueMorphoTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getRhetenorBlueMorphoTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getPeleidesBlueMorphoTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getBrimstoneTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getAuroraTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getPostillionTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getPalaenoSulphurTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getResedaTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getSpringAzureTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getGozoraAzureTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getCommaTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getBatesiaTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getBlueWingTemplate()); + + butterflyInterface.registerTemplate(ButterflyTemplates.getBlueDukeTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getGlassyTigerTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getMonarchTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getPostmanTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getSpicebushTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getMalachiteTemplate()); + butterflyInterface.registerTemplate(ButterflyTemplates.getLeopardLacewingTemplate()); + + } + + private IClassification createButterflyBranch(IClassification family, String scientific) { + IClassification branch = new Branch("moth." + scientific.toLowerCase(Locale.ENGLISH), scientific); + branch.setParent(family); + return branch; + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerLepidopterology(); + } +} diff --git a/forestry_common/mail/forestry/mail/CommandMail.java b/forestry_common/mail/forestry/mail/CommandMail.java new file mode 100755 index 000000000..14a8d45b9 --- /dev/null +++ b/forestry_common/mail/forestry/mail/CommandMail.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.util.List; + +import net.minecraft.command.ICommand; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.mail.ITradeStation; +import forestry.api.mail.PostManager; +import forestry.api.mail.TradeStationInfo; +import forestry.core.proxy.Proxies; +import forestry.core.utils.CommandMC; +import forestry.core.utils.StringUtil; + +public class CommandMail extends CommandMC { + + @Override + public int compareTo(Object arg0) { + return this.getCommandName().compareTo(((ICommand) arg0).getCommandName()); + } + + @Override + public String getCommandName() { + return "mail"; + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return "/" + this.getCommandName() + " help"; + } + + @SuppressWarnings("rawtypes") + @Override + public List getCommandAliases() { + return null; + } + + @Override + public void processCommand(ICommandSender sender, String[] arguments) { + if (arguments.length <= 0) + throw new WrongUsageException("Type '" + this.getCommandUsage(sender) + "' for help."); + + if (arguments[0].matches("trades")) { + commandTrades(sender, arguments); + return; + } else if (arguments[0].matches("virtualize")) { + commandVirtualize(sender, arguments); + return; + } else if (arguments[0].matches("help")) { + sendChatMessage(sender, "Format: '" + this.getCommandName() + " '"); + sendChatMessage(sender, "Available commands:"); + sendChatMessage(sender, "- trades : A list of all trade stations."); + sendChatMessage(sender, "- virtualize : Toggle virtual mode on specified trade station."); + return; + } + + throw new WrongUsageException(this.getCommandUsage(sender)); + } + + private void commandTrades(ICommandSender sender, String[] arguments) { + if (!(sender instanceof EntityPlayer)) + return; + for (ITradeStation trade : PostManager.postRegistry.getPostOffice(((EntityPlayer) sender).worldObj).getActiveTradeStations(((EntityPlayer) sender).worldObj).values()) + sendChatMessage(sender, makeTradeListEntry(trade.getTradeInfo())); + } + + private String makeTradeListEntry(TradeStationInfo info) { + String entry = "\u00A7c"; + if (info.state == EnumStationState.OK) + entry = "\u00A7a"; + + String tradegood = "[ ? ]"; + if (info.tradegood != null) + tradegood = info.tradegood.stackSize + "x" + info.tradegood.getDisplayName(); + String demand = "[ ? ]"; + if (info.required.length > 0) { + demand = ""; + for (ItemStack dmd : info.required) + demand = StringUtil.append(", ", demand, dmd.stackSize + "x" + dmd.getDisplayName()); + } + + return String.format("%s%-12s | %-20s | %s", entry, info.moniker, tradegood, demand); + } + + private void commandVirtualize(ICommandSender sender, String[] arguments) { + if ((sender instanceof EntityPlayer && !Proxies.common.isOp((EntityPlayer) sender)) || (!sender.canCommandSenderUseCommand(4, getCommandName()))) { + sendChatMessage(sender, "\u00a7cYou do not have permission to use this command."); + return; + } + + if (arguments.length <= 1) + throw new WrongUsageException("/" + getCommandName() + " virtualize "); + + World world = getWorld(sender, arguments); + ITradeStation trade = PostManager.postRegistry.getTradeStation(world, arguments[1]); + if (trade == null) { + sendChatMessage(sender, String.format("\u00a7cNo tradestation by the name of '%s' was found.", arguments[1])); + return; + } + + trade.setVirtual(!trade.isVirtual()); + sendChatMessage(sender, String.format("\u00A7aSet virtualization for '%s' to %s.", trade.getMoniker(), trade.isVirtual())); + } +} diff --git a/forestry_common/mail/forestry/mail/EnumAddressee.java b/forestry_common/mail/forestry/mail/EnumAddressee.java new file mode 100755 index 000000000..82a57f90a --- /dev/null +++ b/forestry_common/mail/forestry/mail/EnumAddressee.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +public enum EnumAddressee { + PLAYER, TRADER; + + public static EnumAddressee fromString(String ident) { + for(EnumAddressee addr : values()) { + if(addr.toString().equals(ident)) + return addr; + } + + return null; + } +} diff --git a/forestry_common/mail/forestry/mail/EnumDeliveryState.java b/forestry_common/mail/forestry/mail/EnumDeliveryState.java new file mode 100755 index 000000000..d04bd6d23 --- /dev/null +++ b/forestry_common/mail/forestry/mail/EnumDeliveryState.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.util.Locale; + +import forestry.api.mail.IPostalState; + +public enum EnumDeliveryState implements IPostalState { + OK, NO_MAILBOX, NOT_MAILABLE, ALREADY_MAILED, NOT_POSTPAID, MAILBOX_FULL, RESPONSE_NOT_MAILABLE; + + @Override + public boolean isOk() { + return this == OK; + } + + @Override + public String getIdentifier() { + return this.toString().toLowerCase(Locale.ENGLISH); + } +} diff --git a/forestry_common/mail/forestry/mail/EnumStationState.java b/forestry_common/mail/forestry/mail/EnumStationState.java new file mode 100755 index 000000000..8685584be --- /dev/null +++ b/forestry_common/mail/forestry/mail/EnumStationState.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.util.Locale; + +import forestry.api.mail.IPostalState; + +public enum EnumStationState implements IPostalState { + OK, INSUFFICIENT_OFFER, INSUFFICIENT_TRADE_GOOD, INSUFFICIENT_BUFFER, INSUFFICIENT_PAPER, INSUFFICIENT_STAMPS; + + @Override + public boolean isOk() { + return this == OK; + } + + @Override + public String getIdentifier() { + return this.toString().toLowerCase(Locale.ENGLISH); + } +} diff --git a/forestry_common/mail/forestry/mail/GuiHandlerMail.java b/forestry_common/mail/forestry/mail/GuiHandlerMail.java new file mode 100755 index 000000000..7bfb76584 --- /dev/null +++ b/forestry_common/mail/forestry/mail/GuiHandlerMail.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.core.GuiHandlerBase; +import forestry.core.network.GuiId; +import forestry.mail.gadgets.MachineMailbox; +import forestry.mail.gadgets.MachinePhilatelist; +import forestry.mail.gadgets.MachineTrader; +import forestry.mail.gui.ContainerCatalogue; +import forestry.mail.gui.ContainerLetter; +import forestry.mail.gui.ContainerMailbox; +import forestry.mail.gui.ContainerPhilatelist; +import forestry.mail.gui.ContainerTradeName; +import forestry.mail.gui.ContainerTrader; +import forestry.mail.gui.GuiCatalogue; +import forestry.mail.gui.GuiLetter; +import forestry.mail.gui.GuiMailbox; +import forestry.mail.gui.GuiPhilatelist; +import forestry.mail.gui.GuiTradeName; +import forestry.mail.gui.GuiTrader; +import forestry.mail.items.ItemCatalogue; +import forestry.mail.items.ItemLetter; +import forestry.mail.items.ItemLetter.LetterInventory; + +public class GuiHandlerMail extends GuiHandlerBase { + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + case CatalogueGUI: + ItemStack cata = getEquippedItem(player); + if (cata == null) + return null; + + if (cata.getItem() instanceof ItemCatalogue) + return new GuiCatalogue(player); + else + return null; + + case LetterGUI: + ItemStack equipped = getEquippedItem(player); + if (equipped == null) + return null; + + if (equipped.getItem() instanceof ItemLetter) + return new GuiLetter(player, new LetterInventory(equipped)); + else + return null; + + case MailboxGUI: + return new GuiMailbox(player.inventory, (MachineMailbox) getTileForestry(world, x, y, z)); + case PhilatelistGUI: + return new GuiPhilatelist(player.inventory, (MachinePhilatelist) getTileForestry(world, x, y, z)); + case TraderGUI: + return new GuiTrader(player.inventory, (MachineTrader) getTileForestry(world, x, y, z)); + case TraderNameGUI: + return new GuiTradeName(player.inventory, (MachineTrader) getTileForestry(world, x, y, z)); + default: + return null; + + } + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + case CatalogueGUI: + ItemStack cata = getEquippedItem(player); + if (cata == null) + return null; + + if (cata.getItem() instanceof ItemCatalogue) + return new ContainerCatalogue(player); + else + return null; + + case LetterGUI: + ItemStack equipped = getEquippedItem(player); + if (equipped == null) + return null; + + if (equipped.getItem() instanceof ItemLetter) + return new ContainerLetter(player, new LetterInventory(getEquippedItem(player))); + else + return null; + + case MailboxGUI: + return new ContainerMailbox(player.inventory, (MachineMailbox) getTileForestry(world, x, y, z)); + case PhilatelistGUI: + return new ContainerPhilatelist(player.inventory, (MachinePhilatelist) getTileForestry(world, x, y, z)); + case TraderGUI: + return new ContainerTrader(player.inventory, (MachineTrader) getTileForestry(world, x, y, z)); + case TraderNameGUI: + return new ContainerTradeName(player.inventory, (MachineTrader) getTileForestry(world, x, y, z)); + default: + return null; + + } + } + +} diff --git a/forestry_common/mail/forestry/mail/IMailContainer.java b/forestry_common/mail/forestry/mail/IMailContainer.java new file mode 100755 index 000000000..b36006ac6 --- /dev/null +++ b/forestry_common/mail/forestry/mail/IMailContainer.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +public interface IMailContainer { + boolean hasMail(); +} diff --git a/forestry_common/mail/forestry/mail/Letter.java b/forestry_common/mail/forestry/mail/Letter.java new file mode 100755 index 000000000..5e69d3cb6 --- /dev/null +++ b/forestry_common/mail/forestry/mail/Letter.java @@ -0,0 +1,323 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.core.INBTTagable; +import forestry.api.mail.ILetter; +import forestry.api.mail.IStamps; +import forestry.api.mail.MailAddress; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.StringUtil; + +public class Letter implements ILetter, INBTTagable { + + // CONSTANTS + public static short SLOT_ATTACHMENT_1 = 0; + public static short SLOT_POSTAGE_1 = 18; + + private boolean isProcessed = false; + + private MailAddress sender; + private MailAddress[] recipient; + + private String text; + private InventoryAdapter inventory = new InventoryAdapter(22, "INV"); + + public Letter(MailAddress sender, MailAddress recipient) { + this.sender = sender; + this.recipient = new MailAddress[] { recipient }; + } + + public Letter(NBTTagCompound nbttagcompound) { + if (nbttagcompound != null) + readFromNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + this.isProcessed = nbttagcompound.getBoolean("PRC"); + this.sender = MailAddress.loadFromNBT(nbttagcompound.getCompoundTag("SDR")); + + int recipientCount = nbttagcompound.getShort("CRC"); + this.recipient = new MailAddress[recipientCount]; + for (int i = 0; i < recipientCount; i++) + this.recipient[i] = MailAddress.loadFromNBT(nbttagcompound.getCompoundTag("RC" + i)); + + this.text = nbttagcompound.getString("TXT"); + + this.inventory.readFromNBT(nbttagcompound); + + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + + nbttagcompound.setBoolean("PRC", isProcessed); + + NBTTagCompound subcompound = new NBTTagCompound(); + this.sender.writeToNBT(subcompound); + nbttagcompound.setTag("SDR", subcompound); + + nbttagcompound.setShort("CRC", (short) recipient.length); + for (int i = 0; i < recipient.length; i++) { + subcompound = new NBTTagCompound(); + this.recipient[i].writeToNBT(subcompound); + nbttagcompound.setTag("RC" + i, subcompound); + } + + nbttagcompound.setString("TXT", this.text); + + inventory.writeToNBT(nbttagcompound); + } + + @Override + public ItemStack[] getPostage() { + return inventory.getStacks(SLOT_POSTAGE_1, 4); + } + + @Override + public ItemStack[] getAttachments() { + return inventory.getStacks(SLOT_ATTACHMENT_1, 18); + } + + @Override + public int countAttachments() { + + int count = 0; + for (ItemStack stack : getAttachments()) + if (stack != null) + count++; + + return count; + + } + + @Override + public void addAttachment(ItemStack itemstack) { + inventory.tryAddStack(itemstack, false); + } + + @Override + public void addAttachments(ItemStack[] itemstacks) { + for (ItemStack stack : itemstacks) + addAttachment(stack); + } + + @Override + public void invalidatePostage() { + for (int i = SLOT_POSTAGE_1; i < SLOT_POSTAGE_1 + 4; i++) + inventory.setInventorySlotContents(i, null); + } + + public void setInventory(InventoryAdapter inventory) { + this.inventory = inventory; + } + + @Override + public void setProcessed(boolean flag) { + this.isProcessed = flag; + } + + @Override + public boolean isProcessed() { + return this.isProcessed; + } + + @Override + public boolean isMailable() { + + // Can't resend an already sent letter + if (this.isProcessed) + return false; + + // Requires at least one recipient + if (this.recipient != null && this.recipient.length > 0) + return true; + + return false; + } + + @Override + public boolean isPostPaid() { + + int posted = 0; + + for (ItemStack stamp : getPostage()) { + if (stamp == null) + continue; + if (!(stamp.getItem() instanceof IStamps)) + continue; + + posted += ((IStamps) stamp.getItem()).getPostage(stamp).getValue() * stamp.stackSize; + } + + return posted >= requiredPostage(); + } + + @Override + public int requiredPostage() { + + int required = 1; + for (ItemStack attach : getAttachments()) + if (attach != null) + required++; + + return required; + } + + @Override + public void addStamps(ItemStack stamps) { + this.inventory.tryAddStack(stamps, SLOT_POSTAGE_1, 4, false); + } + + @Override + public boolean hasRecipient() { + if (getRecipients().length <= 0) + return false; + + MailAddress recipient = getRecipients()[0]; + if (recipient == null) + return false; + + if (recipient.getIdentifier().isEmpty()) + return false; + + return true; + } + + @Override + public void setSender(MailAddress address) { + this.sender = address; + } + + @Override + public MailAddress getSender() { + return sender; + } + + public void setRecipients(MailAddress[] recipients) { + this.recipient = recipients; + } + + @Override + public void setRecipient(MailAddress address) { + if (address == null) + this.recipient = new MailAddress[] {}; + else + this.recipient = new MailAddress[] { address }; + } + + @Override + public MailAddress[] getRecipients() { + return recipient; + } + + @Override + public String getRecipientString() { + String recipientString = ""; + for (MailAddress address : recipient) { + if (recipientString.length() > 0) + recipientString += ", "; + recipientString += address.getIdentifier(); + } + + return recipientString; + } + + @Override + public void setText(String text) { + this.text = text; + } + + @Override + public String getText() { + return text; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addTooltip(List list) { + if (this.sender != null) + list.add(StringUtil.localize("gui.mail.from") + ": " + this.sender.getIdentifier()); + if (this.recipient != null && this.recipient.length > 0) + list.add(StringUtil.localize("gui.mail.to") + ": " + this.getRecipientString()); + } + + // / IINVENTORY + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int var1) { + return inventory.getStackInSlot(var1); + } + + @Override + public ItemStack decrStackSize(int var1, int var2) { + return inventory.decrStackSize(var1, var2); + } + + @Override + public ItemStack getStackInSlotOnClosing(int var1) { + return inventory.getStackInSlotOnClosing(var1); + } + + @Override + public void setInventorySlotContents(int var1, ItemStack var2) { + inventory.setInventorySlotContents(var1, var2); + } + + @Override + public String getInventoryName() { + return inventory.getInventoryName(); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void markDirty() { + inventory.markDirty(); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer var1) { + return true; + } + + @Override + public void openInventory() { + inventory.openInventory(); + } + + @Override + public void closeInventory() { + inventory.closeInventory(); + } + + @Override + public boolean hasCustomInventoryName() { + return inventory.hasCustomInventoryName(); + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return inventory.isItemValidForSlot(i, itemstack); + } +} diff --git a/forestry_common/mail/forestry/mail/POBox.java b/forestry_common/mail/forestry/mail/POBox.java new file mode 100755 index 000000000..76f4eed1b --- /dev/null +++ b/forestry_common/mail/forestry/mail/POBox.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.WorldSavedData; + +import forestry.api.mail.ILetter; +import forestry.api.mail.PostManager; +import forestry.core.utils.InventoryAdapter; + +public class POBox extends WorldSavedData implements IInventory { + + public static final String SAVE_NAME = "POBox_"; + public static final short SLOT_SIZE = 84; + + private String owner; + private InventoryAdapter letters = new InventoryAdapter(SLOT_SIZE, "Letters"); + + public POBox(String owner, boolean isUser) { + super(SAVE_NAME + owner); + this.owner = owner; + } + + public POBox(String savename) { + super(savename); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + owner = nbttagcompound.getString("Owner"); + letters.readFromNBT(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + nbttagcompound.setString("Owner", owner); + letters.writeToNBT(nbttagcompound); + } + + public String getOwnerName() { + return this.owner; + } + + public boolean storeLetter(ItemStack letterstack) { + ILetter letter = PostManager.postRegistry.getLetter(letterstack); + + // Mark letter as processed + letter.setProcessed(true); + letter.invalidatePostage(); + NBTTagCompound nbttagcompound = new NBTTagCompound(); + letter.writeToNBT(nbttagcompound); + letterstack.setTagCompound(nbttagcompound); + + this.markDirty(); + return this.letters.tryAddStack(letterstack, true); + } + + public POBoxInfo getPOBoxInfo() { + int playerLetters = 0; + int tradeLetters = 0; + for (int i = 0; i < letters.getSizeInventory(); i++) { + if (letters.getStackInSlot(i) == null) + continue; + ILetter letter = new Letter(letters.getStackInSlot(i).getTagCompound()); + if (letter.getSender().isPlayer()) + playerLetters++; + else + tradeLetters++; + } + + return new POBoxInfo(playerLetters, tradeLetters); + } + + /* IINVENTORY */ + @Override + public void markDirty() { + this.markDirty(); + letters.markDirty(); + } + + @Override + public void setInventorySlotContents(int var1, ItemStack var2) { + this.markDirty(); + letters.setInventorySlotContents(var1, var2); + } + + @Override + public int getSizeInventory() { + return letters.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int var1) { + return letters.getStackInSlot(var1); + } + + @Override + public ItemStack decrStackSize(int var1, int var2) { + return letters.decrStackSize(var1, var2); + } + + @Override + public ItemStack getStackInSlotOnClosing(int var1) { + return letters.getStackInSlotOnClosing(var1); + } + + @Override + public String getInventoryName() { + return letters.getInventoryName(); + } + + @Override + public int getInventoryStackLimit() { + return letters.getInventoryStackLimit(); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer var1) { + return letters.isUseableByPlayer(var1); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return true; + } + +} diff --git a/forestry_common/mail/forestry/mail/POBoxInfo.java b/forestry_common/mail/forestry/mail/POBoxInfo.java new file mode 100755 index 000000000..f28677e3e --- /dev/null +++ b/forestry_common/mail/forestry/mail/POBoxInfo.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +public class POBoxInfo { + public final int playerLetters; + public final int tradeLetters; + + public POBoxInfo(int playerLetters, int tradeLetters) { + this.playerLetters = playerLetters; + this.tradeLetters = tradeLetters; + } + + public boolean hasMail() { + return playerLetters > 0 || tradeLetters > 0; + } +} diff --git a/forestry_common/mail/forestry/mail/PacketHandlerMail.java b/forestry_common/mail/forestry/mail/PacketHandlerMail.java new file mode 100755 index 000000000..c68e0c855 --- /dev/null +++ b/forestry_common/mail/forestry/mail/PacketHandlerMail.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.io.DataInputStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; + +import forestry.core.interfaces.IPacketHandler; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.mail.gui.ContainerCatalogue; +import forestry.mail.gui.ContainerLetter; +import forestry.mail.gui.ContainerTradeName; +import forestry.mail.network.PacketPOBoxInfo; +import forestry.mail.network.PacketTradeInfo; +import forestry.plugins.PluginMail; + +public class PacketHandlerMail implements IPacketHandler { + + @Override + public void onPacketData(int packetID, DataInputStream data, EntityPlayer player) { + + try { + + PacketUpdate packet; + switch (packetID) { + case PacketIds.TRADING_INFO: + PacketTradeInfo packetT = new PacketTradeInfo(); + packetT.readData(data); + onTradeInfo(packetT); + break; + case PacketIds.POBOX_INFO: + PacketPOBoxInfo packetP = new PacketPOBoxInfo(); + packetP.readData(data); + onPOBoxInfo(packetP); + break; + case PacketIds.LETTER_RECIPIENT: + packet = new PacketUpdate(); + packet.readData(data); + onLetterRecipient(player, packet); + break; + case PacketIds.LETTER_TEXT: + packet = new PacketUpdate(); + packet.readData(data); + onLetterText(player, packet); + break; + case PacketIds.TRADING_MONIKER_SET: + packet = new PacketUpdate(); + packet.readData(data); + onMonikerSet(player, packet); + break; + case PacketIds.POBOX_INFO_REQUEST: + onPOBoxInfoRequest(player); + break; + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + private void onTradeInfo(PacketTradeInfo packet) { + + Container container = Proxies.common.getClientInstance().thePlayer.openContainer; + if (container instanceof ContainerLetter) { + ((ContainerLetter) container).handleTradeInfoUpdate(packet); + } else if(container instanceof ContainerCatalogue) { + ((ContainerCatalogue) container).handleTradeInfoUpdate(packet); + } + + } + + private void onPOBoxInfo(PacketPOBoxInfo packet) { + PluginMail.proxy.setPOBoxInfo(Proxies.common.getRenderWorld(), Proxies.common.getClientInstance().thePlayer.getGameProfile().getId(), packet.poboxInfo); + } + + private void onMonikerSet(EntityPlayer player, PacketUpdate packet) { + if (!(player.openContainer instanceof ContainerTradeName)) + return; + + ((ContainerTradeName) player.openContainer).handleSetMoniker(packet); + } + + private void onLetterText(EntityPlayer player, PacketUpdate packet) { + if (!(player.openContainer instanceof ContainerLetter)) + return; + + ((ContainerLetter) player.openContainer).handleSetText(packet); + } + + private void onLetterRecipient(EntityPlayer player, PacketUpdate packet) { + if (!(player.openContainer instanceof ContainerLetter)) + return; + + ((ContainerLetter) player.openContainer).handleSetRecipient(player, packet); + } + + private void onPOBoxInfoRequest(EntityPlayer player) { + POBox pobox = PostRegistry.getPOBox(player.worldObj, player.getGameProfile().getId()); + if (pobox == null) + return; + + Proxies.net.sendToPlayer(new PacketPOBoxInfo(PacketIds.POBOX_INFO, pobox.getPOBoxInfo()), player); + } + +} diff --git a/forestry_common/mail/forestry/mail/PostOffice.java b/forestry_common/mail/forestry/mail/PostOffice.java new file mode 100755 index 000000000..798d12e0a --- /dev/null +++ b/forestry_common/mail/forestry/mail/PostOffice.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.io.File; +import java.util.LinkedHashMap; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.WorldSavedData; + +import forestry.api.mail.EnumPostage; +import forestry.api.mail.ILetter; +import forestry.api.mail.IPostOffice; +import forestry.api.mail.IPostalCarrier; +import forestry.api.mail.IPostalState; +import forestry.api.mail.IStamps; +import forestry.api.mail.ITradeStation; +import forestry.api.mail.MailAddress; +import forestry.api.mail.PostManager; +import forestry.core.config.ForestryItem; + +public class PostOffice extends WorldSavedData implements IPostOffice { + + // / CONSTANTS + public static final String SAVE_NAME = "ForestryMail"; + private int[] collectedPostage = new int[EnumPostage.values().length]; + + // / CONSTRUCTOR + public PostOffice(String s) { + super(s); + } + + public PostOffice() { + super(SAVE_NAME); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + for (int i = 0; i < collectedPostage.length; i++) { + if (nbttagcompound.hasKey("CPS" + i)) + collectedPostage[i] = nbttagcompound.getInteger("CPS" + i); + } + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + for (int i = 0; i < collectedPostage.length; i++) { + nbttagcompound.setInteger("CPS" + i, collectedPostage[i]); + } + } + + /* TRADE STATION MANAGMENT */ + private LinkedHashMap activeTradeStations; + + @Override + public LinkedHashMap getActiveTradeStations(World world) { + if (activeTradeStations == null) + refreshActiveTradeStations(world); + + return this.activeTradeStations; + } + + private void refreshActiveTradeStations(World world) { + activeTradeStations = new LinkedHashMap(); + if (world == null || world.getSaveHandler() == null) + return; + File worldSave = world.getSaveHandler().getMapFileFromName("dummy"); + if (worldSave == null) + return; + File file = worldSave.getParentFile(); + if (!file.exists() || !file.isDirectory()) + return; + + for (String str : file.list()) { + if (!str.startsWith(TradeStation.SAVE_NAME)) + continue; + if (!str.endsWith(".dat")) + continue; + + ITradeStation trade = PostManager.postRegistry.getTradeStation(world, str.replace(TradeStation.SAVE_NAME, "").replace(".dat", "")); + if (trade == null) + continue; + + registerTradeStation(trade); + } + } + + @Override + public void registerTradeStation(ITradeStation trade) { + if (activeTradeStations == null) + return; + + if (!activeTradeStations.containsKey(trade.getMoniker())) + activeTradeStations.put(trade.getMoniker(), trade); + + } + + @Override + public void deregisterTradeStation(ITradeStation trade) { + if (activeTradeStations == null) + return; + + activeTradeStations.remove(trade.getMoniker()); + } + + // / STAMP MANAGMENT + @Override + public ItemStack getAnyStamp(int max) { + return getAnyStamp(EnumPostage.values(), max); + } + + @Override + public ItemStack getAnyStamp(EnumPostage postage, int max) { + return getAnyStamp(new EnumPostage[] { postage }, max); + } + + @Override + public ItemStack getAnyStamp(EnumPostage[] postages, int max) { + + for (EnumPostage postage : postages) { + + int collected = 0; + if (collectedPostage[postage.ordinal()] <= 0) + continue; + + if (max >= collectedPostage[postage.ordinal()]) { + collected = collectedPostage[postage.ordinal()]; + collectedPostage[postage.ordinal()] = 0; + } else { + collected = max; + collectedPostage[postage.ordinal()] -= max; + } + + if (collected > 0) + return ForestryItem.stamps.getItemStack(collected, postage.ordinal() - 1); + } + + return null; + } + + // / DELIVERY + @Override + public IPostalState lodgeLetter(World world, ItemStack itemstack, boolean doLodge) { + ILetter letter = PostManager.postRegistry.getLetter(itemstack); + + if (letter.isProcessed()) + return EnumDeliveryState.ALREADY_MAILED; + + if (!letter.isPostPaid()) + return EnumDeliveryState.NOT_POSTPAID; + + if (!letter.isMailable()) + return EnumDeliveryState.NOT_MAILABLE; + + IPostalState state = EnumDeliveryState.NOT_MAILABLE; + for (MailAddress address : letter.getRecipients()) { + IPostalCarrier carrier = PostManager.postRegistry.getCarrier(address.getType()); + if (carrier == null) + continue; + state = carrier.deliverLetter(world, this, address.getIdentifier(), itemstack, doLodge); + if (!state.isOk()) + break; + } + /* + for (MailAddress address : letter.getRecipients()) + if (address.isPlayer()) + state = storeInPOBox(world, address, itemstack, doLodge); + else if (address.getType().equals(EnumAddressee.TRADER.toString())) + state = handleTradeLetter(world, address, itemstack, doLodge); + */ + + if (!state.isOk()) + return state; + + collectPostage(letter.getPostage()); + + markDirty(); + return EnumDeliveryState.OK; + + } + + @Override + public void collectPostage(ItemStack[] stamps) { + for (ItemStack stamp : stamps) { + if (stamp == null) + continue; + + if (stamp.getItem() instanceof IStamps) { + EnumPostage postage = ((IStamps) stamp.getItem()).getPostage(stamp); + collectedPostage[postage.ordinal()] += stamp.stackSize; + } + } + } +} diff --git a/forestry_common/mail/forestry/mail/PostRegistry.java b/forestry_common/mail/forestry/mail/PostRegistry.java new file mode 100755 index 000000000..d34a2d236 --- /dev/null +++ b/forestry_common/mail/forestry/mail/PostRegistry.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.io.File; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; + +import forestry.api.mail.ILetter; +import forestry.api.mail.IPostOffice; +import forestry.api.mail.IPostRegistry; +import forestry.api.mail.IPostalCarrier; +import forestry.api.mail.ITradeStation; +import forestry.api.mail.MailAddress; +import forestry.api.mail.PostManager; +import forestry.core.config.ForestryItem; +import forestry.mail.items.ItemLetter; +import forestry.plugins.PluginMail; + +public class PostRegistry implements IPostRegistry { + + public static PostOffice cachedPostOffice; + public static HashMap cachedPOBoxes = new HashMap(); + public static HashMap cachedTradeStations = new HashMap(); + + /** + * @param world + * @param username + * @return true if the passed username is valid for poboxes. + */ + @Override + public boolean isValidPOBox(World world, String username) { + if (!username.matches("^[a-zA-Z0-9]+$")) + return false; + + return true; + } + + public static POBox getPOBox(World world, String username) { + + if (cachedPOBoxes.containsKey(username.toLowerCase(Locale.ENGLISH))) + return cachedPOBoxes.get(username.toLowerCase(Locale.ENGLISH)); + + POBox pobox = (POBox) world.loadItemData(POBox.class, POBox.SAVE_NAME + username.toLowerCase(Locale.ENGLISH)); + if (pobox != null) + cachedPOBoxes.put(username.toLowerCase(Locale.ENGLISH), pobox); + return pobox; + } + + public static POBox getOrCreatePOBox(World world, String username) { + POBox pobox = getPOBox(world, username); + + if (pobox == null) { + pobox = new POBox(username.toLowerCase(Locale.ENGLISH), true); + world.setItemData(POBox.SAVE_NAME + username.toLowerCase(Locale.ENGLISH), pobox); + pobox.markDirty(); + cachedPOBoxes.put(username.toLowerCase(Locale.ENGLISH), pobox); + PluginMail.proxy.setPOBoxInfo(world, username, pobox.getPOBoxInfo()); + } + + return pobox; + } + + /** + * @param world + * @param moniker + * @return true if the passed moniker can be a moniker for a trade station + */ + @Override + public boolean isValidTradeMoniker(World world, String moniker) { + if (!moniker.matches("^[a-zA-Z0-9]+$")) + return false; + + return true; + } + + /** + * @param world + * @param moniker + * @return true if the trade moniker has not yet been used before. + */ + @Override + public boolean isAvailableTradeMoniker(World world, String moniker) { + return getTradeStation(world, moniker) == null; + } + + @Override + public TradeStation getTradeStation(World world, String moniker) { + if (cachedTradeStations.containsKey(moniker)) + return (TradeStation)cachedTradeStations.get(moniker); + + TradeStation trade = (TradeStation) world.loadItemData(TradeStation.class, TradeStation.SAVE_NAME + moniker); + + // Only existing and valid mail orders are returned + if (trade != null && trade.isValid()) { + cachedTradeStations.put(moniker, trade); + getPostOffice(world).registerTradeStation(trade); + return trade; + } + + return null; + } + + @Override + public TradeStation getOrCreateTradeStation(World world, String owner, String moniker) { + TradeStation trade = getTradeStation(world, moniker); + + if (trade == null) { + trade = new TradeStation(owner, moniker, true); + world.setItemData(TradeStation.SAVE_NAME + moniker, trade); + trade.markDirty(); + cachedTradeStations.put(moniker, trade); + getPostOffice(world).registerTradeStation(trade); + } + + return trade; + } + + @Override + public void deleteTradeStation(World world, String moniker) { + TradeStation trade = (TradeStation)getTradeStation(world, moniker); + if (trade == null) + return; + + // Need to be marked as invalid since WorldSavedData seems to do some caching of its own. + trade.invalidate(); + cachedTradeStations.remove(moniker); + getPostOffice(world).deregisterTradeStation(trade); + File file = world.getSaveHandler().getMapFileFromName(trade.mapName); + file.delete(); + } + + @Override + public IPostOffice getPostOffice(World world) { + if (cachedPostOffice != null) + return cachedPostOffice; + + PostOffice office = (PostOffice) world.loadItemData(PostOffice.class, PostOffice.SAVE_NAME); + + // Create office if there is none yet + if (office == null) { + office = new PostOffice(); + world.setItemData(PostOffice.SAVE_NAME, office); + } + + cachedPostOffice = office; + return office; + } + + /* CARRIER */ + private HashMap carriers = new HashMap(); + + @Override + public Map getRegisteredCarriers() { + return carriers; + } + + @Override + public void registerCarrier(IPostalCarrier carrier) { + carriers.put(carrier.getUID(), carrier); + } + + @Override + public IPostalCarrier getCarrier(String uid) { + return carriers.get(uid); + } + + /* LETTERS */ + @Override + public ILetter createLetter(MailAddress sender, MailAddress recipient) { + return new Letter(sender, recipient); + } + + @Override + public ItemStack createLetterStack(ILetter letter) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + letter.writeToNBT(nbttagcompound); + + ItemStack mailstack = ForestryItem.letters.getItemStack(1, ItemLetter.encodeMeta(1, ItemLetter.getType(letter))); + mailstack.setTagCompound(nbttagcompound); + + return mailstack; + } + + @Override + public ILetter getLetter(ItemStack itemstack) { + if (itemstack == null) + return null; + + if (!PostManager.postRegistry.isLetter(itemstack)) + return null; + + if (itemstack.getTagCompound() == null) + return null; + + return new Letter(itemstack.getTagCompound()); + } + + @Override + public boolean isLetter(ItemStack itemstack) { + return ForestryItem.letters.isItemEqual(itemstack); + } + + +} diff --git a/forestry_common/mail/forestry/mail/PostalCarrier.java b/forestry_common/mail/forestry/mail/PostalCarrier.java new file mode 100755 index 000000000..f2b7f4e0b --- /dev/null +++ b/forestry_common/mail/forestry/mail/PostalCarrier.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.util.Locale; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.mail.IPostOffice; +import forestry.api.mail.IPostalCarrier; +import forestry.api.mail.IPostalState; +import forestry.api.mail.ITradeStation; +import forestry.api.mail.PostManager; +import forestry.core.render.TextureManager; +import forestry.core.utils.StringUtil; +import forestry.plugins.PluginMail; + +public class PostalCarrier implements IPostalCarrier { + + private String uid; + private String iconID; + private EnumAddressee type; + + public PostalCarrier(EnumAddressee type) { + uid = type.toString().toLowerCase(Locale.ENGLISH); + iconID = "mail/carrier." + uid; + this.type = type; + } + + @Override + public String getUID() { + return uid; + } + + @Override + public String getName() { + return StringUtil.localize("gui.addressee." + uid); + } + + @Override + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return TextureManager.getInstance().getDefault(iconID); + } + + @Override + public IPostalState deliverLetter(World world, IPostOffice office, String recipient, ItemStack letterstack, boolean doDeliver) { + if(type == EnumAddressee.TRADER) + return handleTradeLetter(world, office, recipient, letterstack, doDeliver); + else + return storeInPOBox(world, office, recipient, letterstack, doDeliver); + } + + private IPostalState handleTradeLetter(World world, IPostOffice office, String recipient, ItemStack letterstack, boolean doLodge) { + IPostalState state = EnumDeliveryState.NOT_MAILABLE; + + ITradeStation trade = PostManager.postRegistry.getTradeStation(world, recipient); + if (trade == null) + return EnumDeliveryState.NO_MAILBOX; + + state = trade.handleLetter(world, recipient, letterstack, doLodge); + + return state; + } + + private EnumDeliveryState storeInPOBox(World world, IPostOffice office, String recipient, ItemStack letterstack, boolean doLodge) { + + POBox pobox = PostRegistry.getPOBox(world, recipient); + if (pobox == null) + return EnumDeliveryState.NO_MAILBOX; + + if (!pobox.storeLetter(letterstack.copy())) + return EnumDeliveryState.MAILBOX_FULL; + else + PluginMail.proxy.setPOBoxInfo(world, recipient, pobox.getPOBoxInfo()); + + return EnumDeliveryState.OK; + } + +} diff --git a/forestry_common/mail/forestry/mail/SaveEventHandlerMail.java b/forestry_common/mail/forestry/mail/SaveEventHandlerMail.java new file mode 100755 index 000000000..610d935dd --- /dev/null +++ b/forestry_common/mail/forestry/mail/SaveEventHandlerMail.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import net.minecraft.world.World; + +import forestry.core.interfaces.ISaveEventHandler; +import forestry.plugins.PluginMail; + +public class SaveEventHandlerMail implements ISaveEventHandler { + + @Override + public void onWorldLoad(World world) { + PostRegistry.cachedPostOffice = null; + PostRegistry.cachedPOBoxes.clear(); + PostRegistry.cachedTradeStations.clear(); + PluginMail.proxy.clearMailboxInfo(); + } + + @Override + public void onWorldSave(World world) { + } + + @Override + public void onWorldUnload(World world) { + } + +} diff --git a/forestry_common/mail/forestry/mail/TickHandlerMailClient.java b/forestry_common/mail/forestry/mail/TickHandlerMailClient.java new file mode 100755 index 000000000..96aca6b8e --- /dev/null +++ b/forestry_common/mail/forestry/mail/TickHandlerMailClient.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent.Phase; +import cpw.mods.fml.common.gameevent.TickEvent.RenderTickEvent; + +import forestry.mail.gui.GuiMailboxInfo; +import forestry.plugins.PluginMail; + +public class TickHandlerMailClient { + public TickHandlerMailClient() { + FMLCommonHandler.instance().bus().register(this); + } + + @SubscribeEvent + public void onRenderTick(RenderTickEvent event) { + if (event.phase != Phase.END) return; + + if (GuiMailboxInfo.instance != null) + GuiMailboxInfo.instance.render(0, 0); + else + PluginMail.proxy.resetMailboxInfo(); + } +} diff --git a/forestry_common/mail/forestry/mail/TradeStation.java b/forestry_common/mail/forestry/mail/TradeStation.java new file mode 100755 index 000000000..fe812a567 --- /dev/null +++ b/forestry_common/mail/forestry/mail/TradeStation.java @@ -0,0 +1,492 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail; + +import java.util.ArrayList; +import java.util.Locale; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.WorldSavedData; + +import forestry.api.mail.EnumPostage; +import forestry.api.mail.ILetter; +import forestry.api.mail.IPostalState; +import forestry.api.mail.IStamps; +import forestry.api.mail.ITradeStation; +import forestry.api.mail.MailAddress; +import forestry.api.mail.PostManager; +import forestry.api.mail.TradeStationInfo; +import forestry.core.config.ForestryItem; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.StackUtils; +import forestry.mail.items.ItemLetter; + +public class TradeStation extends WorldSavedData implements ITradeStation, IInventory { + + // / CONSTANTS + public static final String SAVE_NAME = "TradePO_"; + public static final short SLOT_SIZE = 39; + public static final short SLOT_TRADEGOOD = 0; + public static final short SLOT_EXCHANGE_1 = 1; + public static final short SLOT_EXCHANGE_COUNT = 4; + public static final short SLOT_LETTERS_1 = 5; + public static final short SLOT_LETTERS_COUNT = 6; + public static final short SLOT_STAMPS_1 = 11; + public static final short SLOT_STAMPS_COUNT = 4; + public static final short SLOT_INPUTBUF_1 = 15; + public static final short SLOT_OUTPUTBUF_1 = 27; + public static final short SLOT_BUFFER_COUNT = 12; + // / MEMBER + private String owner; + private String moniker; + private boolean isVirtual = false; + private boolean isInvalid = false; + private final InventoryAdapter inventory = new InventoryAdapter(SLOT_SIZE, "INV"); + + // / CONSTRUCTORS + public TradeStation(String owner, String moniker, boolean isMoniker) { + super(SAVE_NAME + moniker); + this.owner = owner; + this.moniker = moniker; + } + + public TradeStation(String savename) { + super(savename); + } + + @Override + public String getMoniker() { + return this.moniker; + } + + // / SAVING & LOADING + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + this.owner = nbttagcompound.getString("OWN"); + this.moniker = nbttagcompound.getString("MNK"); + this.isVirtual = nbttagcompound.getBoolean("VRT"); + this.isInvalid = nbttagcompound.getBoolean("IVL"); + inventory.readFromNBT(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + if (this.owner != null && !this.owner.isEmpty()) + nbttagcompound.setString("OWN", this.owner); + nbttagcompound.setString("MNK", this.moniker); + nbttagcompound.setBoolean("VRT", this.isVirtual); + nbttagcompound.setBoolean("IVL", this.isInvalid); + inventory.writeToNBT(nbttagcompound); + } + + /* INVALIDATING */ + @Override + public boolean isValid() { + return !this.isInvalid; + } + + @Override + public void invalidate() { + this.isInvalid = true; + } + + /* INFORMATION */ + @Override + public void setVirtual(boolean isVirtual) { + this.isVirtual = isVirtual; + markDirty(); + } + + @Override + public boolean isVirtual() { + return isVirtual; + } + + @Override + public TradeStationInfo getTradeInfo() { + ItemStack[] condensedRequired = StackUtils.condenseStacks(inventory.getStacks(SLOT_EXCHANGE_1, SLOT_EXCHANGE_COUNT)); + + // Set current state + EnumStationState state = EnumStationState.OK; + + // Virtual trade stations are always ready for service + if (!isVirtual()) { + if (!hasPaper()) + state = EnumStationState.INSUFFICIENT_PAPER; + if (!canPayPostage(2)) + state = EnumStationState.INSUFFICIENT_STAMPS; + if (countFillableOrders(1, inventory.getStackInSlot(SLOT_TRADEGOOD)) <= 0) + state = EnumStationState.INSUFFICIENT_TRADE_GOOD; + } + + return new TradeStationInfo(moniker, owner, inventory.getStackInSlot(SLOT_TRADEGOOD), condensedRequired, state); + } + + /* ILETTERHANDLER */ + @Override + public IPostalState handleLetter(World world, String recipient, ItemStack letterstack, boolean doLodge) { + + ILetter letter = PostManager.postRegistry.getLetter(letterstack); + + if (!isVirtual() && !hasPaper()) + return EnumStationState.INSUFFICIENT_PAPER; + + int ordersToFill = StackUtils.containsSets(inventory.getStacks(SLOT_EXCHANGE_1, SLOT_EXCHANGE_COUNT), letter.getAttachments()); + // Not a single match. + if (ordersToFill <= 0) + return EnumStationState.INSUFFICIENT_OFFER; + + if (!isVirtual()) { + int fillable = countFillableOrders(ordersToFill, inventory.getStackInSlot(SLOT_TRADEGOOD)); + // Nothing can be filled. + if (fillable <= 0) + return EnumStationState.INSUFFICIENT_TRADE_GOOD; + if (fillable < ordersToFill) + ordersToFill = fillable; + + // Check for sufficient output buffer + int storable = countStorablePayment(ordersToFill, inventory.getStacks(SLOT_EXCHANGE_1, SLOT_EXCHANGE_COUNT)); + if (storable <= 0) + return EnumStationState.INSUFFICIENT_BUFFER; + if (storable < ordersToFill) + ordersToFill = storable; + } + + // Prepare and send letter + ILetter mail = new Letter(new MailAddress(this.moniker, EnumAddressee.TRADER.toString().toLowerCase(Locale.ENGLISH)), letter.getSender()); + mail.setText("Please find your order attached."); + for (int i = 0; i < ordersToFill; i++) { + mail.addAttachment(inventory.getStackInSlot(SLOT_TRADEGOOD).copy()); + } + mail.addAttachments(getSurplusAttachments(ordersToFill, letter.getAttachments())); + + // Attach necessary postage + int requiredPostage = mail.requiredPostage(); + if (!isVirtual()) + if (!canPayPostage(requiredPostage)) + return EnumStationState.INSUFFICIENT_STAMPS; + + int[] stampCount = getPostage(requiredPostage, isVirtual()); + for (int i = 0; i < stampCount.length; i++) { + if (stampCount[i] > 0) + mail.addStamps(ForestryItem.stamps.getItemStack(stampCount[i], EnumPostage.values()[i].ordinal())); + } + + NBTTagCompound nbttagcompound = new NBTTagCompound(); + mail.writeToNBT(nbttagcompound); + + ItemStack mailstack = ForestryItem.letters.getItemStack(1, ItemLetter.encodeMeta(1, ItemLetter.getType(mail))); + mailstack.setTagCompound(nbttagcompound); + + IPostalState responseState = PostManager.postRegistry.getPostOffice(world).lodgeLetter(world, mailstack, doLodge); + if (!responseState.isOk()) { + return EnumDeliveryState.RESPONSE_NOT_MAILABLE; + } + + // Store received items + for (int i = 0; i < ordersToFill; i++) { + for (ItemStack stack : inventory.getStacks(SLOT_EXCHANGE_1, SLOT_EXCHANGE_COUNT)) { + if (stack == null) + continue; + inventory.tryAddStack(stack.copy(), SLOT_OUTPUTBUF_1, SLOT_BUFFER_COUNT, false); + } + } + + // Remove resources + removePaper(); + removeStamps(stampCount); + removeTradegood(ordersToFill); + markDirty(); + + // Send confirmation message to seller + if (doLodge && owner != null && !owner.isEmpty()) { + ILetter confirm = new Letter(new MailAddress(this.moniker, EnumAddressee.TRADER.toString().toLowerCase(Locale.ENGLISH)), new MailAddress(this.owner)); + confirm.setText(ordersToFill + " order(s) from " + letter.getSender().getIdentifier() + " were filled."); + confirm.addStamps(ForestryItem.stamps.getItemStack(1, EnumPostage.P_1.ordinal())); + nbttagcompound = new NBTTagCompound(); + confirm.writeToNBT(nbttagcompound); + ItemStack confirmstack = ForestryItem.letters.getItemStack(1, ItemLetter.encodeMeta(1, ItemLetter.getType(confirm))); + confirmstack.setTagCompound(nbttagcompound); + PostManager.postRegistry.getPostOffice(world).lodgeLetter(world, confirmstack, doLodge); + } + + return EnumDeliveryState.OK; + } + + /* TRADE LOGIC */ + private int countFillableOrders(int max, ItemStack tradegood) { + + if (tradegood == null) + return 0; + + // How many orders are fillable? + int itemCount = 0; + for (ItemStack stack : inventory.getStacks(SLOT_INPUTBUF_1, SLOT_BUFFER_COUNT)) { + if (stack != null && stack.isItemEqual(tradegood) && ItemStack.areItemStackTagsEqual(stack, tradegood)) + itemCount += stack.stackSize; + } + + return (int) Math.floor(itemCount / tradegood.stackSize); + } + + private int countStorablePayment(int max, ItemStack[] exchange) { + + InventoryAdapter test = inventory.copy(); + int count = 0; + + for (int i = 0; i < max; i++) { + if (test.tryAddStacksCopy(exchange, true)) + count++; + else + break; + } + + return count; + } + + private void removeTradegood(int filled) { + + for (int j = 0; j < filled; j++) { + int toRemove = inventory.getStackInSlot(SLOT_TRADEGOOD).stackSize; + for (int i = SLOT_INPUTBUF_1; i < SLOT_INPUTBUF_1 + SLOT_BUFFER_COUNT; i++) { + ItemStack buffer = inventory.getStackInSlot(i); + if (buffer == null) + continue; + + if (!buffer.isItemEqual(inventory.getStackInSlot(SLOT_TRADEGOOD))) + continue; + + if (!ItemStack.areItemStackTagsEqual(buffer, inventory.getStackInSlot(SLOT_TRADEGOOD))) + continue; + + ItemStack decrease = inventory.decrStackSize(i, toRemove); + toRemove -= decrease.stackSize; + + if (toRemove <= 0) + break; + } + } + } + + // Checks if at least one scrap of paper is available + private boolean hasPaper() { + for (ItemStack stack : inventory.getStacks(SLOT_LETTERS_1, SLOT_LETTERS_COUNT)) { + if (stack != null && stack.stackSize > 0) + return true; + } + + return false; + } + + // Removes a single paper from the inventory + private void removePaper() { + for (int i = SLOT_LETTERS_1; i < SLOT_LETTERS_1 + SLOT_LETTERS_COUNT; i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack != null && stack.getItem() == Items.paper && stack.stackSize > 0) { + inventory.decrStackSize(i, 1); + break; + } + } + } + + private boolean canPayPostage(int postage) { + + int posted = 0; + for (ItemStack stamp : inventory.getStacks(SLOT_STAMPS_1, SLOT_STAMPS_COUNT)) { + if (stamp == null) + continue; + if (!(stamp.getItem() instanceof IStamps)) + continue; + + posted += ((IStamps) stamp.getItem()).getPostage(stamp).getValue() * stamp.stackSize; + if (posted >= postage) + return true; + } + + return false; + } + + private int[] getPostage(int postage, boolean virtual) { + int[] stamps = new int[EnumPostage.values().length]; + + for (int i = EnumPostage.values().length - 1; i > 0; i--) { + if (postage <= 0) + break; + + EnumPostage postValue = EnumPostage.values()[i]; + + if (postValue.getValue() > postage) + continue; + + int num = 99; + if (!virtual) + num = getNumStamps(postValue); + int max = (int) Math.floor(postage / postValue.getValue()); + if (max < num) + num = max; + + stamps[i] = num; + postage -= num * postValue.getValue(); + + } + + return stamps; + } + + private int getNumStamps(EnumPostage postage) { + int count = 0; + for (ItemStack stamp : inventory.getStacks(SLOT_STAMPS_1, SLOT_STAMPS_COUNT)) { + if (stamp == null) + continue; + if (!(stamp.getItem() instanceof IStamps)) + continue; + + if (((IStamps) stamp.getItem()).getPostage(stamp) == postage) + count += stamp.stackSize; + + } + + return count; + } + + private void removeStamps(int[] stampCount) { + for (int i = 1; i < stampCount.length; i++) { + + if (stampCount[i] <= 0) + continue; + + for (int j = SLOT_STAMPS_1; j < SLOT_STAMPS_1 + SLOT_STAMPS_COUNT; j++) { + if (stampCount[i] <= 0) + continue; + + ItemStack stamp = inventory.getStackInSlot(j); + if (stamp == null) + continue; + if (!(stamp.getItem() instanceof IStamps)) + continue; + + if (((IStamps) stamp.getItem()).getPostage(stamp) == EnumPostage.values()[i]) { + ItemStack decrease = inventory.decrStackSize(j, stampCount[i]); + stampCount[i] -= decrease.stackSize; + } + + } + } + } + + private ItemStack[] getSurplusAttachments(int filled, ItemStack[] attachments) { + ArrayList surplus = new ArrayList(); + + // Get a copy of the attachments to play with + ItemStack[] pool = new ItemStack[attachments.length]; + for (int i = 0; i < attachments.length; i++) { + if (attachments[i] != null) + pool[i] = attachments[i].copy(); + } + + // Remove stuff until we are only left with the remants + for (int i = 0; i < filled; i++) { + ItemStack[] condensedRequired = StackUtils.condenseStacks(inventory.getStacks(SLOT_EXCHANGE_1, SLOT_EXCHANGE_COUNT)); + for (ItemStack req : condensedRequired) { + for (int j = 0; j < pool.length; j++) { + ItemStack pol = pool[j]; + if (pol == null) + continue; + if (!pol.isItemEqual(req)) + continue; + + if (req.stackSize >= pol.stackSize) { + req.stackSize -= pol.stackSize; + pool[j] = null; + } else { + pol.stackSize -= req.stackSize; + req.stackSize = 0; + } + } + } + } + + for (ItemStack stack : pool) { + if (stack != null) + surplus.add(stack); + } + + return surplus.toArray(new ItemStack[0]); + } + + /* IINVENTORY */ + @Override + public void markDirty() { + this.markDirty(); + inventory.markDirty(); + } + + @Override + public void setInventorySlotContents(int var1, ItemStack var2) { + this.markDirty(); + inventory.setInventorySlotContents(var1, var2); + } + + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int var1) { + return inventory.getStackInSlot(var1); + } + + @Override + public ItemStack decrStackSize(int var1, int var2) { + return inventory.decrStackSize(var1, var2); + } + + @Override + public ItemStack getStackInSlotOnClosing(int var1) { + return inventory.getStackInSlotOnClosing(var1); + } + + @Override + public String getInventoryName() { + return inventory.getInventoryName(); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer var1) { + return inventory.isUseableByPlayer(var1); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public boolean isItemValidForSlot(int i, ItemStack itemstack) { + return true; + } +} diff --git a/forestry_common/mail/forestry/mail/gadgets/MachineMailbox.java b/forestry_common/mail/forestry/mail/gadgets/MachineMailbox.java new file mode 100755 index 000000000..632bd6e02 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gadgets/MachineMailbox.java @@ -0,0 +1,275 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gadgets; + +import java.util.LinkedList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentTranslation; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.core.ForestryAPI; +import forestry.api.mail.ILetter; +import forestry.api.mail.IPostalState; +import forestry.api.mail.PostManager; +import forestry.core.config.Config; +import forestry.core.gadgets.TileBase; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.InventoryAdapter; +import forestry.mail.EnumDeliveryState; +import forestry.mail.IMailContainer; +import forestry.mail.POBox; +import forestry.mail.PostRegistry; +import forestry.plugins.PluginMail; + +public class MachineMailbox extends TileBase implements IMailContainer, ISpecialInventory, ISidedInventory { + + private boolean isLinked = false; + + public MachineMailbox() { + setHints(Config.hints.get("mailbox")); + } + + @Override + public String getInventoryName() { + return "mail.0"; + } + + /* GUI */ + @Override + public void openGui(EntityPlayer player, TileBase tile) { + + if (!Proxies.common.isSimulating(worldObj)) + return; + + ItemStack held = player.getCurrentEquippedItem(); + + // Handle letter sending + if (PostManager.postRegistry.isLetter(held)) { + IPostalState result = this.tryDispatchLetter(held, true); + if (!result.isOk()) + player.addChatMessage(new ChatComponentTranslation("chat.mail." + result.getIdentifier())); + else + held.stackSize--; + } else + player.openGui(ForestryAPI.instance, GuiId.MailboxGUI.ordinal(), player.worldObj, xCoord, yCoord, zCoord); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + nbttagcompound.setBoolean("LNK", this.isLinked); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + this.isLinked = nbttagcompound.getBoolean("LNK"); + } + + /* UPDATING */ + @Override + public void updateServerSide() { + if (!isLinked) { + getOrCreateMailInventory(); + isLinked = true; + } + } + + /* MAIL HANDLING */ + public IInventory getOrCreateMailInventory() { + + // Handle client side + if (!Proxies.common.isSimulating(worldObj)) + return new InventoryAdapter(POBox.SLOT_SIZE, "Letters"); + + if (getOwnerName() == null || getOwnerName().isEmpty()) + return new InventoryAdapter(POBox.SLOT_SIZE, "Letters"); + + return PostRegistry.getOrCreatePOBox(worldObj, getOwnerName()); + } + + private IPostalState tryDispatchLetter(ItemStack letterstack, boolean dispatchLetter) { + ILetter letter = PostManager.postRegistry.getLetter(letterstack); + IPostalState result; + + if (letter != null) + result = PostManager.postRegistry.getPostOffice(worldObj).lodgeLetter(worldObj, letterstack, dispatchLetter); + else + result = EnumDeliveryState.NOT_MAILABLE; + + return result; + } + + /* IMAILCONTAINER */ + @Override + public boolean hasMail() { + + IInventory mailInventory = getOrCreateMailInventory(); + for (int i = 0; i < mailInventory.getSizeInventory(); i++) + if (mailInventory.getStackInSlot(i) != null) + return true; + + return false; + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(PluginMail.triggerHasMail); + return res; + } + + /* ISIDEDINVENTORY */ + private static int[] slotIndices; + + public int[] getSizeInventorySide(int side) { + IInventory inventory = getOrCreateMailInventory(); + if(slotIndices == null) { + slotIndices = new int[inventory.getSizeInventory()]; + for(int i = 0; i < inventory.getSizeInventory(); i++) + slotIndices[i] = i; + } + return slotIndices; + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + if (!PostManager.postRegistry.isLetter(stack)) + return 0; + + IPostalState result = tryDispatchLetter(stack, doAdd); + + if (!result.isOk()) + return 0; + else + return 1; + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + + ItemStack product = null; + IInventory mailInventory = getOrCreateMailInventory(); + + for (int i = 0; i < mailInventory.getSizeInventory(); i++) { + ItemStack slotStack = mailInventory.getStackInSlot(i); + if (slotStack == null) + continue; + + product = slotStack; + if (doRemove) + mailInventory.setInventorySlotContents(i, null); + break; + } + + if (product != null) + return new ItemStack[] { product }; + else + return new ItemStack[0]; + } + + @Override + public int getSizeInventory() { + return 0; + } + + @Override + public ItemStack getStackInSlot(int var1) { + return null; + } + + @Override + public ItemStack decrStackSize(int var1, int var2) { + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int var1) { + return null; + } + + @Override + public void setInventorySlotContents(int var1, ItemStack var2) { + } + + @Override + public int getInventoryStackLimit() { + return 0; + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } +} diff --git a/forestry_common/mail/forestry/mail/gadgets/MachinePhilatelist.java b/forestry_common/mail/forestry/mail/gadgets/MachinePhilatelist.java new file mode 100755 index 000000000..e83413db3 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gadgets/MachinePhilatelist.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gadgets; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import forestry.api.core.ForestryAPI; +import forestry.api.mail.IStamps; +import forestry.api.mail.PostManager; +import forestry.core.gadgets.TileBase; +import forestry.core.network.GuiId; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.StackUtils; + +public class MachinePhilatelist extends TileBase implements IInventory { + + // / CONSTANTS + public static final short SLOT_FILTER = 0; + public static final short SLOT_BUFFER_1 = 1; + public static final short SLOT_BUFFER_COUNT = 27; + + private final InventoryAdapter inventory = new InventoryAdapter(28, "INV"); + + public MachinePhilatelist() { + } + + @Override + public String getInventoryName() { + return "mail.2"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + player.openGui(ForestryAPI.instance, GuiId.PhilatelistGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + inventory.writeToNBT(nbttagcompound); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + inventory.readFromNBT(nbttagcompound); + } + + // / UPDATING + @Override + public void updateServerSide() { + if (worldObj.getTotalWorldTime() % 20 * 10 != 0) + return; + + ItemStack stamp = null; + + if (inventory.getStackInSlot(SLOT_FILTER) == null) + stamp = PostManager.postRegistry.getPostOffice(worldObj).getAnyStamp(1); + else { + ItemStack filter = inventory.getStackInSlot(SLOT_FILTER); + if (filter.getItem() instanceof IStamps) + stamp = PostManager.postRegistry.getPostOffice(worldObj).getAnyStamp(((IStamps) filter.getItem()).getPostage(filter), 1); + } + + if (stamp == null) + return; + + // Store it. + StackUtils.stowInInventory(stamp, inventory, true, SLOT_BUFFER_1, SLOT_BUFFER_COUNT); + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + return inventory.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return inventory.getStackInSlot(i); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return inventory.decrStackSize(i, j); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + inventory.setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return inventory.getStackInSlotOnClosing(slot); + } + + @Override + public void markDirty() { + inventory.markDirty(); + } + + @Override + public int getInventoryStackLimit() { + return inventory.getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + +} diff --git a/forestry_common/mail/forestry/mail/gadgets/MachineTrader.java b/forestry_common/mail/forestry/mail/gadgets/MachineTrader.java new file mode 100755 index 000000000..8b91314ce --- /dev/null +++ b/forestry_common/mail/forestry/mail/gadgets/MachineTrader.java @@ -0,0 +1,402 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gadgets; + +import java.util.LinkedList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITrigger; +import buildcraft.api.inventory.ISpecialInventory; + +import forestry.api.core.ForestryAPI; +import forestry.api.mail.IStamps; +import forestry.api.mail.PostManager; +import forestry.core.EnumErrorCode; +import forestry.core.gadgets.TileBase; +import forestry.core.network.EntityNetData; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.InventoryAdapter; +import forestry.core.utils.StackUtils; +import forestry.mail.TradeStation; +import forestry.plugins.PluginMail; + +public class MachineTrader extends TileBase implements ISpecialInventory, ISidedInventory { + + @EntityNetData + public String moniker = ""; + + @Override + public String getInventoryName() { + return "mail.1"; + } + + @Override + public void openGui(EntityPlayer player, TileBase tile) { + if (isLinked()) + player.openGui(ForestryAPI.instance, GuiId.TraderGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + else + player.openGui(ForestryAPI.instance, GuiId.TraderNameGUI.ordinal(), worldObj, xCoord, yCoord, zCoord); + } + + @Override + public void onRemoval() { + if (isLinked()) + PostManager.postRegistry.deleteTradeStation(worldObj, moniker); + } + + /* SAVING & LOADING */ + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + + if (moniker != null) + nbttagcompound.setString("MNK", moniker); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + + if (nbttagcompound.hasKey("MNK")) + this.moniker = nbttagcompound.getString("MNK"); + } + + /* UPDATING */ + @Override + public void updateServerSide() { + + if (worldObj.getTotalWorldTime() % 40 * 10 != 0) + return; + + setErrorState(EnumErrorCode.OK); + + if (!hasPaperMin(0.0f) || !hasInputBufMin(0.0f)) { + setErrorState(EnumErrorCode.NORESOURCE); + return; + } + if (!hasPostageMin(2)) { + setErrorState(EnumErrorCode.NOSTAMPS); + return; + } + + } + + /* STATE INFORMATION */ + + public boolean isLinked() { + return getMoniker() != null && !getMoniker().isEmpty(); + } + + private float percentOccupied(int startSlot, int countSlots) { + int max = 0; + int avail = 0; + + IInventory tradeInventory = this.getOrCreateTradeInventory(); + for (int i = startSlot; i < startSlot + countSlots; i++) { + max += 64; + if (tradeInventory.getStackInSlot(i) == null) + continue; + avail += tradeInventory.getStackInSlot(i).stackSize; + } + + return ((float) avail / (float) max); + } + + public boolean hasPaperMin(float percentage) { + return percentOccupied(TradeStation.SLOT_LETTERS_1, TradeStation.SLOT_LETTERS_COUNT) > percentage; + } + + public boolean hasInputBufMin(float percentage) { + return percentOccupied(TradeStation.SLOT_INPUTBUF_1, TradeStation.SLOT_BUFFER_COUNT) > percentage; + } + + public boolean hasOutputBufMin(float percentage) { + return percentOccupied(TradeStation.SLOT_OUTPUTBUF_1, TradeStation.SLOT_BUFFER_COUNT) > percentage; + } + + public boolean hasPostageMin(int postage) { + + int posted = 0; + + IInventory tradeInventory = this.getOrCreateTradeInventory(); + for (int i = TradeStation.SLOT_STAMPS_1; i < TradeStation.SLOT_STAMPS_1 + TradeStation.SLOT_STAMPS_COUNT; i++) { + ItemStack stamp = tradeInventory.getStackInSlot(i); + if (stamp == null) + continue; + if (!(stamp.getItem() instanceof IStamps)) + continue; + + posted += ((IStamps) stamp.getItem()).getPostage(stamp).getValue() * stamp.stackSize; + } + + return posted >= postage; + } + + /* MONIKER */ + public String getMoniker() { + return this.moniker; + } + + public void setMoniker(String moniker) { + + if (Proxies.common.isSimulating(worldObj)) { + if (!PostManager.postRegistry.isValidTradeMoniker(worldObj, moniker)) { + setErrorState(EnumErrorCode.NOTALPHANUMERIC); + return; + } + + if (!PostManager.postRegistry.isAvailableTradeMoniker(worldObj, moniker)) { + setErrorState(EnumErrorCode.NOTUNIQUE); + return; + } + + this.moniker = moniker; + PostManager.postRegistry.getOrCreateTradeStation(worldObj, getOwnerName(), this.moniker); + setErrorState(EnumErrorCode.OK); + sendNetworkUpdate(); + } else + this.moniker = moniker; + } + + /* TRADING */ + public IInventory getOrCreateTradeInventory() { + + // Handle client side + if (!Proxies.common.isSimulating(worldObj)) + return new InventoryAdapter(TradeStation.SLOT_SIZE, "INV"); + + if (this.moniker == null || this.moniker.isEmpty()) + return new InventoryAdapter(TradeStation.SLOT_SIZE, "INV"); + + return PostManager.postRegistry.getOrCreateTradeStation(worldObj, getOwnerName(), this.moniker); + } + + /* ISPECIALINVENTORY */ + @Override + public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { + + if (!this.isLinked()) + return 0; + + IInventory inventory = getOrCreateTradeInventory(); + ItemStack tradegood = inventory.getStackInSlot(TradeStation.SLOT_TRADEGOOD); + + // Special handling for paper + if (stack.getItem() == Items.paper) + // Handle paper as resource if its not the trade good or pumped in from above or below + if ((tradegood != null && tradegood.getItem() != Items.paper) || from == ForgeDirection.DOWN || from == ForgeDirection.UP) + return StackUtils.addToInventory(stack, inventory, doAdd, TradeStation.SLOT_LETTERS_1, TradeStation.SLOT_LETTERS_COUNT); + + // Special handling for stamps + if (stack.getItem() instanceof IStamps) + // Handle stamps as resource if its not the trade good or pumped in from above or below + if ((tradegood != null && !(tradegood.getItem() instanceof IStamps)) || from == ForgeDirection.DOWN || from == ForgeDirection.UP) + return StackUtils.addToInventory(stack, inventory, doAdd, TradeStation.SLOT_STAMPS_1, TradeStation.SLOT_STAMPS_COUNT); + + // Everything else + if (tradegood == null) + return 0; + + if (!tradegood.isItemEqual(stack)) + return 0; + + return StackUtils.addToInventory(stack, inventory, doAdd, TradeStation.SLOT_INPUTBUF_1, TradeStation.SLOT_BUFFER_COUNT); + } + + @Override + public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { + + if (!this.isLinked()) + return new ItemStack[0]; + + ItemStack product = null; + IInventory inventory = getOrCreateTradeInventory(); + for (int i = TradeStation.SLOT_OUTPUTBUF_1; i < TradeStation.SLOT_OUTPUTBUF_1 + TradeStation.SLOT_BUFFER_COUNT; i++) { + ItemStack stackSlot = inventory.getStackInSlot(i); + if (stackSlot == null) + continue; + if (stackSlot.stackSize <= 0) + continue; + + product = inventory.decrStackSize(i, 1); + break; + } + + if (product != null) + return new ItemStack[] { product }; + else + return new ItemStack[0]; + } + + /* ISIDEDINVENTORY */ + private static int[] slotIndices; + + public int[] getSizeInventorySide(int side) { + IInventory inventory = getOrCreateTradeInventory(); + if(slotIndices == null) { + slotIndices = new int[inventory.getSizeInventory()]; + for(int i = 0; i < inventory.getSizeInventory(); i++) + slotIndices[i] = i; + } + return slotIndices; + } + + @Override + protected boolean canTakeStackFromSide(int slotIndex, ItemStack itemstack, int side) { + + if(!super.canTakeStackFromSide(slotIndex, itemstack, side)) + return false; + + if(slotIndex >= TradeStation.SLOT_OUTPUTBUF_1 && slotIndex < TradeStation.SLOT_OUTPUTBUF_1 + TradeStation.SLOT_BUFFER_COUNT) + return true; + + return false; + } + + @Override + protected boolean canPutStackFromSide(int slotIndex, ItemStack itemstack, int side) { + if(!super.canPutStackFromSide(slotIndex, itemstack, side)) + return false; + + if (slotIndex >= TradeStation.SLOT_LETTERS_1 && slotIndex < TradeStation.SLOT_LETTERS_1 + TradeStation.SLOT_LETTERS_COUNT + && itemstack.getItem() == Items.paper) { + return true; + } + + if (slotIndex >= TradeStation.SLOT_STAMPS_1 && slotIndex < TradeStation.SLOT_STAMPS_COUNT) { + return itemstack.getItem() instanceof IStamps; + } + + if (slotIndex >= TradeStation.SLOT_INPUTBUF_1 && slotIndex < TradeStation.SLOT_BUFFER_COUNT) { + IInventory inventory = getOrCreateTradeInventory(); + ItemStack tradegood = inventory.getStackInSlot(TradeStation.SLOT_TRADEGOOD); + if(tradegood == null) + return false; + return StackUtils.isIdenticalItem(tradegood, itemstack); + } + + return false; + } + + /* IINVENTORY */ + @Override + public int getSizeInventory() { + return getOrCreateTradeInventory().getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int i) { + return getOrCreateTradeInventory().getStackInSlot(i); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return getOrCreateTradeInventory().decrStackSize(i, j); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + getOrCreateTradeInventory().setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return getOrCreateTradeInventory().getStackInSlotOnClosing(slot); + } + + @Override + public void markDirty() { + getOrCreateTradeInventory().markDirty(); + } + + @Override + public int getInventoryStackLimit() { + return getOrCreateTradeInventory().getInventoryStackLimit(); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return super.isUseableByPlayer(player); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean hasCustomInventoryName() { + return super.hasCustomInventoryName(); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { + return super.isItemValidForSlot(slotIndex, itemstack); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canInsertItem(int i, ItemStack itemstack, int j) { + return super.canInsertItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public boolean canExtractItem(int i, ItemStack itemstack, int j) { + return super.canExtractItem(i, itemstack, j); + } + + /** + * TODO: just a specialsource workaround + */ + @Override + public int[] getAccessibleSlotsFromSide(int side) { + return super.getAccessibleSlotsFromSide(side); + } + + /* ITRIGGERPROVIDER */ + @Override + public LinkedList getCustomTriggers() { + LinkedList res = new LinkedList(); + res.add(PluginMail.lowPaper25); + res.add(PluginMail.lowPaper10); + res.add(PluginMail.lowInput25); + res.add(PluginMail.lowInput10); + res.add(PluginMail.lowPostage40); + res.add(PluginMail.lowPostage20); + res.add(PluginMail.highBuffer90); + res.add(PluginMail.highBuffer75); + return res; + } + +} diff --git a/forestry_common/mail/forestry/mail/gui/ContainerCatalogue.java b/forestry_common/mail/forestry/mail/gui/ContainerCatalogue.java new file mode 100755 index 000000000..09e9a1854 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/ContainerCatalogue.java @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import java.util.EnumSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Set; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ICrafting; + +import forestry.api.mail.ITradeStation; +import forestry.api.mail.PostManager; +import forestry.api.mail.TradeStationInfo; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.IGuiSelectable; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.mail.EnumStationState; +import forestry.mail.network.PacketTradeInfo; + +public class ContainerCatalogue extends ContainerForestry implements IGuiSelectable { + + private final EntityPlayer player; + private final LinkedHashMap stations; + private TradeStationInfo currentTrade = null; + private Iterator iterator = null; + + private int maxItPos = 0; + private int currentItPos = 0; + + private boolean needsSynch = true; + private int currentFilter = 1; + + private static final String[] FILTER_NAMES = new String[] { "all", "online", "offline" }; + @SuppressWarnings("unchecked") + private static final Set[] FILTERS = new EnumSet[] { + EnumSet.noneOf(EnumStationState.class), + EnumSet.of(EnumStationState.OK), + EnumSet.of(EnumStationState.INSUFFICIENT_OFFER, EnumStationState.INSUFFICIENT_TRADE_GOOD, EnumStationState.INSUFFICIENT_BUFFER, EnumStationState.INSUFFICIENT_PAPER, EnumStationState.INSUFFICIENT_STAMPS) + }; + + public ContainerCatalogue(EntityPlayer player) { + super(player.inventory); + this.player = player; + + // Filter out any trade stations which do not actually offer anything. + stations = new LinkedHashMap(); + rebuildStationsList(); + } + + public int getMaxCount() { return maxItPos; } + public int getCurrentPos() { return currentItPos; } + + public String getFilterIdent() { return FILTER_NAMES[currentFilter]; } + + private void rebuildStationsList() { + stations.clear(); + for(ITradeStation station : PostManager.postRegistry.getPostOffice(player.worldObj).getActiveTradeStations(player.worldObj).values()) { + TradeStationInfo info = station.getTradeInfo(); + if(info.tradegood == null) + continue; + + if(!FILTERS[currentFilter].isEmpty()) { + if(!FILTERS[currentFilter].contains(info.state)) + continue; + } + + stations.put(station.getMoniker(), station); + } + maxItPos = stations.size(); + resetIteration(); + + } + + private void resetIteration() { + if(!stations.isEmpty()) { + iterator = stations.values().iterator(); + updateTradeInfo(iterator.next()); + } else + updateTradeInfo(null); + + currentItPos = 1; + } + + public void advanceIteration() { + + if(!Proxies.common.isSimulating(player.worldObj)) { + sendSelection(true); + return; + } + + if(stations.isEmpty()) + return; + + if(iterator.hasNext()) { + currentItPos++; + updateTradeInfo(iterator.next()); + } else + resetIteration(); + } + + public void regressIteration() { + + if(!Proxies.common.isSimulating(player.worldObj)) { + sendSelection(false); + return; + } + + if(stations.isEmpty()) + return; + + iterator = stations.values().iterator(); + ITradeStation previous = null; + currentItPos = 0; + + while(iterator.hasNext()) { + ITradeStation current = iterator.next(); + if(!current.getMoniker().equals(currentTrade.moniker)) { + currentItPos++; + previous = current; + continue; + } + + if(previous == null) { + Iterator it = stations.values().iterator(); + currentItPos = stations.size(); + while(it.hasNext()) + previous = it.next(); + + } + updateTradeInfo(previous); + break; + } + } + + public void cycleFilter() { + if(!Proxies.common.isSimulating(player.worldObj)) { + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = 2; + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + return; + } + + if(currentFilter < FILTERS.length -1) + currentFilter++; + else + currentFilter = 0; + + rebuildStationsList(); + } + + private void sendSelection(boolean advance) { + PacketPayload payload = new PacketPayload(1, 0, 0); + payload.intPayload[0] = advance ? 0 : 1; + PacketUpdate packet = new PacketUpdate(PacketIds.GUI_SELECTION_CHANGE, payload); + Proxies.net.sendToServer(packet); + } + + /* Managing Trade info */ + public void updateTradeInfo(ITradeStation station) { + // Updating is done by the server. + if (!Proxies.common.isSimulating(player.worldObj)) + return; + + if(station != null) + setTradeInfo(station.getTradeInfo()); + else + setTradeInfo(null); + needsSynch = true; + } + + public void handleTradeInfoUpdate(PacketTradeInfo packet) { + setTradeInfo(packet.tradeInfo); + } + + public TradeStationInfo getTradeInfo() { + return currentTrade; + } + + private void setTradeInfo(TradeStationInfo info) { + currentTrade = info; + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + + if(needsSynch) { + for (int i = 0; i < crafters.size(); i++) { + ICrafting crafter = (ICrafting)crafters.get(i); + crafter.sendProgressBarUpdate(this, 0, currentItPos); + crafter.sendProgressBarUpdate(this, 1, maxItPos); + crafter.sendProgressBarUpdate(this, 2, currentFilter); + } + + Proxies.net.sendToPlayer(new PacketTradeInfo(PacketIds.TRADING_INFO, currentTrade), player); + needsSynch = false; + } + } + + @Override + public void updateProgressBar(int i, int j) { + switch(i) { + case 0: + currentItPos = j; + break; + case 1: + maxItPos = j; + break; + case 2: + currentFilter = j; + break; + } + } + + @Override + public void handleSelectionChange(EntityPlayer player, PacketUpdate packet) { + + if (packet.payload.intPayload[0] == 0) { + advanceIteration(); + } else if(packet.payload.intPayload[0] == 1) + regressIteration(); + else if(packet.payload.intPayload[0] == 2) + cycleFilter(); + + needsSynch = true; + } + + @Override + public void setSelection(PacketUpdate packet) { + } + +} diff --git a/forestry_common/mail/forestry/mail/gui/ContainerLetter.java b/forestry_common/mail/forestry/mail/gui/ContainerLetter.java new file mode 100755 index 000000000..6e0db3e34 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/ContainerLetter.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import java.util.Iterator; +import java.util.Locale; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.mail.ILetter; +import forestry.api.mail.IPostalCarrier; +import forestry.api.mail.ITradeStation; +import forestry.api.mail.MailAddress; +import forestry.api.mail.PostManager; +import forestry.api.mail.TradeStationInfo; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.mail.EnumAddressee; +import forestry.mail.Letter; +import forestry.mail.items.ItemLetter; +import forestry.mail.items.ItemLetter.LetterInventory; +import forestry.mail.items.ItemStamps; +import forestry.mail.network.PacketTradeInfo; + +public class ContainerLetter extends ContainerItemInventory { + + private final LetterInventory letterInventory; + private String carrier = EnumAddressee.PLAYER.toString().toLowerCase(Locale.ENGLISH); + private TradeStationInfo tradeInfo = null; + + public ContainerLetter(EntityPlayer player, LetterInventory inventory) { + super(inventory, player); + + letterInventory = inventory; + + // Rip open delivered mails + if (Proxies.common.isSimulating(player.worldObj) && letterInventory.getLetter().isProcessed() && inventory.parent != null + && ItemLetter.getState(inventory.parent.getItemDamage()) < 2) + inventory.parent.setItemDamage(ItemLetter.encodeMeta(2, ItemLetter.getSize(inventory.parent.getItemDamage()))); + + // Init slots + Object[] validStamps = new Object[] { ItemStamps.class }; + if (letterInventory.getLetter().isProcessed()) + validStamps = new Object[] {}; + + // Stamps + for (int i = 0; i < 4; i++) + addSlot(new SlotCustom(inventory, Letter.SLOT_POSTAGE_1 + i, 150, 14 + i * 19, validStamps).setStackLimit(1)); + + // Attachments + if (!letterInventory.getLetter().isProcessed()) + for (int i = 0; i < 2; i++) + for (int j = 0; j < 9; j++) + addSlot(new SlotCustom(inventory, Letter.SLOT_ATTACHMENT_1 + j + i * 9, 17 + j * 18, 98 + i * 18, true, new Object[] { ItemLetter.class })); + else + for (int i = 0; i < 2; i++) + for (int j = 0; j < 9; j++) + addSlot(new SlotClosed(inventory, Letter.SLOT_ATTACHMENT_1 + j + i * 9, 17 + j * 18, 98 + i * 18)); + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSecuredSlot(player.inventory, j + i * 9 + 9, 17 + j * 18, 145 + i * 18); + // Player hotbar + for (int i = 0; i < 9; i++) + addSecuredSlot(player.inventory, i, 17 + i * 18, 203); + + // Set recipient type + if (letterInventory.getLetter() != null) + if (letterInventory.getLetter().getRecipients() != null) + if (letterInventory.getLetter().getRecipients().length > 0) + this.carrier = letterInventory.getLetter().getRecipients()[0].getType(); + } + + @Override + public void onContainerClosed(EntityPlayer entityplayer) { + + if (Proxies.common.isSimulating(entityplayer.worldObj)) { + ILetter letter = letterInventory.getLetter(); + if (!letter.isProcessed()) + letter.setSender(new MailAddress(entityplayer.getGameProfile().getId())); + } + + super.onContainerClosed(entityplayer); + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + return true; + } + + public ILetter getLetter() { + return letterInventory.getLetter(); + } + + public void setCarrierType(String type) { + this.carrier = type; + } + + public String getCarrierType() { + return this.carrier; + } + + public void advanceCarrierType() { + Iterator it = PostManager.postRegistry.getRegisteredCarriers().values().iterator(); + while(it.hasNext()) { + if(it.next().getUID().equals(carrier)) + break; + } + + IPostalCarrier postal = null; + if(it.hasNext()) + postal = it.next(); + else + postal = PostManager.postRegistry.getRegisteredCarriers().values().iterator().next(); + + setCarrierType(postal.getUID()); + } + + public void setRecipient(MailAddress address) { + getLetter().setRecipient(address); + carrier = address.getType(); + + // / Send to server + PacketPayload payload = new PacketPayload(0, 0, 2); + payload.stringPayload[0] = this.getRecipient().getIdentifier(); + payload.stringPayload[1] = this.carrier; + + PacketUpdate packet = new PacketUpdate(PacketIds.LETTER_RECIPIENT, payload); + Proxies.net.sendToServer(packet); + } + + public void handleSetRecipient(EntityPlayer player, PacketUpdate packet) { + MailAddress recipient = new MailAddress(packet.payload.stringPayload[0], packet.payload.stringPayload[1]); + getLetter().setRecipient(recipient); + // Update the trading info + updateTradeInfo(player.worldObj, recipient); + // Update trade info on client + Proxies.net.sendToPlayer(new PacketTradeInfo(PacketIds.TRADING_INFO, tradeInfo), player); + } + + public MailAddress getRecipient() { + if (getLetter().getRecipients().length > 0) + return getLetter().getRecipients()[0]; + else + return null; + } + + public String getText() { + return getLetter().getText(); + } + + public void setText(String text) { + getLetter().setText(text); + + // / Send to server + PacketPayload payload = new PacketPayload(0, 0, 1); + payload.stringPayload[0] = text; + + PacketUpdate packet = new PacketUpdate(PacketIds.LETTER_TEXT, payload); + Proxies.net.sendToServer(packet); + + } + + public void handleSetText(PacketUpdate packet) { + getLetter().setText(packet.payload.stringPayload[0]); + } + + /* Managing Trade info */ + public void updateTradeInfo(World world, MailAddress address) { + // Updating is done by the server. + if (!Proxies.common.isSimulating(world)) + return; + + if (!address.getType().equals(EnumAddressee.TRADER.toString().toLowerCase(Locale.ENGLISH))) + return; + + ITradeStation station = PostManager.postRegistry.getTradeStation(world, address.getIdentifier()); + if (station == null) + return; + + setTradeInfo(station.getTradeInfo()); + } + + public void handleTradeInfoUpdate(PacketTradeInfo packet) { + this.setTradeInfo(packet.tradeInfo); + } + + public TradeStationInfo getTradeInfo() { + return this.tradeInfo; + } + + private void setTradeInfo(TradeStationInfo info) { + this.tradeInfo = info; + } +} diff --git a/forestry_common/mail/forestry/mail/gui/ContainerMailbox.java b/forestry_common/mail/forestry/mail/gui/ContainerMailbox.java new file mode 100755 index 000000000..6c66a7c5c --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/ContainerMailbox.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.proxy.Proxies; +import forestry.mail.POBox; +import forestry.mail.gadgets.MachineMailbox; +import forestry.plugins.PluginMail; + +public class ContainerMailbox extends ContainerForestry { + + MachineMailbox mailbox; + POBox mailinventory; + + public ContainerMailbox(InventoryPlayer player, MachineMailbox tile) { + super(tile); + + // Mailbox contents + this.mailbox = tile; + + IInventory inv = mailbox.getOrCreateMailInventory(); + if (inv instanceof POBox) + mailinventory = (POBox) inv; + + for (int i = 0; i < 7; i++) + for (int j = 0; j < 12; j++) + addSlot(new SlotClosed(inv, j + i * 9, 8 + j * 18, 8 + i * 18)); + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSlot(new Slot(player, j + i * 9 + 9, 35 + j * 18, 145 + i * 18)); + // Player hotbar + for (int i = 0; i < 9; i++) + addSlot(new Slot(player, i, 35 + i * 18, 203)); + + } + + @Override + public ItemStack slotClick(int slotIndex, int button, int par3, EntityPlayer player) { + ItemStack stack = super.slotClick(slotIndex, button, par3, player); + + if (Proxies.common.isSimulating(player.worldObj) && mailinventory != null) + PluginMail.proxy.setPOBoxInfo(mailbox.getWorldObj(), mailbox.getOwnerName(), mailinventory.getPOBoxInfo()); + + return stack; + } +} diff --git a/forestry_common/mail/forestry/mail/gui/ContainerPhilatelist.java b/forestry_common/mail/forestry/mail/gui/ContainerPhilatelist.java new file mode 100755 index 000000000..7420a4234 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/ContainerPhilatelist.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotCustom; +import forestry.mail.gadgets.MachinePhilatelist; +import forestry.mail.items.ItemStamps; + +public class ContainerPhilatelist extends ContainerForestry { + + public ContainerPhilatelist(InventoryPlayer player, MachinePhilatelist tile) { + super(tile); + + // Filter + addSlot(new SlotCustom(tile, MachinePhilatelist.SLOT_FILTER, 80, 19, new Object[] { ItemStamps.class })); + + // Collected Stamps + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSlot(new SlotClosed(tile, j + i * 9 + MachinePhilatelist.SLOT_BUFFER_1, 8 + j * 18, 46 + i * 18)); + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSlot(new Slot(player, j + i * 9 + 9, 8 + j * 18, 111 + i * 18)); + // Player hotbar + for (int i = 0; i < 9; i++) + addSlot(new Slot(player, i, 8 + i * 18, 169)); + + } + +} diff --git a/forestry_common/mail/forestry/mail/gui/ContainerTradeName.java b/forestry_common/mail/forestry/mail/gui/ContainerTradeName.java new file mode 100755 index 000000000..f4703d375 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/ContainerTradeName.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.gui.ContainerForestry; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.core.utils.InventoryAdapter; +import forestry.mail.gadgets.MachineTrader; + +public class ContainerTradeName extends ContainerForestry { + + boolean isLinked; + MachineTrader machine; + + public ContainerTradeName(InventoryPlayer player, MachineTrader tile) { + super(new InventoryAdapter(0, "Empty")); + machine = tile; + isLinked = machine.isLinked(); + } + + public String getMoniker() { + return machine.getMoniker(); + } + + public void setMoniker(String moniker) { + + if (moniker == null || moniker.isEmpty()) + return; + + PacketPayload payload = new PacketPayload(0, 0, 1); + payload.stringPayload[0] = moniker; + + PacketUpdate packet = new PacketUpdate(PacketIds.TRADING_MONIKER_SET, payload); + Proxies.net.sendToServer(packet); + + machine.setMoniker(moniker); + } + + public void handleSetMoniker(PacketUpdate packet) { + machine.setMoniker(packet.payload.stringPayload[0]); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return true; + } + +} diff --git a/forestry_common/mail/forestry/mail/gui/ContainerTrader.java b/forestry_common/mail/forestry/mail/gui/ContainerTrader.java new file mode 100755 index 000000000..4b3ab69e6 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/ContainerTrader.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.init.Items; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.slots.SlotClosed; +import forestry.core.gui.slots.SlotCustom; +import forestry.mail.TradeStation; +import forestry.mail.gadgets.MachineTrader; +import forestry.mail.items.ItemStamps; + +public class ContainerTrader extends ContainerForestry { + + private final MachineTrader machine; + + public ContainerTrader(InventoryPlayer player, MachineTrader tile) { + super(tile); + + machine = tile; + IInventory inventory = machine.getOrCreateTradeInventory(); + + // Trade good + this.addSlot(new Slot(inventory, TradeStation.SLOT_TRADEGOOD, 78, 109)); + + // Exchange + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + addSlot(new Slot(inventory, TradeStation.SLOT_EXCHANGE_1 + j + i * 2, 69 + j * 18, 55 + i * 18)); + + // Stamps + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + addSlot(new SlotCustom(inventory, TradeStation.SLOT_STAMPS_1 + j + i * 2, 15 + j * 18, 37 + i * 18, new Object[] { ItemStamps.class })); + + // Letters + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + addSlot(new SlotCustom(inventory, TradeStation.SLOT_LETTERS_1 + j + i * 2, 15 + j * 18, 73 + i * 18, new Object[] { Items.paper })); + + // Input buffer + for (int i = 0; i < 6; i++) + for (int j = 0; j < 2; j++) + addSlot(new Slot(inventory, TradeStation.SLOT_INPUTBUF_1 + j + i * 2, 123 + j * 18, 19 + i * 18)); + + // Output buffer + for (int i = 0; i < 6; i++) + for (int j = 0; j < 2; j++) + addSlot(new SlotClosed(inventory, TradeStation.SLOT_OUTPUTBUF_1 + j + i * 2, 177 + j * 18, 19 + i * 18)); + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSlot(new Slot(player, j + i * 9 + 9, 33 + j * 18, 138 + i * 18)); + // Player hotbar + for (int i = 0; i < 9; i++) + addSlot(new Slot(player, i, 33 + i * 18, 196)); + + } + + public boolean isLinked() { + return getMoniker() != null && !getMoniker().isEmpty(); + } + + public String getMoniker() { + return machine.getMoniker(); + } + +} diff --git a/forestry_common/mail/forestry/mail/gui/GuiCatalogue.java b/forestry_common/mail/forestry/mail/gui/GuiCatalogue.java new file mode 100755 index 000000000..4a98632eb --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/GuiCatalogue.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import java.util.Locale; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; + +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; + +import forestry.api.mail.TradeStationInfo; +import forestry.core.config.SessionVars; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.GuiForestry; +import forestry.core.utils.StringUtil; +import forestry.mail.EnumAddressee; + +public class GuiCatalogue extends GuiForestry { + + GuiButton buttonTrade; + GuiButton buttonClose; + + GuiButton buttonFilter; + GuiButton buttonCopy; + + ContainerCatalogue container; + + public GuiCatalogue(EntityPlayer player) { + super(new ResourceLocation("textures/gui/book.png"), new ContainerCatalogue(player)); + this.xSize = 192; + this.ySize = 192; + container = (ContainerCatalogue)inventorySlots; + } + + @SuppressWarnings("unchecked") + @Override + public void initGui() { + super.initGui(); + + buttonList.clear(); + Keyboard.enableRepeatEvents(true); + + //buttonList.add(buttonTrade = new GuiButton(1, width / 2 - 100, 4 + ySize, 98, 20, StringUtil.localize("gui.mail.catalogue.trade"))); + //buttonList.add(buttonClose = new GuiButton(0, (width - 100) / 2, 4 + ySize, 98, 20, StringUtil.localize("gui.mail.catalogue.close"))); + + buttonList.add(new GuiButton(2, width / 2 + 44, guiTop + 150, 12, 20, ">")); + buttonList.add(new GuiButton(3, width / 2 - 58, guiTop + 150, 12, 20, "<")); + + buttonList.add(buttonFilter = new GuiButton(4, (width / 2) - 44, guiTop + 150, 42, 20, StringUtil.localize("gui.mail.filter.all"))); + + buttonList.add(buttonCopy = new GuiButton(5, width / 2, guiTop + 150, 42, 20, StringUtil.localize("gui.mail.address.copy"))); + } + + @Override + public void onGuiClosed() { + Keyboard.enableRepeatEvents(false); + super.onGuiClosed(); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + fontRendererObj.drawString(String.format("%s / %s", container.getCurrentPos(), container.getMaxCount()), guiLeft + xSize - 72, guiTop + 12, fontColor.get("gui.book")); + + if(container.getTradeInfo() != null) + drawTradePreview(guiLeft + 38, guiTop + 30); + else + drawNoTrade(guiLeft + 38, guiTop + 30); + + buttonFilter.displayString = StringUtil.localize("gui.mail.filter." + container.getFilterIdent()); + if(container.getTradeInfo() == null || !container.getTradeInfo().state.isOk()) + buttonCopy.enabled = false; + else + buttonCopy.enabled = true; + } + + private void drawNoTrade(int x, int y) { + fontRendererObj.drawSplitString(StringUtil.localize("gui.mail.notrades"), x, y + 18, 119, fontColor.get("gui.book")); + } + + private void drawTradePreview(int x, int y) { + + fontRendererObj.drawString("\u00A7l\u00A7n" + container.getTradeInfo().moniker, x, y, fontColor.get("gui.book")); + + TradeStationInfo info = container.getTradeInfo(); + fontRendererObj.drawString(String.format(StringUtil.localize("gui.mail.willtrade"), info.owner), x, y + 18, fontColor.get("gui.book")); + + itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.renderEngine, info.tradegood, x, y + 28); + itemRender.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, info.tradegood, x, y + 28); + + GL11.glDisable(GL11.GL_LIGHTING); + fontRendererObj.drawString(StringUtil.localize("gui.mail.tradefor"), x, y + 46, fontColor.get("gui.book")); + GL11.glEnable(GL11.GL_LIGHTING); + for (int i = 0; i < container.getTradeInfo().required.length; i++) { + GL11.glDisable(GL11.GL_LIGHTING); + itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.renderEngine, info.required[i], x + i * 18, y + 56); + itemRender.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, info.required[i], x + i * 18, y + 56); + GL11.glEnable(GL11.GL_LIGHTING); + } + + GL11.glDisable(GL11.GL_LIGHTING); + if(info.state.isOk()) + fontRendererObj.drawSplitString("\u00A72" + StringUtil.localize("chat.mail." + info.state.getIdentifier()), x, y + 82, 119, fontColor.get("gui.book")); + else + fontRendererObj.drawSplitString("\u00A74" + StringUtil.localize("chat.mail." + info.state.getIdentifier()), x, y + 82, 119, fontColor.get("gui.book")); + GL11.glEnable(GL11.GL_LIGHTING); + } + + @Override + protected void actionPerformed(GuiButton button) { + switch(button.id) { + case 0: + mc.displayGuiScreen((GuiScreen)null); + break; + case 2: + container.advanceIteration(); + break; + case 3: + container.regressIteration(); + break; + case 4: + container.cycleFilter(); + break; + case 5: + TradeStationInfo info = container.getTradeInfo(); + if(info != null) { + SessionVars.setStringVar("mail.letter.recipient", info.moniker); + SessionVars.setStringVar("mail.letter.addressee", EnumAddressee.TRADER.toString().toLowerCase(Locale.ENGLISH)); + } + mc.displayGuiScreen((GuiScreen)null); + break; + } + } +} diff --git a/forestry_common/mail/forestry/mail/gui/GuiLetter.java b/forestry_common/mail/forestry/mail/gui/GuiLetter.java new file mode 100755 index 000000000..a53a53f9a --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/GuiLetter.java @@ -0,0 +1,244 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import java.util.Locale; + +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.entity.player.EntityPlayer; + +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; + +import forestry.api.mail.IPostalCarrier; +import forestry.api.mail.MailAddress; +import forestry.api.mail.PostManager; +import forestry.core.config.Defaults; +import forestry.core.config.SessionVars; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.GuiForestry; +import forestry.core.gui.GuiTextBox; +import forestry.core.gui.widgets.Widget; +import forestry.core.proxy.Proxies; +import forestry.core.utils.StringUtil; +import forestry.mail.EnumAddressee; +import forestry.mail.items.ItemLetter.LetterInventory; + +public class GuiLetter extends GuiForestry { + + protected class AddresseeSlot extends Widget { + + public AddresseeSlot(int xPos, int yPos) { + super(widgetManager, xPos, yPos); + this.width = 26; + this.height = 15; + } + + @Override + public void draw(int startX, int startY) { + + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + //mc.renderEngine.bindTexture(Defaults.TEXTURE_PATH_GUI + "/letter.png"); + IPostalCarrier carrier = PostManager.postRegistry.getCarrier(container.getCarrierType()); + if(carrier != null) + drawTexturedModelRectFromIcon(startX + xPos, startY + yPos - 5, carrier.getIcon(), 26, 26); + + } + + @Override + protected String getLegacyTooltip(EntityPlayer player) { + return StringUtil.localize("gui.addressee." + container.getCarrierType().toLowerCase(Locale.ENGLISH)); + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + if(!isProcessedLetter) + container.advanceCarrierType(); + } + + } + + private final boolean isProcessedLetter; + private boolean checkedSessionVars; + + private GuiTextField address; + private GuiTextBox text; + + boolean addressFocus; + boolean textFocus; + + private final ContainerLetter container; + + public GuiLetter(EntityPlayer player, LetterInventory inventory) { + super(Defaults.TEXTURE_PATH_GUI + "/letter.png", new ContainerLetter(player, inventory), inventory); + this.xSize = 194; + this.ySize = 227; + + this.container = (ContainerLetter) inventorySlots; + this.isProcessedLetter = container.getLetter().isProcessed(); + this.widgetManager.add(new AddresseeSlot(16, 12)); + } + + @Override + public void initGui() { + super.initGui(); + + Keyboard.enableRepeatEvents(true); + + address = new GuiTextField(this.fontRendererObj, guiLeft + 46, guiTop + 13, 93, 13); + if (container.getRecipient() != null) { + address.setText(container.getRecipient().getIdentifier()); + this.setRecipient(container.getRecipient().getIdentifier(), container.getCarrierType()); + } + + text = new GuiTextBox(this.fontRendererObj, guiLeft + 17, guiTop + 31, 122, 57); + text.setMaxStringLength(128); + if (!container.getText().isEmpty()) + text.setText(container.getText()); + } + + @Override + protected void keyTyped(char eventCharacter, int eventKey) { + + // Set focus or enter text into address + if (this.address.isFocused()) { + if (eventKey == Keyboard.KEY_RETURN) + this.address.setFocused(false); + else + this.address.textboxKeyTyped(eventCharacter, eventKey); + return; + } + + if (this.text.isFocused()) { + if (eventKey == Keyboard.KEY_RETURN) { + if(Proxies.common.isShiftDown()) + text.setText(text.getText() + "\n"); + else + this.text.setFocused(false); + } else if(eventKey == Keyboard.KEY_DOWN) { + text.advanceLine(); + } else if(eventKey == Keyboard.KEY_UP) { + text.regressLine(); + } else if(text.moreLinesAllowed() || eventKey == Keyboard.KEY_DELETE || eventKey == Keyboard.KEY_BACK) + this.text.textboxKeyTyped(eventCharacter, eventKey); + return; + } + + super.keyTyped(eventCharacter, eventKey); + } + + @Override + protected void mouseClicked(int par1, int par2, int mouseButton) { + super.mouseClicked(par1, par2, mouseButton); + + this.address.mouseClicked(par1, par2, mouseButton); + this.text.mouseClicked(par1, par2, mouseButton); + + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + + if(!isProcessedLetter && !checkedSessionVars) { + checkedSessionVars = true; + setFromSessionVars(); + } + + // Check for focus changes + if (addressFocus != address.isFocused()) + setRecipient(this.address.getText(), container.getCarrierType()); + addressFocus = address.isFocused(); + if (textFocus != text.isFocused()) + setText(); + textFocus = text.isFocused(); + + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + if (this.isProcessedLetter) { + fontRendererObj.drawString(address.getText(), guiLeft + 49, guiTop + 16, fontColor.get("gui.mail.lettertext")); + fontRendererObj.drawSplitString(text.getText(), guiLeft + 20, guiTop + 34, 119, fontColor.get("gui.mail.lettertext")); + } else { + address.drawTextBox(); + if (container.getCarrierType().equals(EnumAddressee.TRADER.toString().toLowerCase(Locale.ENGLISH))) + drawTradePreview(guiLeft + 18, guiTop + 32); + else + text.drawTextBox(); + } + } + + private void drawTradePreview(int x, int y) { + + String infoString = null; + if (container.getTradeInfo() == null) + infoString = "gui.mail.notrader"; + else if (container.getTradeInfo().tradegood == null) + infoString = "gui.mail.nothingtotrade"; + else if (!container.getTradeInfo().state.isOk()) + infoString = "chat.mail." + container.getTradeInfo().state.getIdentifier(); + + if (infoString != null) { + fontRendererObj.drawSplitString(StringUtil.localize(infoString), x, y, 119, fontColor.get("gui.mail.lettertext")); + return; + } + + fontRendererObj.drawString(StringUtil.localize("gui.mail.pleasesend"), x, y, fontColor.get("gui.mail.lettertext")); + + itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.renderEngine, container.getTradeInfo().tradegood, x, y + 10); + itemRender.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, container.getTradeInfo().tradegood, x, y + 10); + + GL11.glDisable(GL11.GL_LIGHTING); + fontRendererObj.drawString(StringUtil.localize("gui.mail.foreveryattached"), x, y + 28, fontColor.get("gui.mail.lettertext")); + GL11.glEnable(GL11.GL_LIGHTING); + for (int i = 0; i < container.getTradeInfo().required.length; i++) { + GL11.glDisable(GL11.GL_LIGHTING); + itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.renderEngine, container.getTradeInfo().required[i], x + i * 18, y + 38); + itemRender.renderItemOverlayIntoGUI(fontRendererObj, mc.renderEngine, container.getTradeInfo().required[i], x + i * 18, y + 38); + GL11.glEnable(GL11.GL_LIGHTING); + } + + } + + @Override + public void onGuiClosed() { + setRecipient(this.address.getText(), container.getCarrierType()); + setText(); + Keyboard.enableRepeatEvents(false); + super.onGuiClosed(); + } + + private void setFromSessionVars() { + if(SessionVars.getStringVar("mail.letter.recipient") == null) + return; + + String recipient = SessionVars.getStringVar("mail.letter.recipient"); + String type = SessionVars.getStringVar("mail.letter.addressee"); + if(type != null) { + address.setText(recipient); + setRecipient(recipient, type); + } + + SessionVars.clearStringVar("mail.letter.recipient"); + SessionVars.clearStringVar("mail.letter.addressee"); + } + + private void setRecipient(String identifier, String type) { + if (this.isProcessedLetter) + return; + + MailAddress recipient = new MailAddress(identifier, type); + container.setRecipient(recipient); + container.updateTradeInfo(this.mc.theWorld, recipient); + } + + private void setText() { + if (this.isProcessedLetter) + return; + + container.setText(this.text.getText()); + } +} diff --git a/forestry_common/mail/forestry/mail/gui/GuiMailbox.java b/forestry_common/mail/forestry/mail/gui/GuiMailbox.java new file mode 100755 index 000000000..f4b1da043 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/GuiMailbox.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.mail.gadgets.MachineMailbox; + +public class GuiMailbox extends GuiForestry { + + public GuiMailbox(InventoryPlayer player, MachineMailbox tile) { + super(Defaults.TEXTURE_PATH_GUI + "/mailbox.png", new ContainerMailbox(player, tile), tile); + this.xSize = 230; + this.ySize = 227; + } +} diff --git a/forestry_common/mail/forestry/mail/gui/GuiMailboxInfo.java b/forestry_common/mail/forestry/mail/gui/GuiMailboxInfo.java new file mode 100755 index 000000000..d7eed1f6d --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/GuiMailboxInfo.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.util.ResourceLocation; + +import org.lwjgl.opengl.GL11; + +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.proxy.Proxies; +import forestry.core.utils.ForestryResource; +import forestry.mail.POBoxInfo; + +public class GuiMailboxInfo extends Gui { + + public static GuiMailboxInfo instance; + + private final FontRenderer fontRendererObj; + private POBoxInfo poInfo; + private final ResourceLocation textureAlert = new ForestryResource(Defaults.TEXTURE_PATH_GUI + "/mailalert.png"); + + public GuiMailboxInfo() { + fontRendererObj = Proxies.common.getClientInstance().fontRenderer; + } + + public void render(int x, int y) { + if (poInfo == null) + return; + if (Proxies.common.getRenderWorld() == null) + return; + if (!Config.mailAlertEnabled) + return; + if (!poInfo.hasMail()) + return; + + GL11.glEnable(3042); + GL11.glEnable(32826); + + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + Proxies.common.bindTexture(textureAlert); + + this.drawTexturedModalRect(x, y, 0, 0, 98, 17); + + fontRendererObj + .drawString(Integer.toString(poInfo.playerLetters), x + 27 + getCenteredOffset(Integer.toString(poInfo.playerLetters), 22), y + 5, 0xffffff); + fontRendererObj.drawString(Integer.toString(poInfo.tradeLetters), x + 75 + getCenteredOffset(Integer.toString(poInfo.tradeLetters), 22), y + 5, 0xffffff); + + GL11.glDisable(32826); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + } + + protected int getCenteredOffset(String string, int xWidth) { + return (xWidth - fontRendererObj.getStringWidth(string)) / 2; + } + + public void setPOBoxInfo(POBoxInfo info) { + boolean playJingle = false; + + if (info.hasMail()) + if (this.poInfo == null) + playJingle = true; + else if (this.poInfo.playerLetters != info.playerLetters || this.poInfo.tradeLetters != info.tradeLetters) + playJingle = true; + + if (playJingle) + Proxies.common.getRenderWorld().playSoundAtEntity(Proxies.common.getClientInstance().thePlayer, "random.levelup", 1.0f, 1.0f); + + this.poInfo = info; + } +} diff --git a/forestry_common/mail/forestry/mail/gui/GuiPhilatelist.java b/forestry_common/mail/forestry/mail/gui/GuiPhilatelist.java new file mode 100755 index 000000000..429ad23e6 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/GuiPhilatelist.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.mail.gadgets.MachinePhilatelist; + +public class GuiPhilatelist extends GuiForestry { + + public GuiPhilatelist(InventoryPlayer player, MachinePhilatelist tile) { + super(Defaults.TEXTURE_PATH_GUI + "/philatelist.png", new ContainerPhilatelist(player, tile), tile); + this.xSize = 176; + this.ySize = 193; + } + +} diff --git a/forestry_common/mail/forestry/mail/gui/GuiTradeName.java b/forestry_common/mail/forestry/mail/gui/GuiTradeName.java new file mode 100755 index 000000000..9c4056a7c --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/GuiTradeName.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.entity.player.InventoryPlayer; + +import org.lwjgl.input.Keyboard; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.utils.StringUtil; +import forestry.mail.gadgets.MachineTrader; + +public class GuiTradeName extends GuiForestry { + + private GuiTextField moniker; + + private boolean monikerFocus; + + private final ContainerTradeName container; + + public GuiTradeName(InventoryPlayer inventoryplayer, MachineTrader tile) { + super(Defaults.TEXTURE_PATH_GUI + "/tradername.png", new ContainerTradeName(inventoryplayer, tile), tile); + this.xSize = 176; + this.ySize = 90; + + this.container = (ContainerTradeName) inventorySlots; + } + + @Override + public void initGui() { + super.initGui(); + + moniker = new GuiTextField(this.fontRendererObj, guiLeft + 44, guiTop + 39, 90, 14); + if (container.getMoniker() != null) + moniker.setText(container.getMoniker()); + } + + @Override + protected void keyTyped(char eventCharacter, int eventKey) { + + // Set focus or enter text into address + if (this.moniker.isFocused()) { + if (eventKey == Keyboard.KEY_RETURN) + this.moniker.setFocused(false); + else + this.moniker.textboxKeyTyped(eventCharacter, eventKey); + return; + } + + super.keyTyped(eventCharacter, eventKey); + } + + @Override + protected void mouseClicked(int par1, int par2, int mouseButton) { + super.mouseClicked(par1, par2, mouseButton); + this.moniker.mouseClicked(par1, par2, mouseButton); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int var2, int var3) { + + // Close gui screen if we linked up. + if (container.machine.isLinked()) { + this.mc.displayGuiScreen((GuiScreen) null); + this.mc.setIngameFocus(); + } + + // Check for focus changes + if (monikerFocus != moniker.isFocused()) + setMoniker(); + monikerFocus = moniker.isFocused(); + + super.drawGuiContainerBackgroundLayer(var1, var2, var3); + + String prompt = StringUtil.localize("gui.mail.nametrader"); + fontRendererObj.drawString(prompt, guiLeft + this.getCenteredOffset(prompt), guiTop + 16, fontColor.get("gui.mail.text")); + moniker.drawTextBox(); + + } + + @Override + public void onGuiClosed() { + setMoniker(); + super.onGuiClosed(); + } + + private void setMoniker() { + container.setMoniker(this.moniker.getText()); + } + +} diff --git a/forestry_common/mail/forestry/mail/gui/GuiTrader.java b/forestry_common/mail/forestry/mail/gui/GuiTrader.java new file mode 100755 index 000000000..eaf46ecd9 --- /dev/null +++ b/forestry_common/mail/forestry/mail/gui/GuiTrader.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.gui; + +import net.minecraft.entity.player.InventoryPlayer; + +import forestry.core.config.Defaults; +import forestry.core.gui.GuiForestry; +import forestry.core.utils.StringUtil; +import forestry.mail.gadgets.MachineTrader; + +public class GuiTrader extends GuiForestry { + + private final ContainerTrader container; + + public GuiTrader(InventoryPlayer inventoryplayer, MachineTrader tile) { + super(Defaults.TEXTURE_PATH_GUI + "/mailtrader.png", new ContainerTrader(inventoryplayer, tile), tile); + this.xSize = 226; + this.ySize = 220; + + this.container = (ContainerTrader) inventorySlots; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + String name = StringUtil.localize("tile.for." + tile.getInventoryName()); + this.fontRendererObj.drawString(name, getCenteredOffset(name), 6, fontColor.get("gui.mail.text")); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(var1, mouseX, mouseY); + + fontRendererObj.drawString(container.getMoniker(), guiLeft + 19, guiTop + 22, fontColor.get("gui.mail.text")); + + } +} diff --git a/forestry_common/mail/forestry/mail/items/ItemCatalogue.java b/forestry_common/mail/forestry/mail/items/ItemCatalogue.java new file mode 100755 index 000000000..590469ab3 --- /dev/null +++ b/forestry_common/mail/forestry/mail/items/ItemCatalogue.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.core.ForestryAPI; +import forestry.core.items.ItemForestry; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; + +public class ItemCatalogue extends ItemForestry { + + public ItemCatalogue() { + super(); + setMaxStackSize(1); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) { + entityplayer.openGui(ForestryAPI.instance, GuiId.CatalogueGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + } + + return itemstack; + } + + +} diff --git a/forestry_common/mail/forestry/mail/items/ItemLetter.java b/forestry_common/mail/forestry/mail/items/ItemLetter.java new file mode 100755 index 000000000..5c0ace90b --- /dev/null +++ b/forestry_common/mail/forestry/mail/items/ItemLetter.java @@ -0,0 +1,270 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.items; + +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import forestry.api.core.ForestryAPI; +import forestry.api.mail.ILetter; +import forestry.core.EnumErrorCode; +import forestry.core.config.Config; +import forestry.core.interfaces.IErrorSource; +import forestry.core.interfaces.IHintSource; +import forestry.core.items.ItemInventoried; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.ItemInventory; +import forestry.core.utils.StringUtil; +import forestry.mail.Letter; + +public class ItemLetter extends ItemInventoried { + + public static class LetterInventory extends ItemInventory implements IErrorSource, IHintSource { + + ILetter letter; + + public LetterInventory(ItemStack itemstack) { + super(ItemLetter.class); + this.parent = itemstack; + this.isItemInventory = true; + + // Set an uid to identify the itemstack on SMP + setUID(true); + + readFromNBT(itemstack.getTagCompound()); + } + + public ILetter getLetter() { + return this.letter; + } + + @Override + public void onGuiSaved(EntityPlayer player) { + super.onGuiSaved(player); + + if (parent == null) + return; + + // Already delivered mails can't be made usable anymore. + int state = getState(parent.getItemDamage()); + if (state >= 2) { + if (state == 2 && letter.countAttachments() <= 0) + parent.setItemDamage(encodeMeta(3, getSize(parent.getItemDamage()))); + return; + } + + int type = getType(letter); + + if (parent != null && letter.isMailable() && letter.isPostPaid()) + parent.setItemDamage(encodeMeta(1, type)); + else + parent.setItemDamage(encodeMeta(0, type)); + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + + if (nbttagcompound == null) + return; + + letter = new Letter(nbttagcompound); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + letter.writeToNBT(nbttagcompound); + } + + @Override + public ItemStack decrStackSize(int i, int j) { + return letter.decrStackSize(i, j); + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + letter.setInventorySlotContents(i, itemstack); + } + + @Override + public ItemStack getStackInSlot(int i) { + return letter.getStackInSlot(i); + } + + @Override + public int getSizeInventory() { + return letter.getSizeInventory(); + } + + @Override + public String getInventoryName() { + return letter.getInventoryName(); + } + + @Override + public int getInventoryStackLimit() { + return letter.getInventoryStackLimit(); + } + + @Override + public void markDirty() { + letter.markDirty(); + } + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return letter.isUseableByPlayer(entityplayer); + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return letter.getStackInSlotOnClosing(slot); + } + + // / IERRORSOURCE + @Override + public boolean throwsErrors() { + return true; + } + + @Override + public EnumErrorCode getErrorState() { + + if (!letter.hasRecipient()) + return EnumErrorCode.NORECIPIENT; + + if (!letter.isProcessed() && !letter.isPostPaid()) + return EnumErrorCode.NOTPOSTPAID; + + return EnumErrorCode.OK; + } + + /* IHINTSOURCE */ + @Override + public boolean hasHints() { + return Config.hints.get("letter") != null && Config.hints.get("letter").length > 0; + } + + @Override + public String[] getHints() { + return Config.hints.get("letter"); + } + + } + + public ItemLetter() { + super(); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer) { + if (Proxies.common.isSimulating(world)) + if (itemstack.stackSize == 1) { + entityplayer.openGui(ForestryAPI.instance, GuiId.LetterGUI.ordinal(), world, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + } else { + entityplayer.addChatMessage(new ChatComponentTranslation("chat.mail.wrongstacksize")); + } + + return itemstack; + } + + @Override + public boolean getShareTag() { + return true; + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[][] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + icons = new IIcon[3][4]; + for (int i = 0; i < 3; i++) { + icons[i][0] = TextureManager.getInstance().registerTex(register, "mail/letter." + i + ".fresh"); + icons[i][1] = TextureManager.getInstance().registerTex(register, "mail/letter." + i + ".stamped"); + icons[i][2] = TextureManager.getInstance().registerTex(register, "mail/letter." + i + ".opened"); + icons[i][3] = TextureManager.getInstance().registerTex(register, "mail/letter." + i + ".emptied"); + } + + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamage(int damage) { + + int state = getState(damage); + int size = getSize(damage); + + return icons[size][state]; + } + + public static int encodeMeta(int state, int size) { + int meta = size << 4; + meta |= state; + + size = getSize(meta); + state = getState(meta); + + return meta; + } + + public static int getState(int meta) { + return meta & 0x0f; + } + + public static int getSize(int meta) { + return meta >> 4; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + NBTTagCompound nbttagcompound = itemstack.getTagCompound(); + if (nbttagcompound == null) { + list.add("<" + StringUtil.localize("gui.blank") + ">"); + return; + } + + ILetter letter = new Letter(nbttagcompound); + letter.addTooltip(list); + } + + public static int getType(ILetter letter) { + int count = letter.countAttachments(); + + if (count > 5) + return 2; + else if (count > 1) + return 1; + else + return 0; + } + +} diff --git a/forestry_common/mail/forestry/mail/items/ItemStamps.java b/forestry_common/mail/forestry/mail/items/ItemStamps.java new file mode 100755 index 000000000..2767691e8 --- /dev/null +++ b/forestry_common/mail/forestry/mail/items/ItemStamps.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.items; + +import net.minecraft.item.ItemStack; + +import forestry.api.mail.EnumPostage; +import forestry.api.mail.IStamps; +import forestry.core.CreativeTabForestry; +import forestry.core.items.ItemOverlay; +import forestry.core.utils.StringUtil; + +public class ItemStamps extends ItemOverlay implements IStamps { + + public static class StampInfo extends OverlayInfo { + + private final Object craftingIngredient; + private final EnumPostage postage; + + public StampInfo(String name, EnumPostage postage, Object crafting, int primaryColor, int secondaryColor) { + super(name, primaryColor, secondaryColor); + this.craftingIngredient = crafting; + this.postage = postage; + } + + public EnumPostage getPostage() { + return this.postage; + } + + public Object getCraftingIngredient() { + return this.craftingIngredient; + } + + } + + private final StampInfo[] stampInfo; + + public ItemStamps(StampInfo[] overlays) { + super(CreativeTabForestry.tabForestry, overlays); + this.stampInfo = overlays; + } + + @Override + public EnumPostage getPostage(ItemStack itemstack) { + if (itemstack.getItem() != this) + return EnumPostage.P_0; + + if (itemstack.getItemDamage() < 0 || itemstack.getItemDamage() >= stampInfo.length) + return EnumPostage.P_0; + + return stampInfo[itemstack.getItemDamage()].getPostage(); + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (itemstack.getItemDamage() < 0 || itemstack.getItemDamage() >= stampInfo.length) + return null; + + return StringUtil.localize(getUnlocalizedName()) + " " + stampInfo[itemstack.getItemDamage()].name; + } + + +} diff --git a/forestry_common/mail/forestry/mail/network/PacketPOBoxInfo.java b/forestry_common/mail/forestry/mail/network/PacketPOBoxInfo.java new file mode 100755 index 000000000..d6398c9aa --- /dev/null +++ b/forestry_common/mail/forestry/mail/network/PacketPOBoxInfo.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import forestry.core.network.ForestryPacket; +import forestry.mail.POBoxInfo; + +public class PacketPOBoxInfo extends ForestryPacket { + + public POBoxInfo poboxInfo; + + public PacketPOBoxInfo() { + } + + public PacketPOBoxInfo(int id, POBoxInfo info) { + super(id); + this.poboxInfo = info; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + if (poboxInfo == null) { + data.writeShort(-1); + return; + } + + data.writeShort(0); + data.writeInt(poboxInfo.playerLetters); + data.writeInt(poboxInfo.tradeLetters); + } + + @Override + public void readData(DataInputStream data) throws IOException { + + short isNotNull = data.readShort(); + if (isNotNull < 0) + return; + + this.poboxInfo = new POBoxInfo(data.readInt(), data.readInt()); + } + +} diff --git a/forestry_common/mail/forestry/mail/network/PacketTradeInfo.java b/forestry_common/mail/forestry/mail/network/PacketTradeInfo.java new file mode 100755 index 000000000..28f2fc949 --- /dev/null +++ b/forestry_common/mail/forestry/mail/network/PacketTradeInfo.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.network; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.item.ItemStack; + +import forestry.api.mail.TradeStationInfo; +import forestry.core.network.ForestryPacket; +import forestry.mail.EnumStationState; + +public class PacketTradeInfo extends ForestryPacket { + + public TradeStationInfo tradeInfo; + + public PacketTradeInfo() { + } + + public PacketTradeInfo(int id, TradeStationInfo info) { + super(id); + this.tradeInfo = info; + } + + @Override + public void writeData(DataOutputStream data) throws IOException { + + if (tradeInfo == null) { + data.writeShort(-1); + return; + } + + data.writeShort(0); + + data.writeUTF(tradeInfo.moniker); + data.writeUTF(tradeInfo.owner); + writeItemStack(tradeInfo.tradegood, data); + data.writeShort(tradeInfo.required.length); + for (int i = 0; i < tradeInfo.required.length; i++) + writeItemStack(tradeInfo.required[i], data); + data.writeShort(tradeInfo.state.ordinal()); + } + + @Override + public void readData(DataInputStream data) throws IOException { + + short isNotNull = data.readShort(); + if (isNotNull < 0) + return; + + String moniker; + String owner; + ItemStack tradegood; + ItemStack[] required; + + moniker = data.readUTF(); + owner = data.readUTF(); + tradegood = readItemStack(data); + required = new ItemStack[data.readShort()]; + for (int i = 0; i < required.length; i++) + required[i] = readItemStack(data); + + this.tradeInfo = new TradeStationInfo(moniker, owner, tradegood, required, EnumStationState.values()[data.readShort()]); + } + +} diff --git a/forestry_common/mail/forestry/mail/proxy/ClientProxyMail.java b/forestry_common/mail/forestry/mail/proxy/ClientProxyMail.java new file mode 100755 index 000000000..250b6c0c2 --- /dev/null +++ b/forestry_common/mail/forestry/mail/proxy/ClientProxyMail.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.proxy; + +import net.minecraft.world.World; + +import forestry.core.network.ForestryPacket; +import forestry.core.network.PacketIds; +import forestry.core.proxy.Proxies; +import forestry.core.utils.Localization; +import forestry.mail.POBox; +import forestry.mail.POBoxInfo; +import forestry.mail.PostRegistry; +import forestry.mail.gui.GuiMailboxInfo; + +public class ClientProxyMail extends ProxyMail { + + @Override + public void clearMailboxInfo() { + GuiMailboxInfo.instance = null; + } + + @Override + public void resetMailboxInfo() { + if (Proxies.common.getClientInstance().thePlayer == null) + return; + + GuiMailboxInfo.instance = new GuiMailboxInfo(); + + if (!Proxies.common.isSimulating(Proxies.common.getRenderWorld())) + Proxies.net.sendToServer(new ForestryPacket(PacketIds.POBOX_INFO_REQUEST)); + else { + POBox pobox = PostRegistry.getPOBox(Proxies.common.getRenderWorld(), Proxies.common.getClientInstance().thePlayer.getGameProfile().getId()); + if (pobox != null) + setPOBoxInfo(Proxies.common.getRenderWorld(), Proxies.common.getClientInstance().thePlayer.getGameProfile().getId(), pobox.getPOBoxInfo()); + } + } + + @Override + public void setPOBoxInfo(World world, String playername, POBoxInfo info) { + if (Proxies.common.getClientInstance().thePlayer == null || !Proxies.common.getClientInstance().thePlayer.getGameProfile().getId().equals(playername)) + return; + + GuiMailboxInfo.instance.setPOBoxInfo(info); + } + + @Override + public void addLocalizations() { + Localization.instance.addLocalization("/lang/forestry/mail/"); + } + +} diff --git a/forestry_common/mail/forestry/mail/proxy/ProxyMail.java b/forestry_common/mail/forestry/mail/proxy/ProxyMail.java new file mode 100755 index 000000000..0a61875ab --- /dev/null +++ b/forestry_common/mail/forestry/mail/proxy/ProxyMail.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.proxy; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.world.World; + +import forestry.core.network.PacketIds; +import forestry.core.proxy.Proxies; +import forestry.mail.POBoxInfo; +import forestry.mail.network.PacketPOBoxInfo; + +public class ProxyMail { + + public void clearMailboxInfo() { + } + + public void resetMailboxInfo() { + } + + public void setPOBoxInfo(World world, String playername, POBoxInfo info) { + for (int i = 0; i < world.playerEntities.size(); i++) { + EntityPlayerMP player = (EntityPlayerMP) world.playerEntities.get(i); + if (!player.getGameProfile().getId().equals(playername)) + continue; + + Proxies.net.sendToPlayer(new PacketPOBoxInfo(PacketIds.POBOX_INFO, info), player); + break; + } + } + + public void addLocalizations() { + } + +} diff --git a/forestry_common/mail/forestry/mail/triggers/TriggerBuffer.java b/forestry_common/mail/forestry/mail/triggers/TriggerBuffer.java new file mode 100755 index 000000000..8951864f7 --- /dev/null +++ b/forestry_common/mail/forestry/mail/triggers/TriggerBuffer.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.triggers.Trigger; +import forestry.mail.gadgets.MachineTrader; + +public class TriggerBuffer extends Trigger { + + float threshold; + + public TriggerBuffer(String tag, float threshold) { + super(tag, "mailBuffer"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " > " + threshold * 100 + "%"; + } + + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof MachineTrader)) + return false; + + return ((MachineTrader) tile).hasOutputBufMin(threshold); + } + +} diff --git a/forestry_common/mail/forestry/mail/triggers/TriggerHasMail.java b/forestry_common/mail/forestry/mail/triggers/TriggerHasMail.java new file mode 100755 index 000000000..fe6b04405 --- /dev/null +++ b/forestry_common/mail/forestry/mail/triggers/TriggerHasMail.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.triggers.Trigger; +import forestry.mail.IMailContainer; + +public class TriggerHasMail extends Trigger { + + public TriggerHasMail() { + super("mail.hasMail", "hasMail"); + } + + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof IMailContainer)) + return false; + + return ((IMailContainer) tile).hasMail(); + } +} diff --git a/forestry_common/mail/forestry/mail/triggers/TriggerLowInput.java b/forestry_common/mail/forestry/mail/triggers/TriggerLowInput.java new file mode 100755 index 000000000..e9bd8fb3e --- /dev/null +++ b/forestry_common/mail/forestry/mail/triggers/TriggerLowInput.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.triggers.Trigger; +import forestry.mail.gadgets.MachineTrader; + +public class TriggerLowInput extends Trigger { + + float threshold; + + public TriggerLowInput(String tag, float threshold) { + super(tag, "lowInput"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof MachineTrader)) + return false; + + return !((MachineTrader) tile).hasInputBufMin(threshold); + } +} diff --git a/forestry_common/mail/forestry/mail/triggers/TriggerLowPaper.java b/forestry_common/mail/forestry/mail/triggers/TriggerLowPaper.java new file mode 100755 index 000000000..4b7a5e133 --- /dev/null +++ b/forestry_common/mail/forestry/mail/triggers/TriggerLowPaper.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.triggers.Trigger; +import forestry.mail.gadgets.MachineTrader; + +public class TriggerLowPaper extends Trigger { + + float threshold; + + public TriggerLowPaper(String tag, float threshold) { + super(tag, "lowPaper"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold * 100 + "%"; + } + + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof MachineTrader)) + return false; + + return !((MachineTrader) tile).hasPaperMin(threshold); + } + +} diff --git a/forestry_common/mail/forestry/mail/triggers/TriggerLowStamps.java b/forestry_common/mail/forestry/mail/triggers/TriggerLowStamps.java new file mode 100755 index 000000000..56a8065c6 --- /dev/null +++ b/forestry_common/mail/forestry/mail/triggers/TriggerLowStamps.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.mail.triggers; + +import net.minecraft.tileentity.TileEntity; + +import net.minecraftforge.common.util.ForgeDirection; + +import buildcraft.api.gates.ITriggerParameter; + +import forestry.core.triggers.Trigger; +import forestry.mail.gadgets.MachineTrader; + +public class TriggerLowStamps extends Trigger { + + int threshold; + + public TriggerLowStamps(String tag, int threshold) { + super(tag, "lowStamps"); + this.threshold = threshold; + } + + @Override + public String getDescription() { + return super.getDescription() + " < " + threshold + "p"; + } + + @Override + public boolean isTriggerActive(ForgeDirection direction, TileEntity tile, ITriggerParameter parameter) { + + if (!(tile instanceof MachineTrader)) + return false; + + return !((MachineTrader) tile).hasPostageMin(threshold); + } + +} diff --git a/forestry_common/mail/forestry/plugins/PluginMail.java b/forestry_common/mail/forestry/plugins/PluginMail.java new file mode 100755 index 000000000..60c360c3f --- /dev/null +++ b/forestry_common/mail/forestry/plugins/PluginMail.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import net.minecraft.block.material.Material; +import net.minecraft.command.ICommand; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.network.IGuiHandler; + +import forestry.api.core.PluginInfo; +import forestry.api.mail.EnumPostage; +import forestry.api.mail.PostManager; +import forestry.api.recipes.RecipeManagers; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.gadgets.BlockBase; +import forestry.core.gadgets.MachineDefinition; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.items.ItemForestryBlock; +import forestry.core.proxy.Proxies; +import forestry.core.triggers.Trigger; +import forestry.core.utils.LiquidHelper; +import forestry.core.utils.ShapedRecipeCustom; +import forestry.mail.CommandMail; +import forestry.mail.EnumAddressee; +import forestry.mail.GuiHandlerMail; +import forestry.mail.PacketHandlerMail; +import forestry.mail.PostRegistry; +import forestry.mail.PostalCarrier; +import forestry.mail.SaveEventHandlerMail; +import forestry.mail.TickHandlerMailClient; +import forestry.mail.gadgets.MachineMailbox; +import forestry.mail.gadgets.MachinePhilatelist; +import forestry.mail.gadgets.MachineTrader; +import forestry.mail.items.ItemCatalogue; +import forestry.mail.items.ItemLetter; +import forestry.mail.items.ItemStamps; +import forestry.mail.items.ItemStamps.StampInfo; +import forestry.mail.proxy.ProxyMail; +import forestry.mail.triggers.TriggerBuffer; +import forestry.mail.triggers.TriggerHasMail; +import forestry.mail.triggers.TriggerLowInput; +import forestry.mail.triggers.TriggerLowPaper; +import forestry.mail.triggers.TriggerLowStamps; + +@PluginInfo(pluginID = "Mail", name = "Mail", author = "SirSengir", url = Defaults.URL, description = "Adds Forestry's mail and trade system.") +public class PluginMail extends NativePlugin { + + @SidedProxy(clientSide = "forestry.mail.proxy.ClientProxyMail", serverSide = "forestry.mail.proxy.ProxyMail") + public static ProxyMail proxy; + public static Trigger triggerHasMail; + public static Trigger lowPaper25; + public static Trigger lowPaper10; + public static Trigger lowPostage40; + public static Trigger lowPostage20; + public static Trigger lowInput25; + public static Trigger lowInput10; + public static Trigger highBuffer75; + public static Trigger highBuffer90; + public static MachineDefinition definitionMailbox; + public static MachineDefinition definitionTradestation; + public static MachineDefinition definitionPhilatelist; + public static StampInfo[] stampDefinitions; + + @Override + public boolean isAvailable() { + return !Config.disableMail; + } + + @Override + public void preInit() { + super.preInit(); + + new TickHandlerMailClient(); + + triggerHasMail = new TriggerHasMail(); + lowPaper25 = new TriggerLowPaper("mail.lowPaper.25", 0.25f); + lowPaper10 = new TriggerLowPaper("mail.lowPaper.10", 0.1f); + lowPostage40 = new TriggerLowStamps("mail.lowStamps.40", 40); + lowPostage20 = new TriggerLowStamps("mail.lowStamps.20", 20); + lowInput25 = new TriggerLowInput("mail.lowInput.25", 0.25f); + lowInput10 = new TriggerLowInput("mail.lowInput.10", 0.1f); + highBuffer75 = new TriggerBuffer("mail.lowBuffer.75", 0.75f); + highBuffer90 = new TriggerBuffer("mail.lowBuffer.90", 0.90f); + + ForestryBlock.mail = new BlockBase(Material.iron); + ForestryBlock.mail.setBlockName("for.mail"); + Proxies.common.registerBlock(ForestryBlock.mail, ItemForestryBlock.class); + + ShapedRecipeCustom recipe = ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.mail, 1, Defaults.DEFINITION_MAILBOX_META), + " # ", "#Y#", "XXX", + '#', "ingotTin", + 'X', Blocks.chest, + 'Y', ForestryItem.sturdyCasing); + definitionMailbox = ForestryBlock.mail.addDefinition(new MachineDefinition(Defaults.DEFINITION_MAILBOX_META, "forestry.Mailbox", MachineMailbox.class, recipe).setFaces(0, 1, 2, 2, 2, 2, 0, 7)); + + + recipe = ShapedRecipeCustom.createShapedRecipe(new ItemStack(ForestryBlock.mail, 1, Defaults.DEFINITION_TRADESTATION_META), + "Z#Z", "#Y#", "XWX", + '#', ForestryItem.tubes.getItemStack(1, 2), + 'X', Blocks.chest, + 'Y', ForestryItem.sturdyCasing, + 'Z', ForestryItem.tubes.getItemStack(1, 3), + 'W', ForestryItem.circuitboards.getItemStack(1, 2)); + definitionTradestation = ForestryBlock.mail.addDefinition(new MachineDefinition(Defaults.DEFINITION_TRADESTATION_META, "forestry.Tradestation", MachineTrader.class, recipe).setFaces(0, 1, 2, 3, 4, 4, 0, 7)); + + definitionPhilatelist = ForestryBlock.mail.addDefinition(new MachineDefinition(Defaults.DEFINITION_PHILATELIST_META, "forestry.Philatelist", MachinePhilatelist.class) + .setFaces(0, 1, 2, 3, 2, 2, 0, 7)); + + + + PostManager.postRegistry = new PostRegistry(); + PostManager.postRegistry.registerCarrier(new PostalCarrier(EnumAddressee.PLAYER)); + PostManager.postRegistry.registerCarrier(new PostalCarrier(EnumAddressee.TRADER)); + } + + @Override + public void doInit() { + super.doInit(); + + proxy.addLocalizations(); + + definitionMailbox.register(); + definitionTradestation.register(); + definitionPhilatelist.register(); + } + + @Override + public void postInit() { + super.postInit(); + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerMail(); + } + + @Override + public IPacketHandler getPacketHandler() { + return new PacketHandlerMail(); + } + + @Override + protected void registerItems() { + + stampDefinitions = new StampInfo[] { + new StampInfo("1n", EnumPostage.P_1, ForestryItem.apatite, 0x4a8ca7, 0xffffff), new StampInfo("2n", EnumPostage.P_2, "ingotCopper", 0xe8c814, 0xffffff), + new StampInfo("5n", EnumPostage.P_5, "ingotTin", 0x9c0707, 0xffffff), new StampInfo("10n", EnumPostage.P_10, Items.gold_ingot, 0x7bd1b8, 0xffffff), + new StampInfo("20n", EnumPostage.P_20, Items.diamond, 0xff9031, 0xfff7dd), new StampInfo("50n", EnumPostage.P_50, Items.emerald, 0x6431d7, 0xfff7dd), + new StampInfo("100n", EnumPostage.P_100, Items.nether_star, 0xd731ba, 0xfff7dd) }; //new StampInfo("200n", EnumPostage.P_200, Item.netherStar, 0xcd9831, 0xfff7dd)}; + + /* STAMPS */ + ForestryItem.stamps.registerItem(new ItemStamps(stampDefinitions), "stamps"); + + /* LETTER */ + ForestryItem.letters.registerItem(new ItemLetter(), "letters"); + + /* CATALOGUE */ + ForestryItem.catalogue.registerItem(new ItemCatalogue(), "catalogue"); + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerCrates() { + } + + @Override + protected void registerRecipes() { + // Letters + Proxies.common.addShapelessRecipe(ForestryItem.letters.getItemStack(), Items.paper, ForestryItem.propolis.getItemStack(1, Defaults.WILDCARD)); + + if (Config.craftingStampsEnabled) { + for (int i = 0; i < stampDefinitions.length; i++) { + if (Config.collectorStamps.contains(stampDefinitions[i].name)) + continue; + + Proxies.common.addRecipe(ForestryItem.stamps.getItemStack(9, i), new Object[] { "XXX", "###", "ZZZ", 'X', + stampDefinitions[i].getCraftingIngredient(), '#', Items.paper, 'Z', ForestryItem.honeyDrop }); + RecipeManagers.carpenterManager.addRecipe(10, LiquidHelper.getLiquid(Defaults.LIQUID_SEEDOIL, 300), null, ForestryItem.stamps.getItemStack(9, i), + new Object[] { "XXX", "###", 'X', stampDefinitions[i].getCraftingIngredient(), '#', Items.paper }); + } + } + + // Recycling + Proxies.common.addRecipe(new ItemStack(Items.paper), new Object[] { "###", '#', ForestryItem.letters.getItemStack(1, Defaults.WILDCARD) }); + + // Carpenter + RecipeManagers.carpenterManager.addRecipe(10, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 250), null, ForestryItem.letters.getItemStack(), new Object[] { "###", "###", '#', ForestryItem.woodPulp }); + + Proxies.common.addShapelessRecipe(ForestryItem.catalogue.getItemStack(), new Object[] { ForestryItem.stamps.getItemStack(1, Defaults.WILDCARD), new ItemStack(Items.book) }); + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return new SaveEventHandlerMail(); + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return null; + } + + @Override + public ICommand[] getConsoleCommands() { + return new ICommand[] { new CommandMail() }; + } +} diff --git a/forestry_common/storage/forestry/plugins/PluginStorage.java b/forestry_common/storage/forestry/plugins/PluginStorage.java new file mode 100755 index 000000000..0d35b6b04 --- /dev/null +++ b/forestry_common/storage/forestry/plugins/PluginStorage.java @@ -0,0 +1,594 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockBasePressurePlate; +import net.minecraft.block.BlockButton; +import net.minecraft.block.BlockChest; +import net.minecraft.block.BlockFence; +import net.minecraft.block.BlockFenceGate; +import net.minecraft.block.BlockFurnace; +import net.minecraft.block.BlockLadder; +import net.minecraft.block.BlockLever; +import net.minecraft.block.BlockLog; +import net.minecraft.block.BlockMelon; +import net.minecraft.block.BlockPumpkin; +import net.minecraft.block.BlockRedstoneDiode; +import net.minecraft.block.BlockStairs; +import net.minecraft.block.BlockTorch; +import net.minecraft.block.BlockTrapDoor; +import net.minecraft.block.BlockWall; +import net.minecraft.block.BlockWorkbench; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemDoor; +import net.minecraft.item.ItemFood; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.event.FMLInterModComms.IMCMessage; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.common.registry.GameData; + +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.common.IShearable; +import net.minecraftforge.oredict.OreDictionary; + +import forestry.api.core.PluginInfo; +import forestry.api.core.Tabs; +import forestry.api.recipes.RecipeManagers; +import forestry.api.storage.BackpackManager; +import forestry.api.storage.EnumBackpackType; +import forestry.api.storage.IBackpackDefinition; +import forestry.core.config.Config; +import forestry.core.config.Configuration; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryBlock; +import forestry.core.config.ForestryItem; +import forestry.core.config.Property; +import forestry.core.interfaces.IOreDictionaryHandler; +import forestry.core.interfaces.IPickupHandler; +import forestry.core.interfaces.IResupplyHandler; +import forestry.core.interfaces.ISaveEventHandler; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.utils.LiquidHelper; +import forestry.storage.BackpackDefinition; +import forestry.storage.BackpackHelper; +import forestry.storage.GuiHandlerStorage; +import forestry.storage.PickupHandlerStorage; +import forestry.storage.ResupplyHandler; +import forestry.storage.items.ItemBackpack; +import forestry.storage.items.ItemNaturalistBackpack; +import forestry.storage.items.ItemNaturalistBackpack.BackpackDefinitionApiarist; +import forestry.storage.items.ItemNaturalistBackpack.BackpackDefinitionLepidopterist; + +@PluginInfo(pluginID = "Storage", name = "Storage", author = "SirSengir", url = Defaults.URL, description = "Adds backpacks and crates.") +public class PluginStorage extends NativePlugin implements IOreDictionaryHandler { + + private final ArrayList minerItems = new ArrayList(); + private final ArrayList diggerItems = new ArrayList(); + private final ArrayList foresterItems = new ArrayList(); + private final ArrayList hunterItems = new ArrayList(); + private final ArrayList adventurerItems = new ArrayList(); + private final ArrayList builderItems = new ArrayList(); + static String CONFIG_CATEGORY = "backpacks"; + Configuration config; + + @Override + public boolean isAvailable() { + return !Config.disableStorage; + } + + @Override + public void preInit() { + BackpackManager.backpackInterface = new BackpackHelper(); + super.preInit(); + createBackpackArrays(); + } + + @Override + public void postInit() { + super.postInit(); + + scanForItems(); + + config = new Configuration(); + + Property backpackConf = config.get("backpacks.miner.items", CONFIG_CATEGORY, ""); + backpackConf.Comment = "add additional blocks and items for the miner's backpack here in the format id:meta. separate blocks and items using ';'. wildcard for metadata: '*'"; + parseBackpackItems("Miner's Backpack", backpackConf.Value, BackpackManager.definitions.get("miner")); + backpackConf = config.get("backpacks.digger.items", CONFIG_CATEGORY, ""); + backpackConf.Comment = "add additional blocks and items for the digger's backpack here in the format id:meta. separate blocks and items using ';'. wildcard for metadata: '*'"; + parseBackpackItems("Digger's Backpack", backpackConf.Value, BackpackManager.definitions.get("digger")); + backpackConf = config.get("backpacks.forester.items", CONFIG_CATEGORY, ""); + backpackConf.Comment = "add additional blocks and items for the forester's backpack here in the format id:meta. separate blocks and items using ';'. wildcard for metadata: '*'"; + parseBackpackItems("Forester's Backpack", backpackConf.Value, BackpackManager.definitions.get("forester")); + backpackConf = config.get("backpacks.hunter.items", CONFIG_CATEGORY, ""); + backpackConf.Comment = "add additional blocks and items for the hunter's backpack here in the format id:meta. separate blocks and items using ';'. wildcard for metadata: '*'"; + parseBackpackItems("Hunter's Backpack", backpackConf.Value, BackpackManager.definitions.get("hunter")); + backpackConf = config.get("backpacks.adventurer.items", CONFIG_CATEGORY, ""); + backpackConf.Comment = "add blocks and items for the adventurer's backpack here in the format id:meta. separate blocks and items using ';'. wildcard for metadata: '*'"; + parseBackpackItems("Adventurer's Backpack", backpackConf.Value, BackpackManager.definitions.get("adventurer")); + backpackConf = config.get("backpacks.builder.items", CONFIG_CATEGORY, ""); + backpackConf.Comment = "add blocks and items for the builder's backpack here in the format id:meta. separate blocks and items using ';'. wildcard for metadata: '*'"; + parseBackpackItems("Builder's Backpack", backpackConf.Value, BackpackManager.definitions.get("builder")); + + config.save(); + + } + + public static void addBackpackItem(String pack, ItemStack stack) { + if (stack == null) + return; + BackpackManager.definitions.get(pack).addValidItem(stack); + } + + public static void addBackpackItem(String pack, Block block) { + BackpackManager.definitions.get(pack).addValidItem(new ItemStack(block, 1, Defaults.WILDCARD)); + } + + public static void addBackpackItem(String pack, Item item) { + BackpackManager.definitions.get(pack).addValidItem(new ItemStack(item, 1, Defaults.WILDCARD)); + } + + public static void scanForItems() { + for (Object id : Block.blockRegistry.getKeys()) { + try { + Block block = (Block) Block.blockRegistry.getObject(id); + + if (block instanceof IPlantable || + block instanceof IShearable || + block instanceof BlockLog || + block instanceof BlockMelon || + block instanceof BlockPumpkin) + addBackpackItem("forester", block); + if (block instanceof BlockStairs || block.getRenderType() == 10 || + block instanceof BlockFence || block.getRenderType() == 11 || + block instanceof BlockFenceGate || block.getRenderType() == 21 || + block instanceof BlockWall || block.getRenderType() == 32 || + block instanceof BlockBasePressurePlate || + block instanceof BlockLever || + block instanceof BlockButton || + block instanceof BlockTorch || + block instanceof BlockRedstoneDiode || + block instanceof BlockChest || block.getRenderType() == 22 || + block instanceof BlockWorkbench || + block instanceof BlockFurnace || + block instanceof BlockLadder || block.getRenderType() == 8 || + block instanceof BlockTrapDoor || + block.getUnlocalizedName().contains("door")) + addBackpackItem("builder", block); + } catch (Throwable error) { + error.printStackTrace(); + } + } + + for (Object id : Item.itemRegistry.getKeys()) { + try { + Item item = (Item) Item.itemRegistry.getObject(id); + + if (item instanceof IPlantable) + addBackpackItem("forester", item); + else if (item instanceof ItemFood) + addBackpackItem("hunter", item); + else if (item instanceof ItemDoor) + addBackpackItem("builder", item); + } catch (Throwable error) { + error.printStackTrace(); + } + } + } + + @Override + public boolean processIMCMessage(IMCMessage message) { + if (message.key.equals("add-backpack-items")) { + String[] tokens = message.getStringValue().split("@"); + if (tokens.length != 2) { + Logger.getLogger("Forestry").log(Level.INFO, + String.format("Received an invalid 'add-backpack-items' request %s from mod %s", message.getStringValue(), message.getSender())); + return true; + } + + if (!BackpackManager.definitions.containsKey(tokens[0])) { + Logger.getLogger("Forestry").log( + Level.INFO, + String.format("Received an invalid 'add-backpack-items' request %s from mod %s for non-existent backpack %s.", + message.getStringValue(), message.getSender(), tokens[0])); + return true; + } + + parseBackpackItems(tokens[0] + "'s Backpack", tokens[1], BackpackManager.definitions.get(tokens[0])); + + return true; + } + return false; + } + + @Override + public IPickupHandler getPickupHandler() { + return new PickupHandlerStorage(); + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerStorage(); + } + + @Override + public IResupplyHandler getResupplyHandler() { + return new ResupplyHandler(); + } + + @Override + protected void registerItems() { + // / BACKPACKS + ForestryItem.apiaristBackpack.registerItem(new ItemNaturalistBackpack(GuiId.ApiaristBackpackGUI.ordinal(), new BackpackDefinitionApiarist("apiarist", 0xc4923d)).setCreativeTab(Tabs.tabApiculture), "apiaristBag"); + BackpackDefinition definition = (BackpackDefinition) ((ItemBackpack) ForestryItem.apiaristBackpack.item()).getDefinition(); + BackpackManager.definitions.put(definition.getKey(), definition); + + ForestryItem.lepidopteristBackpack.registerItem(new ItemNaturalistBackpack(GuiId.LepidopteristBackpackGUI.ordinal(), new BackpackDefinitionLepidopterist("lepidopterist", 0x995b31)).setCreativeTab(Tabs.tabLepidopterology), "lepidopteristBag"); + definition = (BackpackDefinition) ((ItemBackpack) ForestryItem.lepidopteristBackpack.item()).getDefinition(); + BackpackManager.definitions.put(definition.getKey(), definition); + + definition = new BackpackDefinition("miner", 0x36187d).setValidItems(BackpackManager.backpackItems[0]); + BackpackManager.definitions.put(definition.getKey(), definition); + ForestryItem.minerBackpack.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T1), "minerBag"); + ForestryItem.minerBackpackT2.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T2), "minerBagT2"); + + definition = new BackpackDefinition("digger", 0x363cc5).setValidItems(BackpackManager.backpackItems[1]); + BackpackManager.definitions.put(definition.getKey(), definition); + ForestryItem.diggerBackpack.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T1), "diggerBag"); + ForestryItem.diggerBackpackT2.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T2), "diggerBagT2"); + + definition = new BackpackDefinition("forester", 0x347427) + .setValidItems(BackpackManager.backpackItems[2]); + BackpackManager.definitions.put(definition.getKey(), definition); + ForestryItem.foresterBackpack.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T1), "foresterBag"); + ForestryItem.foresterBackpackT2.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T2), "foresterBagT2"); + + definition = new BackpackDefinition("hunter", 0x412215).setValidItems(BackpackManager.backpackItems[3]); + BackpackManager.definitions.put(definition.getKey(), definition); + ForestryItem.hunterBackpack.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T1), "hunterBag"); + ForestryItem.hunterBackpackT2.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T2), "hunterBagT2"); + + definition = new BackpackDefinition("adventurer", 0x7fb8c2) + .setValidItems(BackpackManager.backpackItems[4]); + BackpackManager.definitions.put(definition.getKey(), definition); + ForestryItem.adventurerBackpack.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T1), "adventurerBackpack"); + ForestryItem.adventurerBackpackT2.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T2), "adventurerBackpackT2"); + + definition = new BackpackDefinition("builder", 0xdd3a3a) + .setValidItems(BackpackManager.backpackItems[5]); + BackpackManager.definitions.put(definition.getKey(), definition); + ForestryItem.builderBackpack.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T1), "builderBackpack"); + ForestryItem.builderBackpackT2.registerItem(BackpackManager.backpackInterface.addBackpack(definition, EnumBackpackType.T2), "builderBackpackT2"); + + } + + @Override + protected void registerBackpackItems() { + + // [0] Set valid items in miner's backpack + minerItems.add(new ItemStack(Blocks.obsidian)); + minerItems.add(new ItemStack(Blocks.coal_ore)); + minerItems.add(new ItemStack(Items.coal)); + minerItems.add(new ItemStack(Blocks.diamond_ore)); + minerItems.add(new ItemStack(Items.diamond)); + minerItems.add(new ItemStack(Blocks.gold_ore)); + minerItems.add(new ItemStack(Items.gold_ingot)); + minerItems.add(new ItemStack(Blocks.iron_ore)); + minerItems.add(new ItemStack(Items.iron_ingot)); + minerItems.add(new ItemStack(Blocks.lapis_ore)); + minerItems.add(new ItemStack(Blocks.redstone_ore)); + minerItems.add(new ItemStack(Items.redstone)); + minerItems.add(new ItemStack(Items.dye, 1, 4)); + minerItems.add(new ItemStack(Items.glowstone_dust)); + minerItems.add(new ItemStack(Items.emerald)); + minerItems.add(new ItemStack(Blocks.diamond_block)); + minerItems.add(new ItemStack(Blocks.emerald_block)); + minerItems.add(new ItemStack(Blocks.gold_block)); + minerItems.add(new ItemStack(Blocks.iron_block)); + minerItems.add(new ItemStack(Blocks.lapis_block)); + minerItems.add(ForestryItem.bronzePickaxe.getItemStack()); + minerItems.add(ForestryItem.kitPickaxe.getItemStack()); + minerItems.add(ForestryItem.brokenBronzePickaxe.getItemStack()); + minerItems.add(new ItemStack(Items.quartz)); + minerItems.add(new ItemStack(Blocks.emerald_ore)); + minerItems.add(new ItemStack(Blocks.quartz_ore)); + + // [1] Set valid items in digger's backpack + diggerItems.add(new ItemStack(Blocks.dirt)); + diggerItems.add(new ItemStack(Blocks.cobblestone)); + diggerItems.add(new ItemStack(Blocks.sand)); + diggerItems.add(new ItemStack(Blocks.sandstone)); + diggerItems.add(new ItemStack(Blocks.gravel)); + diggerItems.add(new ItemStack(Items.flint)); + diggerItems.add(new ItemStack(Blocks.netherrack)); + diggerItems.add(new ItemStack(Items.clay_ball)); + diggerItems.add(new ItemStack(Blocks.soul_sand)); + diggerItems.add(ForestryItem.bronzeShovel.getItemStack()); + diggerItems.add(ForestryItem.kitShovel.getItemStack()); + diggerItems.add(ForestryItem.brokenBronzeShovel.getItemStack()); + + // [2] Set valid items in forester's backpack + foresterItems.add(new ItemStack(Blocks.sapling, 1, Defaults.WILDCARD)); + foresterItems.add(new ItemStack(Blocks.red_mushroom)); + foresterItems.add(new ItemStack(Blocks.brown_mushroom)); + foresterItems.add(new ItemStack(Blocks.log, 1, Defaults.WILDCARD)); + foresterItems.add(new ItemStack(Items.wheat_seeds)); + foresterItems.add(new ItemStack(Blocks.red_flower)); + foresterItems.add(new ItemStack(Blocks.yellow_flower)); + foresterItems.add(new ItemStack(Blocks.leaves, 1, Defaults.WILDCARD)); + foresterItems.add(new ItemStack(Blocks.cactus)); + foresterItems.add(new ItemStack(Blocks.tallgrass, 1, Defaults.WILDCARD)); + foresterItems.add(new ItemStack(Blocks.vine)); + foresterItems.add(new ItemStack(Blocks.pumpkin)); + foresterItems.add(new ItemStack(Blocks.melon_block)); + foresterItems.add(new ItemStack(Items.apple)); + foresterItems.add(new ItemStack(Items.golden_apple)); + foresterItems.add(new ItemStack(Items.nether_wart)); + foresterItems.add(new ItemStack(Items.pumpkin_seeds)); + foresterItems.add(new ItemStack(Items.melon_seeds)); + foresterItems.add(new ItemStack(Items.wheat)); + foresterItems.add(new ItemStack(ForestryBlock.saplingGE, 1)); + + // [3] Set valid items in hunter's backpack + hunterItems.add(new ItemStack(Items.feather)); + hunterItems.add(new ItemStack(Items.gunpowder)); + hunterItems.add(new ItemStack(Items.blaze_powder)); + hunterItems.add(new ItemStack(Items.blaze_rod)); + hunterItems.add(new ItemStack(Items.bone)); + hunterItems.add(new ItemStack(Items.string)); + hunterItems.add(new ItemStack(Items.rotten_flesh)); + hunterItems.add(new ItemStack(Items.ghast_tear)); + hunterItems.add(new ItemStack(Items.gold_nugget)); + hunterItems.add(new ItemStack(Items.arrow)); + hunterItems.add(new ItemStack(Items.porkchop)); + hunterItems.add(new ItemStack(Items.cooked_porkchop)); + hunterItems.add(new ItemStack(Items.beef)); + hunterItems.add(new ItemStack(Items.cooked_beef)); + hunterItems.add(new ItemStack(Items.chicken)); + hunterItems.add(new ItemStack(Items.cooked_chicken)); + hunterItems.add(new ItemStack(Items.leather)); + hunterItems.add(new ItemStack(Items.egg)); + hunterItems.add(new ItemStack(Items.ender_pearl)); + hunterItems.add(new ItemStack(Items.spider_eye)); + hunterItems.add(new ItemStack(Items.fermented_spider_eye)); + hunterItems.add(new ItemStack(Items.slime_ball)); + hunterItems.add(new ItemStack(Items.dye, 1, 0)); + hunterItems.add(new ItemStack(Blocks.hay_block)); + hunterItems.add(new ItemStack(Blocks.wool)); + hunterItems.add(new ItemStack(Blocks.wool, 1, Defaults.WILDCARD)); + hunterItems.add(new ItemStack(Items.ender_eye)); + hunterItems.add(new ItemStack(Items.magma_cream)); + hunterItems.add(new ItemStack(Items.speckled_melon)); + hunterItems.add(new ItemStack(Items.fish)); + hunterItems.add(new ItemStack(Items.cooked_fished)); + hunterItems.add(new ItemStack(Items.lead)); + hunterItems.add(new ItemStack(Items.fishing_rod)); + hunterItems.add(new ItemStack(Items.name_tag)); + hunterItems.add(new ItemStack(Items.saddle)); + hunterItems.add(new ItemStack(Items.diamond_horse_armor)); + hunterItems.add(new ItemStack(Items.golden_horse_armor)); + hunterItems.add(new ItemStack(Items.iron_horse_armor)); + + // [4] Set valid items in adventurer's backpack + + // [5] Set valid items in builder's backpack + builderItems.add(new ItemStack(Blocks.torch)); + builderItems.add(new ItemStack(Blocks.redstone_torch)); + builderItems.add(new ItemStack(Blocks.unlit_redstone_torch)); + builderItems.add(new ItemStack(Blocks.redstone_lamp)); + builderItems.add(new ItemStack(Blocks.lit_redstone_lamp)); + builderItems.add(new ItemStack(ForestryBlock.candle)); + builderItems.add(new ItemStack(ForestryBlock.stump)); + builderItems.add(new ItemStack(Blocks.stonebrick, 1, Defaults.WILDCARD)); + builderItems.add(new ItemStack(Blocks.sandstone, 1, 1)); + builderItems.add(new ItemStack(Blocks.sandstone, 1, 2)); + builderItems.add(new ItemStack(Blocks.stone)); + builderItems.add(new ItemStack(Blocks.brick_block)); + builderItems.add(new ItemStack(Blocks.planks, 1, Defaults.WILDCARD)); + builderItems.add(new ItemStack(Blocks.hardened_clay, 1, Defaults.WILDCARD)); + builderItems.add(new ItemStack(Blocks.nether_brick)); + builderItems.add(new ItemStack(Blocks.nether_brick_fence)); + builderItems.add(new ItemStack(Blocks.stone_stairs)); + builderItems.add(new ItemStack(Blocks.oak_stairs)); + builderItems.add(new ItemStack(Blocks.brick_stairs)); + builderItems.add(new ItemStack(Blocks.nether_brick_stairs)); + builderItems.add(new ItemStack(Blocks.stone_brick_stairs)); + builderItems.add(new ItemStack(Blocks.glass)); + builderItems.add(new ItemStack(Blocks.glass_pane)); + builderItems.add(new ItemStack(Blocks.chest)); + builderItems.add(new ItemStack(Blocks.crafting_table)); + builderItems.add(new ItemStack(Blocks.furnace)); + builderItems.add(new ItemStack(Blocks.lever)); + builderItems.add(new ItemStack(Blocks.wooden_button)); + builderItems.add(new ItemStack(Blocks.stone_button)); + builderItems.add(new ItemStack(Blocks.dispenser)); + builderItems.add(new ItemStack(Blocks.dropper)); + builderItems.add(new ItemStack(Blocks.ladder)); + builderItems.add(new ItemStack(Blocks.fence)); + builderItems.add(new ItemStack(Blocks.fence_gate)); + builderItems.add(new ItemStack(Blocks.iron_bars)); + builderItems.add(new ItemStack(Blocks.stone_slab, 1, Defaults.WILDCARD)); + builderItems.add(new ItemStack(Blocks.quartz_block, 1, Defaults.WILDCARD)); + builderItems.add(new ItemStack(Blocks.quartz_stairs)); + builderItems.add(new ItemStack(Blocks.sandstone_stairs)); + builderItems.add(new ItemStack(Blocks.birch_stairs)); + builderItems.add(new ItemStack(Blocks.spruce_stairs)); + builderItems.add(new ItemStack(Blocks.jungle_stairs)); + builderItems.add(new ItemStack(Blocks.cobblestone_wall, 1, Defaults.WILDCARD)); + builderItems.add(new ItemStack(Items.iron_door)); + builderItems.add(new ItemStack(Items.wooden_door)); + builderItems.add(new ItemStack(Items.sign)); + builderItems.add(new ItemStack(Items.repeater)); + builderItems.add(new ItemStack(Items.comparator)); + builderItems.add(new ItemStack(Items.item_frame)); + } + + @Override + protected void registerRecipes() { + + // Apiarist's Backpack + Proxies.common.addRecipe(ForestryItem.apiaristBackpack.getItemStack(), + new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, 'X', Items.string, 'V', + "stickWood", 'Y', new ItemStack(ForestryBlock.apiculture, 1, Defaults.DEFINITION_APIARISTCHEST_META) }); + // Lepidopterist's Backpack + Proxies.common.addRecipe(ForestryItem.lepidopteristBackpack.getItemStack(), + new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, 'X', Items.string, 'V', + "stickWood", 'Y', new ItemStack(ForestryBlock.lepidopterology, 1, Defaults.DEFINITION_LEPICHEST_META) }); + // Miner's Backpack + Proxies.common.addRecipe(ForestryItem.minerBackpack.getItemStack(), + new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, 'X', Items.string, 'V', + Items.iron_ingot, 'Y', Blocks.chest }); + // Digger's Backpack + Proxies.common.addRecipe(ForestryItem.diggerBackpack.getItemStack(), + new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, 'X', Items.string, 'V', + Blocks.stone, 'Y', Blocks.chest }); + // Forester's Backpack + Proxies.common.addRecipe(ForestryItem.foresterBackpack.getItemStack(), new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, + 'X', Items.string, 'V', "logWood", 'Y', Blocks.chest }); + // Hunter's Backpack + Proxies.common.addRecipe(ForestryItem.hunterBackpack.getItemStack(), + new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, 'X', Items.string, 'V', + Items.feather, 'Y', Blocks.chest }); + // Adventurer's Backpack + Proxies.common.addRecipe(ForestryItem.adventurerBackpack.getItemStack(), new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, + 'X', Items.string, 'V', Items.bone, 'Y', Blocks.chest }); + // Builder's Backpack + Proxies.common.addRecipe(ForestryItem.builderBackpack.getItemStack(), new Object[] { "X#X", "VYV", "X#X", '#', Blocks.wool, + 'X', Items.string, 'V', Items.clay_ball, 'Y', Blocks.chest }); + + // / CARPENTER + // / BACKPACKS T2 + RecipeManagers.carpenterManager.addRecipe(200, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.minerBackpackT2.getItemStack(), + new Object[] { "WXW", "WTW", "WWW", 'X', Items.diamond, 'W', + ForestryItem.craftingMaterial.getItemStack(1, 3), 'T', ForestryItem.minerBackpack }); + RecipeManagers.carpenterManager.addRecipe(200, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.diggerBackpackT2.getItemStack(), + new Object[] { "WXW", "WTW", "WWW", 'X', Items.diamond, 'W', + ForestryItem.craftingMaterial.getItemStack(1, 3), 'T', ForestryItem.diggerBackpack }); + RecipeManagers.carpenterManager.addRecipe(200, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.foresterBackpackT2.getItemStack(), + new Object[] { "WXW", "WTW", "WWW", 'X', Items.diamond, 'W', + ForestryItem.craftingMaterial.getItemStack(1, 3), 'T', ForestryItem.foresterBackpack }); + RecipeManagers.carpenterManager.addRecipe(200, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.hunterBackpackT2.getItemStack(), + new Object[] { "WXW", "WTW", "WWW", 'X', Items.diamond, 'W', + ForestryItem.craftingMaterial.getItemStack(1, 3), 'T', ForestryItem.hunterBackpack }); + RecipeManagers.carpenterManager.addRecipe(200, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.adventurerBackpackT2.getItemStack(), + new Object[] { "WXW", "WTW", "WWW", 'X', Items.diamond, 'W', + ForestryItem.craftingMaterial.getItemStack(1, 3), 'T', ForestryItem.adventurerBackpack }); + RecipeManagers.carpenterManager.addRecipe(200, LiquidHelper.getLiquid(Defaults.LIQUID_WATER, 1000), null, ForestryItem.builderBackpackT2.getItemStack(), + new Object[] { "WXW", "WTW", "WWW", 'X', Items.diamond, 'W', + ForestryItem.craftingMaterial.getItemStack(1, 3), 'T', ForestryItem.builderBackpack }); + + } + + @SuppressWarnings("unchecked") + private void createBackpackArrays() { + + if (BackpackManager.backpackItems != null) + return; + + BackpackManager.backpackItems = new ArrayList[6]; + + BackpackManager.backpackItems[0] = minerItems; + BackpackManager.backpackItems[1] = diggerItems; + BackpackManager.backpackItems[2] = foresterItems; + BackpackManager.backpackItems[3] = hunterItems; + BackpackManager.backpackItems[4] = adventurerItems; + BackpackManager.backpackItems[5] = builderItems; + + } + + @Override + protected void registerCrates() { + } + + private static void parseBackpackItems(String backpackIdent, String list, IBackpackDefinition target) { + String[] parts = list.split("[;]+"); + + for (String part : parts) { + if (part.isEmpty()) + continue; + + String[] ident = part.split("[:]+"); + + if (ident.length != 1 && ident.length != 2) { + Proxies.log.warning("Failed to add block/item of (" + part + ") to "+backpackIdent+" since it isn't formatted properly."); + continue; + } + + Item item = GameData.itemRegistry.getObject(ident[0]); + + if (item == null) { + Block block = GameData.blockRegistry.getObject(ident[0]); + + if (block == null || block == Blocks.air || Item.getItemFromBlock(block) == null) { + Proxies.log.warning("Failed to add block/item of (" + part + ") to "+backpackIdent+" since it couldn't be found."); + continue; + } + + item = Item.getItemFromBlock(block); + } + + int meta = 0; + + if (ident.length > 1) { + meta = ident[1].equals("*") ? OreDictionary.WILDCARD_VALUE : Integer.parseInt(ident[1]); + } + + Proxies.log.finer("Adding block/item of (" + part + ") to "+backpackIdent+"."); + target.addValidItem(new ItemStack(item, 1, meta)); + } + } + + @Override + public ISaveEventHandler getSaveEventHandler() { + return null; + } + + @Override + public IOreDictionaryHandler getDictionaryHandler() { + return this; + } + + @Override + public void onOreRegistration(String name, ItemStack ore) { + + createBackpackArrays(); + + if (ore == null) { + Proxies.log.warning("An ore/item of type %s was registered with the Forge ore dictionary, however the passed itemstack is null. Someone broke it. :(", name); + return; + } + + if (name.startsWith("ingot")) + minerItems.add(ore); + else if (name.startsWith("ore")) + minerItems.add(ore); + else if (name.startsWith("gem")) + minerItems.add(ore); + else if (name.startsWith("dust")) + minerItems.add(ore); + else if (name.startsWith("crystal")) + minerItems.add(ore); + else if (name.matches("dropUranium")) + minerItems.add(ore); + else if (name.equals("treeLeaves") || name.equals("treeSapling") || name.equals("logWood")) + foresterItems.add(ore); + else if (name.equals("stairWood") || name.equals("plankWood") || name.equals("slabWood")) + builderItems.add(ore); + else if (name.startsWith("wood")) + foresterItems.add(ore); + } +} diff --git a/forestry_common/storage/forestry/storage/BackpackDefinition.java b/forestry_common/storage/forestry/storage/BackpackDefinition.java new file mode 100755 index 000000000..c761e7f4d --- /dev/null +++ b/forestry_common/storage/forestry/storage/BackpackDefinition.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage; + +import java.util.ArrayList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.storage.IBackpackDefinition; +import forestry.core.config.Defaults; +import forestry.core.utils.StringUtil; + +public class BackpackDefinition implements IBackpackDefinition { + final String name; + + final int primaryColor; // - c03384 + final int secondaryColor; + + ArrayList validItems = new ArrayList(); + + public BackpackDefinition(String name, int primaryColor) { + this(name, primaryColor, 0xffffff); + } + + public BackpackDefinition(String name, int primaryColor, int secondaryColor) { + this.name = name; + this.primaryColor = primaryColor; + this.secondaryColor = secondaryColor; + } + + @Override + public String getKey() { + return name; + } + + @Override + public String getName() { + return StringUtil.localize("storage.backpack." + name); + } + + @Override + public int getPrimaryColour() { + return primaryColor; + } + + @Override + public int getSecondaryColour() { + return secondaryColor; + } + + public BackpackDefinition setValidItems(ArrayList validItems) { + this.validItems = validItems; + return this; + } + + @Override + public void addValidItem(ItemStack validItem) { + this.validItems.add(validItem); + } + + @Override + public ArrayList getValidItems(EntityPlayer player) { + return validItems; + } + + @Override + public boolean isValidItem(EntityPlayer player, ItemStack itemstack) { + for (ItemStack stack : getValidItems(player)) + if (stack.getItemDamage() == Defaults.WILDCARD) { + if (stack.getItem() == itemstack.getItem()) + return true; + } else if (stack.isItemEqual(itemstack)) + return true; + + return false; + } + +} diff --git a/forestry_common/storage/forestry/storage/BackpackHelper.java b/forestry_common/storage/forestry/storage/BackpackHelper.java new file mode 100755 index 000000000..44c3133e1 --- /dev/null +++ b/forestry_common/storage/forestry/storage/BackpackHelper.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage; + +import net.minecraft.item.Item; + +import forestry.api.storage.BackpackManager; +import forestry.api.storage.EnumBackpackType; +import forestry.api.storage.IBackpackDefinition; +import forestry.api.storage.IBackpackInterface; +import forestry.storage.items.ItemBackpack; + +public class BackpackHelper implements IBackpackInterface { + + @Override + public Item addBackpack(IBackpackDefinition definition, EnumBackpackType type) { + BackpackManager.definitions.put(definition.getKey(), definition); + return new ItemBackpack(definition, type.ordinal() + 1); + } + +} diff --git a/forestry_common/storage/forestry/storage/BackpackMode.java b/forestry_common/storage/forestry/storage/BackpackMode.java new file mode 100755 index 000000000..2b7299320 --- /dev/null +++ b/forestry_common/storage/forestry/storage/BackpackMode.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage; + +public enum BackpackMode { + NORMAL, LOCKED, RECEIVE, RESUPPLY +} diff --git a/forestry_common/storage/forestry/storage/GuiHandlerStorage.java b/forestry_common/storage/forestry/storage/GuiHandlerStorage.java new file mode 100755 index 000000000..fdda27494 --- /dev/null +++ b/forestry_common/storage/forestry/storage/GuiHandlerStorage.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.GuiHandlerBase; +import forestry.core.config.Defaults; +import forestry.core.gui.GuiNaturalistInventory; +import forestry.core.gui.IPagedInventory; +import forestry.core.network.GuiId; +import forestry.core.utils.ItemInventory; +import forestry.storage.gui.ContainerBackpack; +import forestry.storage.gui.ContainerNaturalistBackpack; +import forestry.storage.gui.GuiBackpack; +import forestry.storage.gui.GuiBackpackT2; +import forestry.storage.items.ItemBackpack; + +public class GuiHandlerStorage extends GuiHandlerBase { + + public static class PagedInventory extends ItemInventory implements IPagedInventory { + + //private final int x, y, z; + private final int guiId; + + public PagedInventory(Class itemClass, int size, ItemStack itemstack, int x, int y, int z, int guiId) { + super(itemClass, size, itemstack); + /*this.x = x; + this.y = y; + this.z = z;*/ + this.guiId = guiId; + } + + @Override + public void flipPage(EntityPlayer player, int page) { + onGuiSaved(player); + player.openGui(ForestryAPI.instance, encodeGuiData(guiId, page), player.worldObj, (int) player.posX, (int) player.posY, (int) player.posZ); + } + } + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + int guiData = decodeGuiData(id); + + if (cleanId >= GuiId.values().length) + return null; + + ItemStack equipped; + switch (GuiId.values()[cleanId]) { + + case ApiaristBackpackGUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + ISpeciesRoot speciesRoot = AlleleManager.alleleRegistry.getSpeciesRoot("rootBees"); + PagedInventory inventory = new PagedInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_APIARIST, equipped, x, y, z, cleanId); + return new GuiNaturalistInventory(speciesRoot, player, new ContainerNaturalistBackpack(speciesRoot, player.inventory, inventory, guiData, 25), inventory, guiData, 5); + + case BackpackGUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + return new GuiBackpack(new ContainerBackpack(player, new ItemInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_DEFAULT, equipped))); + + case BackpackT2GUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + return new GuiBackpackT2(new ContainerBackpack(player, new ItemInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_T2, equipped))); + + case LepidopteristBackpackGUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + speciesRoot = AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies"); + inventory = new PagedInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_APIARIST, equipped, x, y, z, id); + return new GuiNaturalistInventory(speciesRoot, player, new ContainerNaturalistBackpack(speciesRoot, player.inventory, inventory, guiData, 25), inventory, guiData, 5); + + default: + return null; + + } + } + + private ItemStack getBackpackItem(EntityPlayer player) { + ItemStack equipped = getEquippedItem(player); + if (equipped == null) + return null; + if (equipped.getItem() instanceof ItemBackpack) + return equipped; + return null; + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + int cleanId = decodeGuiID(id); + int guiData = decodeGuiData(id); + + if (cleanId >= GuiId.values().length) + return null; + + ItemStack equipped; + switch (GuiId.values()[cleanId]) { + + case ApiaristBackpackGUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + + ISpeciesRoot speciesRoot = AlleleManager.alleleRegistry.getSpeciesRoot("rootBees"); + speciesRoot.getBreedingTracker(world, player.getGameProfile().getId()).synchToPlayer(player); + return new ContainerNaturalistBackpack(speciesRoot, player.inventory, new PagedInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_APIARIST, equipped, x, y, z, cleanId), guiData, 25); + + case BackpackGUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + + return new ContainerBackpack(player, new ItemInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_DEFAULT, equipped)); + + case BackpackT2GUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + + return new ContainerBackpack(player, new ItemInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_T2, equipped)); + + case LepidopteristBackpackGUI: + equipped = getBackpackItem(player); + if (equipped == null) + return null; + + speciesRoot = AlleleManager.alleleRegistry.getSpeciesRoot("rootButterflies"); + speciesRoot.getBreedingTracker(world, player.getGameProfile().getId()).synchToPlayer(player); + return new ContainerNaturalistBackpack(speciesRoot, player.inventory, new PagedInventory(ItemBackpack.class, Defaults.SLOTS_BACKPACK_APIARIST, equipped, x, y, z, cleanId), guiData, 25); + + default: + return null; + + } + } +} diff --git a/forestry_common/storage/forestry/storage/PickupHandlerStorage.java b/forestry_common/storage/forestry/storage/PickupHandlerStorage.java new file mode 100755 index 000000000..7ebafc0a5 --- /dev/null +++ b/forestry_common/storage/forestry/storage/PickupHandlerStorage.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.core.gui.ContainerNaturalistInventory; +import forestry.core.interfaces.IPickupHandler; +import forestry.storage.gui.ContainerBackpack; +import forestry.storage.items.ItemBackpack; + +public class PickupHandlerStorage implements IPickupHandler { + + @Override + public boolean onItemPickup(EntityPlayer player, EntityItem entityitem) { + + ItemStack itemstack = entityitem.getEntityItem(); + if (itemstack == null || itemstack.stackSize <= 0) + return false; + + // Do not pick up if a backpack is open // FIXME: Must not contain + // anything from apiculture + if (player.openContainer instanceof ContainerBackpack || player.openContainer instanceof ContainerNaturalistInventory) + return true; + + // Make sure to top off manually placed itemstacks in player + // inventory first + topOffPlayerInventory(player, itemstack); + + for (ItemStack pack : player.inventory.mainInventory) { + + if (pack == null || pack.stackSize <= 0) + continue; + + if (itemstack == null || itemstack.stackSize <= 0) + break; + + if (!(pack.getItem() instanceof ItemBackpack)) + continue; + + ItemBackpack backpack = ((ItemBackpack) pack.getItem()); + if (backpack.getDefinition().isValidItem(player, itemstack)) + backpack.tryStowing(player, pack, itemstack); + } + + if (itemstack == null || itemstack.stackSize <= 0) + return false; + else + return true; + } + + /** + * This tops off existing stacks in the player's inventory. That way you can keep f.e. a stack of dirt or cobblestone in your inventory which gets refreshed + * constantly by picked up items. + * + * @param player + * @param itemstack + */ + private void topOffPlayerInventory(EntityPlayer player, ItemStack itemstack) { + + // Add to player inventory first, if there is an incomplete stack in + // there. + for (int i = 0; i < player.inventory.getSizeInventory(); i++) { + ItemStack inventoryStack = player.inventory.getStackInSlot(i); + // We only add to existing stacks. + if (inventoryStack == null) + continue; + + // Already full + if (inventoryStack.stackSize >= inventoryStack.getMaxStackSize()) + continue; + + if (inventoryStack.isItemEqual(itemstack) && ItemStack.areItemStackTagsEqual(inventoryStack, itemstack)) { + int space = inventoryStack.getMaxStackSize() - inventoryStack.stackSize; + + // Enough space to add all + if (space > itemstack.stackSize) { + inventoryStack.stackSize += itemstack.stackSize; + itemstack.stackSize = 0; + itemstack = null; + break; + // Only part can be added + } else { + inventoryStack.stackSize = inventoryStack.getMaxStackSize(); + itemstack.stackSize -= space; + } + } + } + + } + +} diff --git a/forestry_common/storage/forestry/storage/ResupplyHandler.java b/forestry_common/storage/forestry/storage/ResupplyHandler.java new file mode 100755 index 000000000..79a602d71 --- /dev/null +++ b/forestry_common/storage/forestry/storage/ResupplyHandler.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ContainerPlayer; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.eventhandler.Event; + +import net.minecraftforge.common.MinecraftForge; + +import forestry.api.storage.BackpackManager; +import forestry.api.storage.BackpackResupplyEvent; +import forestry.api.storage.IBackpackDefinition; +import forestry.core.interfaces.IResupplyHandler; +import forestry.core.utils.ItemInventory; +import forestry.storage.items.ItemBackpack; + +public class ResupplyHandler implements IResupplyHandler { + + @Override + public void resupply(EntityPlayer player) { + + // Do not attempt resupplying if this backpack is already opened. + if (!(player.openContainer instanceof ContainerPlayer)) + return; + + for (IBackpackDefinition backpack : BackpackManager.definitions.values()) + resupply(backpack, player); + + } + + public void resupply(IBackpackDefinition backpackItem, EntityPlayer player) { + + // Get all backpacks of this type in the player's inventory + for (ItemStack backpack : player.inventory.mainInventory) { + + if (backpack == null || backpack.stackSize <= 0) + continue; + + if (!(backpack.getItem() instanceof ItemBackpack)) + continue; + + // Only handle those in resupply mode + if (ItemBackpack.getMode(backpack) != BackpackMode.RESUPPLY) + continue; + + // Delay before resupplying + if (backpack.getItemDamage() < 40) { + backpack.setItemDamage(backpack.getItemDamage() + 1); + continue; + } + + // Load their inventory + ItemBackpack packItem = ((ItemBackpack) backpack.getItem()); + ItemInventory backpackinventory = new ItemInventory(ItemBackpack.class, packItem.getBackpackSize(), backpack); + Event event = new BackpackResupplyEvent(player, packItem.getDefinition(), backpackinventory); + MinecraftForge.EVENT_BUS.post(event); + if (event.isCanceled()) + continue; + + boolean inventoryChanged = false; + // Cycle through their contents + for (int i = 0; i < backpackinventory.getSizeInventory(); i++) { + + ItemStack packstack = backpackinventory.getStackInSlot(i); + if (packstack == null) + continue; + if (packstack.stackSize <= 0) + continue; + + // Try to add it to the player's inventory and note any change + boolean change = topOffPlayerInventory(player, packstack); + if (!inventoryChanged) + inventoryChanged = change; + + // Clear consumed stacks + if (packstack.stackSize <= 0) + backpackinventory.setInventorySlotContents(i, null); + } + // Save the backpack inventory if it changed + if (inventoryChanged) + backpackinventory.onGuiSaved(player); + + } + } + + /** + * This tops off existing stacks in the player's inventory. + * + * @param player + * @param itemstack + */ + private boolean topOffPlayerInventory(EntityPlayer player, ItemStack itemstack) { + + // Add to player inventory first, if there is an incomplete stack in + // there. + for (int i = 0; i < player.inventory.getSizeInventory(); i++) { + ItemStack inventoryStack = player.inventory.getStackInSlot(i); + // We only add to existing stacks. + if (inventoryStack == null) + continue; + + // Already full + if (inventoryStack.stackSize >= inventoryStack.getMaxStackSize()) + continue; + + if (inventoryStack.isItemEqual(itemstack) && ItemStack.areItemStackTagsEqual(inventoryStack, itemstack)) { + + inventoryStack.stackSize++; + itemstack.stackSize--; + if (itemstack.stackSize <= 0) + itemstack = null; + return true; + } + } + return false; + + } + +} diff --git a/forestry_common/storage/forestry/storage/gui/ContainerBackpack.java b/forestry_common/storage/forestry/storage/gui/ContainerBackpack.java new file mode 100755 index 000000000..8470cd121 --- /dev/null +++ b/forestry_common/storage/forestry/storage/gui/ContainerBackpack.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.core.config.Defaults; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.utils.ItemInventory; +import forestry.storage.items.ItemBackpack; + +public class ContainerBackpack extends ContainerItemInventory { + + public ContainerBackpack(EntityPlayer player, ItemInventory inventory) { + super(inventory, player); + + int lines = 0; + int columns = 0; + int startX = 0; + int startY = 0; + if (inventory.getSizeInventory() == Defaults.SLOTS_BACKPACK_DEFAULT) { + lines = 3; + columns = 5; + startX = 44; + startY = 19; + } else if (inventory.getSizeInventory() == Defaults.SLOTS_BACKPACK_T2) { + lines = 5; + columns = 9; + startX = 8; + startY = 8; + } + + // Inventory + for (int j = 0; j < lines; j++) + for (int k = 0; k < columns; k++) { + int slot = k + j * columns; + addSlot(new SlotCustom(inventory, ((ItemBackpack) inventory.parent.getItem()).getValidItems(player), slot, startX + k * 18, startY + j * 18)); + } + + // Player inventory + for (int i = 0; i < 3; i++) + for (int j = 0; j < 9; j++) + addSecuredSlot(player.inventory, j + i * 9 + 9, 8 + j * 18, 11 + startY + lines * 18 + i * 18); + // Player hotbar + for (int i = 0; i < 9; i++) + addSecuredSlot(player.inventory, i, 8 + i * 18, 11 + startY + lines * 18 + 58); + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + // FIXME: This is incorrect. + // However, if we return false here, even valid items will be dropped + // while being kept inside the backpack, leading to duping. + // inventory.parent will turn null with the current implementation if + // something is put inside a backpack and the backpack is then + // moved from the action bar into the player's inventory. + if (inventory.parent == null) + return true; + + if (!(inventory.parent.getItem() instanceof ItemBackpack)) + return false; + + return ((ItemBackpack) inventory.parent.getItem()).getDefinition().isValidItem(player, stack); + } + +} diff --git a/forestry_common/storage/forestry/storage/gui/ContainerNaturalistBackpack.java b/forestry_common/storage/forestry/storage/gui/ContainerNaturalistBackpack.java new file mode 100755 index 000000000..64268f617 --- /dev/null +++ b/forestry_common/storage/forestry/storage/gui/ContainerNaturalistBackpack.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.ISpeciesRoot; +import forestry.core.gui.ContainerItemInventory; +import forestry.core.gui.IGuiSelectable; +import forestry.core.gui.slots.SlotCustom; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.storage.GuiHandlerStorage.PagedInventory; + +public class ContainerNaturalistBackpack extends ContainerItemInventory implements IGuiSelectable { + + private final PagedInventory inv; + private ISpeciesRoot speciesRoot; + + public ContainerNaturalistBackpack(ISpeciesRoot speciesRoot, InventoryPlayer player, PagedInventory inventory, int page, int pageSize) { + super(inventory, player.player); + + this.inv = inventory; + this.speciesRoot = speciesRoot; + + // Inventory + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) { + addSlot(new SlotCustom(inventory, y + page * pageSize + x * 5, 100 + y * 18, 21 + x * 18, new Object[] { speciesRoot })); + } + } + + // Player inventory + for (int i1 = 0; i1 < 3; i1++) { + for (int l1 = 0; l1 < 9; l1++) { + addSecuredSlot(player, l1 + i1 * 9 + 9, 18 + l1 * 18, 120 + i1 * 18); + } + } + // Player hotbar + for (int j1 = 0; j1 < 9; j1++) { + addSecuredSlot(player, j1, 18 + j1 * 18, 178); + } + } + + @Override + public void purgeBag(EntityPlayer player) { + for (int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if (stack == null) + continue; + + if (speciesRoot.isMember(stack)) + continue; + + Proxies.common.dropItemPlayer(player, stack); + inventory.setInventorySlotContents(i, null); + } + } + + @Override + protected boolean isAcceptedItem(EntityPlayer player, ItemStack stack) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void handleSelectionChange(EntityPlayer player, PacketUpdate packet) { + inv.flipPage(player, packet.payload.intPayload[0]); + } + + @Override + public void setSelection(PacketUpdate packet) { + } +} diff --git a/forestry_common/storage/forestry/storage/gui/GuiBackpack.java b/forestry_common/storage/forestry/storage/gui/GuiBackpack.java new file mode 100755 index 000000000..bf706b83f --- /dev/null +++ b/forestry_common/storage/forestry/storage/gui/GuiBackpack.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage.gui; + +import forestry.core.config.Defaults; +import forestry.core.gadgets.TileForestry; +import forestry.core.gui.ContainerForestry; +import forestry.core.gui.GuiForestry; + +public class GuiBackpack extends GuiForestry { + + public GuiBackpack(ContainerForestry container) { + this(Defaults.TEXTURE_PATH_GUI + "/backpack.png", container); + } + + protected GuiBackpack(String texture, ContainerForestry container) { + super(texture, container); + } + + @Override + protected boolean checkHotbarKeys(int key) { + return false; + } +} diff --git a/forestry_common/storage/forestry/storage/gui/GuiBackpackT2.java b/forestry_common/storage/forestry/storage/gui/GuiBackpackT2.java new file mode 100755 index 000000000..06e2a6657 --- /dev/null +++ b/forestry_common/storage/forestry/storage/gui/GuiBackpackT2.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage.gui; + + +import forestry.core.config.Defaults; +import forestry.core.gui.ContainerForestry; + +public class GuiBackpackT2 extends GuiBackpack { + + public GuiBackpackT2(ContainerForestry container) { + super(Defaults.TEXTURE_PATH_GUI + "/backpackT2.png", container); + + xSize = 176; + ySize = 192; + } +} diff --git a/forestry_common/storage/forestry/storage/items/ItemBackpack.java b/forestry_common/storage/forestry/storage/items/ItemBackpack.java new file mode 100755 index 000000000..eb60fd6ce --- /dev/null +++ b/forestry_common/storage/forestry/storage/items/ItemBackpack.java @@ -0,0 +1,351 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage.items; + +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +import cpw.mods.fml.common.eventhandler.Event; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.core.ForestryAPI; +import forestry.api.storage.BackpackStowEvent; +import forestry.api.storage.EnumBackpackType; +import forestry.api.storage.IBackpackDefinition; +import forestry.core.config.Defaults; +import forestry.core.inventory.InvTools; +import forestry.core.inventory.wrappers.IInvSlot; +import forestry.core.inventory.wrappers.InventoryIterator; +import forestry.core.items.ItemInventoried; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.core.render.TextureManager; +import forestry.core.utils.ItemInventory; +import forestry.core.utils.StringUtil; +import forestry.storage.BackpackMode; + +public class ItemBackpack extends ItemInventoried { + + IBackpackDefinition info; + byte type; + + public ItemBackpack(IBackpackDefinition info, int type) { + super(); + this.info = info; + this.type = (byte) type; + setMaxStackSize(1); + } + + public IBackpackDefinition getDefinition() { + return info; + } + + /** + * @return true if the item's stackTagCompound needs to be synchronized over + * SMP. + */ + @Override + public boolean getShareTag() { + return true; + } + + @Override + public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer player) { + + if (!Proxies.common.isSimulating(world)) + return itemstack; + + if (!player.isSneaking()) + openGui(player, itemstack); + else + switchMode(itemstack); + return itemstack; + + } + + @Override + public boolean onItemUse(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { + if (getInventoryHit(world, x, y, z, side) != null) + return true; + else + return false; + } + + @Override + public boolean onItemUseFirst(ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { + + if (!Proxies.common.isSimulating(world)) + return false; + + // We only do this when shift is clicked + if (!player.isSneaking()) + return false; + + return evaluateTileHit(itemstack, player, world, x, y, z, side, hitX, hitY, hitZ); + } + + public ItemStack tryStowing(EntityPlayer player, ItemStack backpackStack, ItemStack stack) { + + ItemBackpack backpack = ((ItemBackpack) backpackStack.getItem()); + ItemInventory inventory = new ItemInventory(ItemBackpack.class, backpack.getBackpackSize(), backpackStack); + if (backpackStack.getItemDamage() == 1) + return stack; + + Event event = new BackpackStowEvent(player, backpack.getDefinition(), inventory, stack); + MinecraftForge.EVENT_BUS.post(event); + if (stack.stackSize <= 0) + return null; + if (event.isCanceled()) + return stack; + + ItemStack remainder = InvTools.moveItemStack(stack, inventory); + stack.stackSize = remainder == null ? 0 : remainder.stackSize; + + inventory.save(); + return null; + } + + private void switchMode(ItemStack itemstack) { + BackpackMode mode = getMode(itemstack); + if (mode == BackpackMode.RESUPPLY) + itemstack.setItemDamage(0); + else if (mode == BackpackMode.RECEIVE) + itemstack.setItemDamage(3); + else if (mode == BackpackMode.LOCKED) + itemstack.setItemDamage(2); + else + itemstack.setItemDamage(1); + } + + private IInventory getInventoryHit(World world, int x, int y, int z, int side) { + TileEntity targeted = world.getTileEntity(x, y, z); + return InvTools.getInventoryFromTile(targeted, ForgeDirection.getOrientation(side)); + } + + private boolean evaluateTileHit(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { + + // Shift right-clicking on an inventory tile will attempt to transfer + // items contained in the backpack + IInventory inventory = getInventoryHit(world, x, y, z, side); + // Process only inventories + if (inventory != null) { + + // Must have inventory slots + if (inventory.getSizeInventory() <= 0) + return true; + + // Create our own backpack inventory + ItemInventory backpackInventory = new ItemInventory(ItemBackpack.class, getBackpackSize(), stack); + + if (stack.getItemDamage() == 2) + tryChestReceive(player, backpackInventory, inventory); + else + tryChestTransfer(backpackInventory, inventory); + + backpackInventory.save(); + + return true; + } + + return false; + } + + private void tryChestTransfer(ItemInventory backpackInventory, IInventory target) { + + for (IInvSlot slot : InventoryIterator.getIterable(backpackInventory)) { + ItemStack packStack = slot.getStackInSlot(); + if (packStack == null) + continue; + + ItemStack remaining = InvTools.moveItemStack(packStack, target); + slot.setStackInSlot(remaining); + } + } + + private void tryChestReceive(EntityPlayer player, ItemInventory backpackInventory, IInventory target) { + + for (IInvSlot slot : InventoryIterator.getIterable(target)) { + ItemStack targetStack = slot.getStackInSlot(); + if (targetStack == null) + continue; + + if(!info.isValidItem(player, targetStack)) + continue; + + ItemStack remaining = InvTools.moveItemStack(targetStack, backpackInventory); + slot.setStackInSlot(remaining); + } + + } + + public void openGui(EntityPlayer entityplayer, ItemStack itemstack) { + if (getBackpackSize() == Defaults.SLOTS_BACKPACK_DEFAULT) + entityplayer.openGui(ForestryAPI.instance, GuiId.BackpackGUI.ordinal(), entityplayer.worldObj, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + else if (getBackpackSize() == Defaults.SLOTS_BACKPACK_T2) + entityplayer.openGui(ForestryAPI.instance, GuiId.BackpackT2GUI.ordinal(), entityplayer.worldObj, (int) entityplayer.posX, (int) entityplayer.posY, + (int) entityplayer.posZ); + } + + public boolean isBackpack(ItemStack stack) { + if (stack == null) + return false; + + return stack.getItem() == this; + } + + public Collection getValidItems(EntityPlayer player) { + return info.getValidItems(player); + } + + public int getBackpackSize() { + return getSlotsForType(type); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack itemstack, EntityPlayer player, List list, boolean flag) { + ItemInventory inventory = new ItemInventory(ItemBackpack.class, getBackpackSize(), itemstack); + + // HashMap contents = new HashMap(); + int occupied = 0; + + for (int i = 0; i < inventory.getSizeInventory(); i++) { + if (inventory.getStackInSlot(i) == null) + continue; + if (inventory.getStackInSlot(i).stackSize <= 0) + continue; + + // Count the slot as occupied + occupied++; + } + + BackpackMode mode = getMode(itemstack); + if (mode == BackpackMode.LOCKED) + list.add("(LOCKED)"); + else if (mode == BackpackMode.RECEIVE) + list.add("(RECEIVING)"); + else if (mode == BackpackMode.RESUPPLY) + list.add("(RESUPPLY)"); + list.add(occupied + "/" + getBackpackSize() + " " + StringUtil.localize("gui.slots")); + + } + + @Override + public String getItemStackDisplayName(ItemStack itemstack) { + if (type > 1) + return StringUtil.localize("storage.backpack.t2adj") + " " + info.getName(); + else + return info.getName(); + } + + /* ICONS */ + @SideOnly(Side.CLIENT) + private IIcon[][] icons; + + @SideOnly(Side.CLIENT) + @Override + public void registerIcons(IIconRegister register) { + icons = new IIcon[EnumBackpackType.values().length][6]; + + for (int i = 0; i < EnumBackpackType.values().length; i++) { + icons[i][0] = TextureManager.getInstance().registerTex( + register, "backpacks/" + EnumBackpackType.values()[i].toString().toLowerCase(Locale.ENGLISH) + ".cloth"); + icons[i][1] = TextureManager.getInstance().registerTex( + register, "backpacks/" + EnumBackpackType.values()[i].toString().toLowerCase(Locale.ENGLISH) + ".outline"); + icons[i][2] = TextureManager.getInstance().registerTex(register, "backpacks/neutral"); + icons[i][3] = TextureManager.getInstance().registerTex(register, "backpacks/locked"); + icons[i][4] = TextureManager.getInstance().registerTex(register, "backpacks/receive"); + icons[i][5] = TextureManager.getInstance().registerTex(register, "backpacks/resupply"); + } + } + + // Return true to enable color overlay - client side only + @Override + public boolean requiresMultipleRenderPasses() { + return true; + } + + @Override + public int getRenderPasses(int metadata) { + return 3; + } + + @Override + public int getColorFromItemStack(ItemStack itemstack, int j) { + + if (j == 0) + return info.getPrimaryColour(); + else if (j == 1) + return info.getSecondaryColour(); + else + return 0xffffff; + } + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamageForRenderPass(int i, int j) { + + int iconType = type; + if (type > 0) + iconType--; + + if (j == 0) + return icons[iconType][0]; + if (j == 1) + return icons[iconType][1]; + + if (i > 2) + return icons[iconType][5]; + else if (i > 1) + return icons[iconType][4]; + else if (i > 0) + return icons[iconType][3]; + else + return icons[iconType][2]; + } + + public static int getSlotsForType(int type) { + switch (type) { + case 0: + return Defaults.SLOTS_BACKPACK_APIARIST; + case 2: + return Defaults.SLOTS_BACKPACK_T2; + case 1: + default: + return Defaults.SLOTS_BACKPACK_DEFAULT; + } + } + + public static BackpackMode getMode(ItemStack backpack) { + int meta = backpack.getItemDamage(); + + if (meta >= 3) + return BackpackMode.RESUPPLY; + else if (meta >= 2) + return BackpackMode.RECEIVE; + else if (meta >= 1) + return BackpackMode.LOCKED; + else + return BackpackMode.NORMAL; + } +} diff --git a/forestry_common/storage/forestry/storage/items/ItemNaturalistBackpack.java b/forestry_common/storage/forestry/storage/items/ItemNaturalistBackpack.java new file mode 100755 index 000000000..41af04866 --- /dev/null +++ b/forestry_common/storage/forestry/storage/items/ItemNaturalistBackpack.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.storage.items; + +import java.util.ArrayList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import forestry.api.core.ForestryAPI; +import forestry.plugins.PluginApiculture; +import forestry.plugins.PluginLepidopterology; +import forestry.storage.BackpackDefinition; + +public class ItemNaturalistBackpack extends ItemBackpack { + + public static class BackpackDefinitionApiarist extends BackpackDefinition { + + public BackpackDefinitionApiarist(String name, int primaryColor) { + super(name, primaryColor); + } + + @Override + public boolean isValidItem(EntityPlayer player, ItemStack stack) { + return PluginApiculture.beeInterface.isMember(stack); + } + } + + public static class BackpackDefinitionLepidopterist extends BackpackDefinition { + + public BackpackDefinitionLepidopterist(String name, int primaryColor) { + super(name, primaryColor); + } + + @Override + public boolean isValidItem(EntityPlayer player, ItemStack stack) { + return PluginLepidopterology.butterflyInterface.isMember(stack); + } + } + private final int guiId; + + public ItemNaturalistBackpack(int guiId, BackpackDefinition definition) { + super(definition, 0); + this.guiId = guiId; + } + + @Override + public void openGui(EntityPlayer player, ItemStack itemstack) { + player.openGui(ForestryAPI.instance, guiId, player.worldObj, (int) player.posX, (int) player.posY, (int) player.posZ); + } + + @Override + public ArrayList getValidItems(EntityPlayer player) { + return null; + } +} diff --git a/forestry_resources/CREDITS.txt b/forestry_resources/CREDITS.txt new file mode 100755 index 000000000..5d9c630f7 --- /dev/null +++ b/forestry_resources/CREDITS.txt @@ -0,0 +1,27 @@ + +Forestry for Minecraft +CREDITS + +I'd like to thank and mention the following people who helped in the making of this mod or whose own work made it possible: + +MCP Team, Searge - MCP, without which modding Minecraft would be a pain +SpaceToad - Minecraft Forge, BuildCraft +CPW - FML, Forge +IC2 Team - IndustrialCraft 2 API +Eloraam - Minecraft Forge +LexManos - Minecraft Forge +Krapht - Input and generally being a great guy. +Pahimar - Input, BeeFX and see above. +Binnie - Addons, bugfixes +Mistaqur - Bugfixes, NEI plugin +Player - Input, general coding help, helping fix my EU net derps. +Maeyanie - Bukkit porting +Dariys - Testing, testing, testing and some more testing! +Direwolf20 - Mod spotlights +Stylez84 - Mod spotlight and testing +Crocodine - Flowcharts/Diagrams +Ineedabettername - Testing +Killgore - Testing +Headhunter67 - Testing +V4sh - Sprite contribution and testing +jimeowan - Original localization class \ No newline at end of file diff --git a/forestry_resources/README.txt b/forestry_resources/README.txt new file mode 100755 index 000000000..bfa57ea9a --- /dev/null +++ b/forestry_resources/README.txt @@ -0,0 +1,17 @@ + +Forestry for Minecraft +====================== + +Please refer to Forestry's thread on the Minecraft forums: +http://www.minecraftforum.net/topic/700588-181-forestry-for-minecraft/page__p__9486882 + +Forestry Wiki: +http://forestry.sengir.net/wiki/ + + +License: +---------- + +The code of "Forestry for Minecraft" in source or binary form is the intellectual property of SirSengir. +It may not be reproduced, redistributed or modified. If you have other plans, ask first. + diff --git a/forestry_resources/assets/forestry/logo.png b/forestry_resources/assets/forestry/logo.png new file mode 100755 index 0000000000000000000000000000000000000000..bfa3bc0f854657826335d83bc7c3dea3688f6ef1 GIT binary patch literal 27326 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 HN@xNA-beo4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/analyzer_pedestal.png b/forestry_resources/assets/forestry/textures/blocks/analyzer_pedestal.png new file mode 100755 index 0000000000000000000000000000000000000000..6d9275c99fc67a65a08ab3342cbad807010accc8 GIT binary patch literal 1129 zcmV-v1eW`WP)H^(d{d(Jo1ib=6T+)XUs;UQNRK=91h{V zhjR{$F>uboIfwTioO1v`UDpVqy^Rn8Qc6rF6FBEk*EO7T2qC~ZM{_vm^f}M2udf$5 zJ|q@2Yb}jK2t-CS@BKaS&G}8xAp{yT#=sb(xsiakt@j`VH0}8K7}Mz#Ns>THiLxxw z>-FZ&JvurfFilY2dsu7XoP(4SLI`?h312A!uCA`Iy}b=%4AL~ENXYa2-rS3e3yOf4 zA^>o3aDcKb38a(~oO3Y7kftf>x`vbzqtU1p6^j^OCY#n;FvbumklLk|d$=ynKG~*(L-R$a)H# zbGX_=NRHDV{siY7X_~H13e}Zg1~?TNK68z%RWB0zjVU9iFAv317r*^jSb zjQJO6(Mq$J0%@8qMF%W}0OuUavV<{)RG{}BT5A|%$kT6ORDb8!nnV`-|~EvxhE$l6dAEzMBSj2qP=FkDcD5dTdvq(g|8$^u}zmF*vJHs+AMGF&9RTX(7f{$L3Qo>r> zI%w?sasIrv=Di1F40)cnh>BNjYb~Udt(5q$#%^wI!fakf)fP8pjN#d{-|^(hEByA! zH%PwD@XJRR&{|XfjzVX4tqAVB;Se7`evHGv>lPpnQ3L^UL6@QrP$1}&_=WlaMGB)+mNe*|!Bh5h zs*wn~@z%lNsc0h|YXR1oi~vRe zBY+XWeg=DZcnEHT#uzx~5JeF<=djkoS_{rO<)oC9_i=G?0RT`+K?niH7`T?q7RDH~Hu&*%g(zB)$Pb_2t__F( zwH&3?ARzF5+51>57T}x*;``ynYpvm&qg7pl=;-;c2ebgNC0Hpnj0)&acClFCV3JQyPcX(n2tlUioP*YyAWA8qwMHDrWS&wAIOo6^gOqX*!U;fMd{tFAJ3B)Z zMbKIYVESh0O;Br1IjuDqV-SK-sryRtjh z5L-fxG03tkI4OL^Y>wY404XJ{*rv(d+}z;&{2XOjqAW{lg!(J%#l&$Od~w^hV2mM6 z)2*I?G4^U7F_>1kZChMkUQ%b+KlXfA=*0*j5Jk}optT3|o2ERUlHj_op_GC#W;myS zkE5d_JU>4}DYdnKvn<2a)fMGA=j0RK-KCVs^9=7lrR!!WpJ4W8y?xR&MP1iH4=@B1 z6uzX7kB?!kg;EM_+XjQ;I1ZYaf3?Ctzm;g3<^|Gk93CD9TdTkSU+XjeI{U|%}#EE<9~zW4e}ta^ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/analyzer_tower2.png b/forestry_resources/assets/forestry/textures/blocks/analyzer_tower2.png new file mode 100755 index 0000000000000000000000000000000000000000..9b1889102406fc70c52fdbee849d2f00d69497c8 GIT binary patch literal 982 zcmV;{11bE8P)U&xp;< zP0tNB$qly#Km(uw&;V!vGyoa^4S)tf1E2wLGff;E9C+s(gTdh6i$Va%(_nx}0@&5d!ay%a6oI^@Unx;r85kla-M=6Dr)692vcCHnG4uM^? z5Kvi`09^Jd%MxQu49t5^RaJQJqi;BtQc@HJ#+V3co=ji9@WID#Q4}S0?P#@9v{sy) zB>eLIUsoVWDXHt4s;U53U0sdG0KHz1g@px1qY-(YBZOdWZEd~*0Q~&jF;!K?6n_81 z&J`c$T-~zHCKKwqp05m$QeLU?AXHUVy@CN+ z>nT4WL=-_OC1+=693LOEc;^mQDLSvpB)fl~Qz0;ANtR{v*9L_Ulx2yv7Hch|(HWD; zge=SAZoPbYuIwRwLk9?-p!~gFkEc(6U2bSZn8V4w#ja-g~UI zD5W9<=N!fuwAKhA&{{_k4DGMm?UH5RaO>9JaZS7ZEw^v~8C&aIc7e;iIheJUZnqmB zUI-C=Ll+Q2Oa*uM?j}MAj7ccVl6&`lLMcU>z7f~WYQ5K50!pdZik!6;V{|;9Nl|Os z?KXLy^VOSQv+?_vWLd`6))wpO7ku{X=cH*GOXafGTq}U^5U+#aoFhqQ0|3nBhrTRJ27>`rRWbOe7r%V|d`y}el0-B7 z@deH~hQr~Nfe2uCcQ*nHyKJpxadDAWs|CQ)($dsgV+?zHd)KQ07i(B+&DIYmF@O-9 zQVJmid7d+?ZECGqUS6IWhozJxNfOVUb5k>bF=jqQFerT(ev%}iD2k~1A@z+hOeT}q z`Yr|%)`oHlT>_veimCDmr7|~fgUx?~%?~0CfE#W9070e3J#Pr48UO$Q07*qoM6N<$ Ef?yV}%>V!Z literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiaristchest.0.png b/forestry_resources/assets/forestry/textures/blocks/apiaristchest.0.png new file mode 100755 index 0000000000000000000000000000000000000000..7ff8f73b84c3954d1c88112fa1678cd46319701e GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>%0fWV@x!d{4KfslJ+-zN(plnuWfqk*?bR|Noh~-=70&XH4>T zcM+JniB|{6;VkfoEM{Qf76M_$OLy!300pBxT^vIsF1Pjsavf0Mah|_x?bT~<|81YE z#B-&e^;1+v5QpM2<)as#&(w1%);v5{A@}M-zYRtwuXi1Ynz&PGM;14~`L9_F`>Nli z`2YDUu*z>$wbHKpY1?=1woTjPb)93T*e3oJKxTq8hE zxvr5xh@qjCsezTLv9^Jcm4SiAlcPZONE&kUQ!>*kK^ly84UBY+Ohb%}tc=aAOiZ;6 v41pSI{JpmVH3))iNXyJg%}dNpwJHHJ7|i3%mGz9+K*o8x`njxgN@xNA3;uy1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiaristchest.1.png b/forestry_resources/assets/forestry/textures/blocks/apiaristchest.1.png new file mode 100755 index 0000000000000000000000000000000000000000..dd65182e05d0f0b7b3156d87a8024458a88c9dcb GIT binary patch literal 503 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>8>%0fWV@x!d{4LKfv^97;LR+_7gw`P_0=|CyS=$e!%ScG#R(BJ z12qeMRU=)s|Ns9#dA2GEXeMKlx4Vlt_q7@QKn`btM`SSr1Gf+eGhVt|_XjB0>*?Yc zB5^six0CO%0*~|Mi;kzJHkbYXztZ@v+Ex#~u8s08r?WXzG+VfJZn zkz QJR`_BPgg&ebxsLQ0EOVHb^rhX literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiaristchest.2.png b/forestry_resources/assets/forestry/textures/blocks/apiaristchest.2.png new file mode 100755 index 0000000000000000000000000000000000000000..0c09eb6d291ed83e3996dbd29d4c07ce1fc804aa GIT binary patch literal 467 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>#6SPwmdS)RzpR0OPjfije(Y`thSoGnZBx-fttCYy1b0|%p!xyxw@`4`dVsoI;yf- zs&eYea*DFz|NsBr;q|lvXeMKlx4Vlt_q7@QKn`btM`SSr1Gf+eGhVt|_XjAL;pyTS zB5}FZH(IDcfg|Ry(V0_SyZ#3{SD(p{KgeW!#*SeztBKW0jty%=ZSFFji<%zyuI|gs z4@N&G?x?om;Z8F8qs+PD$l%ynM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiaristchest.3.png b/forestry_resources/assets/forestry/textures/blocks/apiaristchest.3.png new file mode 100755 index 0000000000000000000000000000000000000000..10c084edabf28877ed340d197e71014964d3cc98 GIT binary patch literal 531 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>>&gDGrCm$Zz-eY%|dSULA7N%ygr#qweJ9@L;TexPziKzz}odg5wm#ng2 zbm)10`m0#-p5``#B_=9T)mrj98_k}x_xhh&pHrBn=W_Pw8a?e+SKehD+hnRQaUQaN zSzW()^%Ci$?UiZoZS~J|f6@OK#*vX=o%s&vCe;$xh?11Vl2ohYqEsNoU}Ruuq-$WV zYh(~&XlP|>U}b8oZD3?&V4(5jC{R6;hTQy=%(P0724h_VBV8lY5F;ZiV{2xGILV%5_40nN`MRo^LUHR6ZNNqjPrE$b6Mw<&;$SmbFLo% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiaristchest.4.png b/forestry_resources/assets/forestry/textures/blocks/apiaristchest.4.png new file mode 100755 index 0000000000000000000000000000000000000000..0c09eb6d291ed83e3996dbd29d4c07ce1fc804aa GIT binary patch literal 467 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>#6SPwmdS)RzpR0OPjfije(Y`thSoGnZBx-fttCYy1b0|%p!xyxw@`4`dVsoI;yf- zs&eYea*DFz|NsBr;q|lvXeMKlx4Vlt_q7@QKn`btM`SSr1Gf+eGhVt|_XjAL;pyTS zB5}FZH(IDcfg|Ry(V0_SyZ#3{SD(p{KgeW!#*SeztBKW0jty%=ZSFFji<%zyuI|gs z4@N&G?x?om;Z8F8qs+PD$l%ynM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiary.0.png b/forestry_resources/assets/forestry/textures/blocks/apiary.0.png new file mode 100755 index 0000000000000000000000000000000000000000..9f6ddee034f5122adfd6826e7dc3dfe4807ca4b7 GIT binary patch literal 440 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>oiWMV z-9=#PCSDyNhqJ&VvY3H^TL^?1FWs&C0~Ad5ba4!kxSZM_$ag@2!+CX6j>fxx+huEf zV|WcK6>}N8xL4RMWD_V)lzt^7#doc8d#YcYa19@85n3hISN#dq#-vyB{QuOq`_F%z)07~G{nfr z%Glh>#8lhB5U8QX-+L=igCNL;w9K5;yu{p8s}dlC!6M#Vqo~vxWSpm~pUXO@geCwJ CEQf{w literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiary.1.png b/forestry_resources/assets/forestry/textures/blocks/apiary.1.png new file mode 100755 index 0000000000000000000000000000000000000000..5b4abd8b6df355acbbaec615d3622576f4d3e3a5 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFcVa`4AH%8Z^BK+Z7wTVX-Ys}5rK{08K3LcA(g%iPEn5$+(=-2a z{qq&|_wRo(`q%P&3`{5y16r$E;u=wsl30>zm0Xkxq!^4042^UR%yo?nLJSS9Obx6| zjkOJotPBh^o*V_LN79g+pOTqY3DRJ!Yha{nWEx^*WMyn_Wn!vrU14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>cguvR z;yBBiB)iNIV;@_!txYD2O7z#(7){I8u8mS@jaLh@max$lRFmf3T&3}5mgJmV&DA9u z<$*Gb^3>LpYBoeEb|k771u6dj|Np4y=GQ>O8I!!-U8G9WpBMo-oCO|{#S9GGLLkg| z>2BR0px{(b7sn8Z%cgz3LWdN1nvEsfg4E9aG`|1e)%WI^!j|mQ*BNFk^PGN;b>Wmt zb3V^``g2w>Q>4mfFR7DU<@xP3HVYe51Jid%D(=547Pk3A&=Cu+^yUm*xr3biZtuTu zEkETf%C8%nsm5J!G|g##sC1lSRQziKsNfpQcYZUMZ%)eIl z-B#hB=wtSlot#ZZXLHX39jIF38c~vxSdwa$T$Bo=7>o=IjdTsnb&U){3=OSJ4XjL! zwGE7{3=A}$90jUJ(vX{V5Dng8e(K*Wo&L`VybOm2-HyH@4XeMK@em^ iT4qjaUSe*lRSA&6U=eSz<7~z%ka3=_elF{r5}E+HGOk$w literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiary.4.png b/forestry_resources/assets/forestry/textures/blocks/apiary.4.png new file mode 100755 index 0000000000000000000000000000000000000000..c6b745165b591ed78c973c558cee628b722de12d GIT binary patch literal 510 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>cguvR z;yBBiB)iNIV;@_!txYD2O7z#(7){I8u8mS@jaLh@max$lRFmeOldHM9M58=VW>KEn zno`Y%D8-IM^`aof|Ns9-cTDmJ8q1jE?d~EmJF`^|$l)yTh%9Dc;1&X5#!GkW{s09h zc)B=-NL)7UMvVfh~!wTvPZ(f%X9iU-i32M2b~If@-)ti zEmC!}o773R^7p}Z^DZ3NwaWNT&xHKjr_#jYR!eLyFzvYaSa8mVgg4H6_B<4f&Rk}F zfVZ8qHg%%ZJUgL3lS^c}j<3?aB^>zi()A7-!>b?q{s%sgP_WxO|6RJnAMIoO)xMlb z?b`E=fNoPQag8WRNi0dVN-jzTQVd20hDN#u=DJ1(A%=!lrUq7~#@Yr(Rt5$dPmTiB zBWcLZPsvQH1ZgnVH89dOG7T{@vNATeGBMRQFa&C-@%P>e)F1@1AuTf}H7_wY)v5%@ YV6cccG!S0&_#4PPPgg&ebxsLQ05>nG`~Uy| literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiary.7.png b/forestry_resources/assets/forestry/textures/blocks/apiary.7.png new file mode 100755 index 0000000000000000000000000000000000000000..a2f2e4fd81b84af478f123198523be5c80877850 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa2=EDU-7_O;ev9vx2~ovymYE^O zHA!|pwrcjC6&7I;J!Gca%qfiUBxyLEqng6t)pzOL+d znFYBl*ga*PzXFAFJY5_^IIhd~I`T3*@-WwGHKquvSTPlP9oVgU!APTCr1zKf%}YF5 zr%tg6*}DjOApjTUmxdq>yVoi=+4m20v%yTAg{gj6l t+usTQSjW6J(qwJp59hVBenp&mVc#MxJfW)T+)|*u44$rjF6*2UngEPERtEq8 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.bottom.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.bottom.png new file mode 100755 index 0000000000000000000000000000000000000000..7024ea503fdd3fc082d4eab5d5f2e6d013a12ef1 GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>yCHtEiY_r&TM$o&^W1K%4Oyal~r>z+uOfCm~ts$ zti=Q!FdemX9m?0*NBpo#FA92W^AdAYtxA9l2E%wmL&>#sUV+T>boFyt=akR{ E08wv>BLDyZ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.entrance.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.entrance.png new file mode 100755 index 0000000000000000000000000000000000000000..47acff73ac34a5ab32f636d746ad352cd9b2164f GIT binary patch literal 481 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>;3=*n><|{LnJQi`gijkcHnUG z%f4RP|L(tiS%#`%#XLq9ABGiLI-=r{!HYMtKg(NU_5D`IhuqI1dFxnBe`PMaXROfe zU7xRWTfSZ5L{F2+BMqtVUQT6w%UxvVx_sMK(04<3oyGcdf|Hen)bpaF&mO4GIX>^l zg7sH5kCpvNixUiI|EYOGe)mP@H$hXljsRVwTH+c}l9E`GYL#4+3Zxi}3=EBQ4a{|o z3_=VItxOH9OpUb-jI0a{G@cv14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>fUvNzt&U)8yxN>x&DA9u<$*Gb^3>LpYBoeEb|k77 z1u6dj|6l%UxeL%V#w2fd7tyCTel7-bI14-?iy0WWg+Q3`(%rg0K*5QgE{-7*mtFli z`3@U!6h{jS9on_{_y6ej=v-qb1-|5lr3`DH9%8#NYbN(IH_>xY;- zZ?!olqUHJKN&Jj;HhWyWZ+yMbwY)B{ab0{v__K?@FB)&&UwxiGAd{W9vLuBG=s499 z*NBpo#FA92W^AdAYtxA9l29tPm#f+YK Oka3=_elF{r5}E+9dZLs7 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.fan.on.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.fan.on.png new file mode 100755 index 0000000000000000000000000000000000000000..3a4fb5ad341aac1da45bda65776d0c113a3b7b54 GIT binary patch literal 634 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>)C>1L$0TEG2Q88&zaal151#wA5aVZrEX*CHM4M|xoDLEZm z9l_RkH7R+0aY-dfS#2pfU1ihB~uBYN*PTVMPpfI^EtVivMN@qOEhGaE#y>f z$^&KO)a<0?^<@-IWR%S0)$HWe9Tw%Ottr)Ph*IoGR4)or{Qv)d3-b)1M;I8Byxm=l z94`5s0CG4BJR*x37`TN%nDNrxx<5d{{hlt4ArhBW{kww>Iq>k56juvQXewW-D>`L6 zSJ(gl#c>7cMw4%*d{Z>i5|Er;7@~AxfmeIb!z0Pp88iYqGQOG2JU8$8*QB3Gn%xtG znHJi#xrL@2F}NDKbNk$HDHqw&W++eKz1HC2w{6p{X_{ZnY)l%$b2{9%|9YnPKIQDS z$vlbfVVlD5F3A4%wcx_yELC;ywKG+Z-_$uR_d@UQ@#l%UO_QmvAUQh^kMk%6I+u7SC( zkwJ)|p_QqDm8r3|fsvJgfyR@gK=nu(a`RI%(<(t4jCBo+bd5|yjEt;|&814Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>>P10{|NsB@ z`dqdIXbxkNx4Vll&+eFMKn`btM`SSr1Gf+eGhVt|_Xj9A$n3rJoF+F>TUm zGk%iDCS%14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>3jMK{pX*2R$Jl3Fbg)=5RUY)_65f zF=juY0vYB=c_wdh<^UYGxz-+7l9nk0*}aI1_o{+5N5n|x9$&6aJQ$6V~E6M+5VeBPL4b-#S5+1 z8W=v>v8YMo-R?*K|Iaf19 zP%Ky|5_xt>^1~yATK39k*?wA9K8%?(J?Jyrx`yoQr#7;k$vUQ!G_O*4qoi#E>mRWl z%G+&IC%kKAe--#oWvkp1p^9m7C&G)eOp8P}o~t=s(=TCbx1jfR@UK^z!avP7l>Q0W ze`!hnLo=I zjdTsnb&U){3=OSJ4XjL!wGE7{3=A}$90jUJ(vX{V5Dng8e(K*Wo&L` zVybOm2-HyH@4XeMK?r0+T4qjaUSe*lRSA&6U>t8~aAa}HcaV9Wu6{1-oD!M<1TV?1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.left.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.left.png new file mode 100755 index 0000000000000000000000000000000000000000..78f21b8533bbb7b47ac402d35eb7d3aa493a9141 GIT binary patch literal 483 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>=B~4R3dTu=*EViH&AD5+zir#(K#t=#^@FOrA4}Tqt#x@Ma=7b}(5kwb>;2FE z-1khy?uK9Do-bd{?oobc_DTDie1<%;$9}`YZ$JmBmbgZgq$HN4S|t~y0x1R~14AQS z19M#?gAhYQD^mk2Q)6udBP#;~jVDKe>X9_$=BH$)Rf04a>lzs88kvR|8Ce;dTbY<@ w8yEsL)cAXE1!@ok*^ri*lbV;9n`%`8WH1=TTONwN`wC>7r>mdKI;Vst0Hhh7J^%m! literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.plain.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.plain.png new file mode 100755 index 0000000000000000000000000000000000000000..e2bf2d95e64da2dd5848fe6244f63126ff03c00a GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFo0F@#x@Q5sCVBi)4Va7{$>;3=*D?MEtLpZL>_BaYM849picQ*PYJ-A_9(Asu{@%Q6q zW-eZd1B_|~4J<4h%lEIGIZtinGcMM!$x+=3H>WL@ynOd~L6hdn+fC=fbPPITr3HT5 z%m}!W^KsY8SyiuWa?Ed@x?FyF#vRY4*^SrTPO6*UOI&vJXR&Pj{y)#;H9Lh4ZP==n z26TjKiEBhjN@7W>RdP`(kYX@0Ff`INFxNFQ2r)FYGBvO=HP$vTvNABxcybh|9!W!P zeoAIqB}jv@u7Q!Rk!gsLk(IHzm5Hggfgw;sjlcI+pawyZ4QZJ4EUHx3vIVCg!0D85Ry#N3J literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.right.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.right.png new file mode 100755 index 0000000000000000000000000000000000000000..b093220b8a45f4966b0a6763a677cb54e71f3b7c GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>LpYBoeEb|k771u6dj|NpD8P&&{A z#w2fd7r{qcZFd1VoCO|{#S9GGLLkg|>2BR0pkSk?i(`nyW#7I?K4wE6C&SLyWxIUd z*WXIAk$3HyBJi70K*(Y4wM!3`Zu7F`9=YfE%FRFJ-R<1zQ-VVIPh9YC2{RR$zL34W ze)}{wwe+&j{SUw79rCQ?*z~Zrxp2e6cUPk-cDWn-Xv)mE5#Z9nN|tXV61Ckq-$gvVq|1xY;I*@s%>Bh)KKH^y%nfI m2xLQAW=?8eVs5Hc36Q~H6mMuyBhNeuWS*z1pUXO@geCyU%$R`y literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.sieve.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.sieve.png new file mode 100755 index 0000000000000000000000000000000000000000..8acc72431a14fdbb18d4059f135932df285b2258 GIT binary patch literal 582 zcmV-M0=fN(P)ZOE8NMi3?-!U)PB3@9#i3Ub;uMBzt08=_`YSP=XNOMU^ zrgZ717#&2EN?~f$jfFOKHx_Zo0Z58zQzuGNYBv@D(oJzRQZ%hSN`CmZB`ps4g#|WQ zWh&R0lpyaN_y5PRNb{qSB7c_K(LuDY2{}8ve+ZzoE{Vl{s9;-d8xufjeWSB}zwexL z&Ux>plmMLDuMvhJ=R64Z0Iapf82R{4=exTx91fLIob%ai=DnXxCQ7OKd=6kboz``2 ztz9mc`1O%JxqC$j{%IL1rM&mfInMcNwE{36kG=Oo2=Bet`s7fT*0Wd7Zod1n1@QKB zCd7Vk&N%?am=HorX^eSvI|A_V)@AnQ`7w_>uivi-E`Z;~zf*>iHTu&BSJO?wUYuPE zRZKT-u72T9+J1R@J?Zq4Cbr&HgI=&m^F+xkw~3PU_rwbTGA~`etFqh@5gHZ@dI51n zo0=X~%1$KIrJ$i&n>KOC*So6S9)SG%!vsMMKyapu`ur!lk_YP)MjH~h+0E|e?Z(5?HQ?}gyqWo!Z@!s_UOmazjSl>^ zs3rh_?fRze@prF%tFHt6pg8$6({;?5)uIC5IquXQq zhvsTgKd83vUDc~~=l;#nJv>2qkE>sF!DB6n*-7Dhl{x14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>LpYBoeEb|k771u6dj|NpD8P&&{A z#w2fd7r{qcZFd1VoCO|{#S9GGLLkg|>2BR0pkS+~i(`nyWz&9czQYPU&ce*z*K2S6 zo?mv}aWjjAkhPkUV@t%bgiMb*-=)74)ng2N%h#C7Z|?EUu;@EH)kN_75hmT)+w7xu z2j3{ZAhp%M`b&v=VEM7lt!uY`?AWY5_q4>vDAVokGehP$&O4H-!ZQ84{S20e=JQ{e zw0L|yl7DsUwX2SKHgzHC%v?N&HYEZbq*~${QIe8al4_M)lnSI6j0_BobPddPjSNBz z4XsQKtW1ry4UDV|3^bk`1*%8Vkei>9nN|tXV61Ckq-$gvVq|1xY;I*@s%>Bh)KKH^ py%nfI5M)DIW=?8eVs5Hc36Q~H9B;0oKI<09I8RqUmvv4FO#r^2m_z^o literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.swarmer.on.png b/forestry_resources/assets/forestry/textures/blocks/apiculture/alveary.swarmer.on.png new file mode 100755 index 0000000000000000000000000000000000000000..ad1c3d2389d92787de717a6638d8e5f97a7a5964 GIT binary patch literal 479 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>~Q?gt%^PGFeojzqZC` zTDG=@roiSZjoK)cH?t&LC5Nb&#w|C;Y3 zQK$!8;-MT+O!4^*!#}J9jrhS}3hYdKGHy+UQ zt6K8^e@?5%%)&(n(;_z?G-CFj`dOjj6(5^v(lLgZ#$M6ShRTt$H||$oKl{RA8S|W{ z>}S=tzS#4^cIIlW-}5W;^@U$7m6f`(NBn}HLq^rqg|{awDY}JuSU+{{D&KHDo`-A0 z_LFTw%(s4=+;eT0$|u#=?A=Dpt!zog8-eaoEpd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg( z1|f!qR;C74rpDR^Mpgy}8c&Xbe1*`Eo1c=IRteHztZQJTYh)T?WMpM*Ze?PsZD0u0 sP~-2t6{tZFWJ6kJPHJ9aZmLxYkilRaZ?R=YyEn)14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>C`fie;j;*0Xs)|6^CL@9P8suu+*{{R1fTfxjmpk0hf-tI2)th@qy zfgH{PkH}&M25un`X1sK_?hjCKuBVG*h{R=8|8AjX1CDO4+KzMI=iI*Yzy6ui?A>vS z?oJF+Oc_6AWEG@B7CSHQ5?*>uVUdzb(79SywJPQshqjM~u3n-Uf8?K~&I~VKWWH6p z+DO=zVR2bJSKlkgsx?RAw%KULtWHU8;!|InT5`F0YFS09e?iRkh)EKDT&i9jjg_^h zt=X10U1^T0`6H%&gx%t!>F(fNlV>iC_xi>zcZ6g2PxT}-phHzlTq8hExvr5xh@qjCsezTLv9^Jcm4SiAlcPZONE&kUQ!>*kK^ly84UBY+Ohb%} ztc=aAOiZ;641pSI{JpmVH3))iNXyJg%}dNpwJHHJ7);_Vk6l<80W!|h)z4*}Q$iB} D=scu6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/arbchest.0.png b/forestry_resources/assets/forestry/textures/blocks/arbchest.0.png new file mode 100755 index 0000000000000000000000000000000000000000..84aa0895dd2343873acafcb5a6f0fd6ef1dbc445 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqHcnnC_1?pWX8?tsc)B=-Xq=xq$G1h=U!QB2-EBWY<%*SBo3c>l#4_uJOodvDh!*dVY(rhVi4 zZG!I_SDj*ZEchXFHYAR(|8U`^UZ#wwzfX7X^ZfMfS02N%;ElazYyZ8R&eD+j_GQS2 z#Y^LbR9#wpSAV|#^VltYPS+g0x@zy@LgT5oqm4wlzw?BoZ~EqW=&r`3_gC4j*?DrF zh_N|*b@Mk*h8ZhUc4U|8orsm3vO}NQRYz&lq5WMP$~))%GM)J3^1Fraw=uA2C@{E+ lOtARBk)eC>y6ejO7;9Pg2NpDi-Ua%X!PC{xWt~$(697exjd%b6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/arbchest.1.png b/forestry_resources/assets/forestry/textures/blocks/arbchest.1.png new file mode 100755 index 0000000000000000000000000000000000000000..465ae44e55ab985d2c6acbbcd9b0a7940d2f5a89 GIT binary patch literal 685 zcmV;e0#f~nP)}O$OgU)4-k)UUj*HsF+WnL$;8nA;?G=L*ezjn=fD zNHesB$fnY@1{LF_qiPJQc>Z*U{MTOqL|>odRGpAbrJ3K-b|Z!7r8I9I4YVPVGzq4)Q zmE*Dp#u&ulK+N2@+s6N3?PUhhf34FrMas`30gV7aVbJ9dZVLy`ae=9E8-u5-pUXO@geCw}qL};u literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/arbchest.3.png b/forestry_resources/assets/forestry/textures/blocks/arbchest.3.png new file mode 100755 index 0000000000000000000000000000000000000000..0a62fd911a62884dd68f743ef93623cdddeb821a GIT binary patch literal 476 zcmV<20VDp2P)9Wxe{UvU>Q0Lg@jnwn-Y36m;gkhaeJ>F1i|b5FlQfV|u3MnbAIiGYP^1?H{G&3Rf1!fQpl1!9m zYcvz_|1V7}q=lW|A)8&;!CK1%`u`3@M2%pxwB!NM27&?DnLn%n0bp43+x-D*39t{v S(}bx200004DA2lp=H1?e zoSZj0EV(+mx;ZTMtG50>c+Wl|UAo1=$tN#AO-IkNulvwb(ZlAa58VF#Nhh}@jMEy=HEV5Kumd@ei yno`B)_~hTas{i%{ECGiEJN})SvxLF^_Fes-|5jc!NInJ%HU>{uKbLh*2~7YNRG7m6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/arbchest.7.png b/forestry_resources/assets/forestry/textures/blocks/arbchest.7.png new file mode 100755 index 0000000000000000000000000000000000000000..c5ca5af96ed4895ecdfb0ec4b4c25a1cd989e929 GIT binary patch literal 675 zcmV;U0$lxxP)FhKv`~Vmn~S)Jiyd^ZE)|CkP7Z|# zY8SypK?IR31#!?)sVImQY6T^=9jZpqkQAHG=HD!Dpwi47^cmuFxE`~XKxrLZEb2xe=hY0PlJBv z`ixU)`0*e!7v9inv5;auV;7jMz|-490C=PT!!VshfbJuNc zMF30-q!1E+pxwEY&*m6;^okG1zZ2;@N^l|$z`Z4t(H`XjDhZxqxk|ZMBNnoQlS?L7 z@And#>f&!XM?PC(*F=0%GJrti3HUqk2ilp>n8ZSgo2fxWGR-g2Lqyv;%gB-mYug%rVwI3k&*cRGkqff99AZ@dGb@U_IlyDNPD zw9ph0Z37w_SSd=Tz-tvCm4>ISqE4d-$cp_rA5rLEfmj;uUzwqGPNy0<>9pLuo zKV4mD`~%qd2Tog(X-0b#3yF-Qg-E8^$`l%pMq?NzvlTaaJQ1<|GtDQr#sMrq^hLrt zap}OOL2BJ^wSG+fMjY(!(tCIBw278RO5qyk|Hr#^oD0P={{Wm`4$bTydEWp4002ov JPDHLkV1h?EEad14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>EY)uPd|RT z_u=E+kDqRT`V8bgwzA^z@ZdEvV%ODWQC4PFQex85V)^v>(fbc~-n_g1{=;o&XC7;7 z4s&x3eSKCvJyuCcCTVF#LqoPtpPzjE^yt&)2OmE@`0(+;`ww?tzrFnW&6RiWZ@&L< z%hi>~-k!_Wmea)rcXZ{FS5vv<9M0*i_Yld>|Ch6b~-F`K$N^Sk%A|Ns9VVLEjI z(2%y{W;-5;RfVow*x5Q)paeK*CL40v3ESBH2j zy512CxRW6`{r`W<%S^9oPo0^W!t@|9=g7|){!DC#jOThvYKd}QWL0o;SzG$ZZMkI$ z+a(+S)(D-WUS3=8Y3yX(b~<6cbKs+g9)e4L_ptu+bG81(^4z;>@6Tl(f{G~y4O=gU z8fj$53SP8Nn|+#E|xDU$p(!uHn9<6u2KkX>H02{CD zjyl05KDyr(~v8f;1TG8W`ysnT8k{Ss9yKnV4!D7y>oa_hft0U77%>gTe~DWM4fKse%# literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.1.top.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.1.top.png new file mode 100755 index 0000000000000000000000000000000000000000..40f980eee5babe37c24f25abfc31e3e6737a02a4 GIT binary patch literal 416 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF%y{W;-5;P}h^LEV2*>s01RzLZU{q5z2uMg^DwYh8P>^IxRd8lp zF+r8*lm@erg~$w%Wy=^PV|KTQ1S$5g@+7b|Gac6oGhklvTVncps|0B<)-^EFH8Kq`GO{u@w=yx+HZTNgsPXsS3e+G7vLP)qCp9lI cH`S^H$Y3ytH$9Q>x*lYlr>mdKI;Vst06bNHJ^%m! literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.2.side.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.2.side.png new file mode 100755 index 0000000000000000000000000000000000000000..6b7dd941d1c3259e5f637d470402b316dd83dd58 GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5Z6U6k~1uYr~ao?EnA&A9XY@0~IqSdAqxCWnB0Y2IO!SctjR6FmMZj zFyp1Wb$@_@MxHK?Asp9}6GEC8*o4J75;&SVH4aMX8EC3LT5@I5f}oeF0V}^4tq^Hx zT)CRl$CZtdVO5;Oqi^iLoq)PkOI#yLQW8s2t&)pUffR$0fuWJEfw``cL5QKDm8pT1 zsj;?!k(Ggg#*?E!^++0W^HVa@DnS~Ibq$PkjZ8y~jI4~!txQa{4Ge)AYW%&o0yPMN kY)H$@NzF^lO|>ckG8hcvP4;J$T7r!8boFyt=akR{0F!-Yr2qf` literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.2.top.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.2.top.png new file mode 100755 index 0000000000000000000000000000000000000000..f68f1b09de141f7c856fa5b5e1899787f5ee6d4d GIT binary patch literal 649 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>2ctX>vjPwEBoqENP3~Gn_8JBDIz{#_ zkS>8fLw-S4#wHccIz^5?1AzsO;#xv%Gc1K#HMqE#83frF+qJj_SQ(3@Sj!dIyLEY{ znh6TCF*Yc%Pd4RmQ08b+=k7P;>(S$xY%18K$|=jm+@;M^tH{x&!PBqL+oi)Z!HBO% zmq&t=S(b;n&wzK5F@LuX&vZ+nc@Cog|Nl2{ntcuE7se!ScNcrRWP?&5hqJ&VvY3H^ zTL^?1FWs&C0~B2D>Eak7aXIw-bv`CX4%Psdn9~}&ZtPyS_j}yG|C>|hd^|Y&z+q0# zoeYL8`;T-AIU2dX>^Z4c#4};JlSYusZm-lr5-Ml*6&ZRyFI$5>EHKHUXu_Vlzt^7#doc8d#YcYa19@85n3hISN#dq#-vyB{QuOq`_F%z)07~ zG{nfr%Glh>#8lhB5U8QX-+L=igCNL;w9K5;yu{p8s}dlC!64o&Fik`hWSpm~pUXO@ GgeCxKbG%&u literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.3.side.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.3.side.png new file mode 100755 index 0000000000000000000000000000000000000000..61e553f317d9b3418cfad984e97b286ab9526e03 GIT binary patch literal 634 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>~xPtxkBGyw2SWYiwxwx7=#*Zy4hATOg!_R@)&63%{nDORL{@Z(mF0J7>x19az zX6}>oSo|HCUCfwFG#D?f<+!|-^YS{*s~fqluIKi5WC?O%iST0cux7coiR;2D_8Xgc z<~Fik-NYT>#2V_(A}-D(DapK|k5fT`MOvCA%!BRHI?gMbxUOvEyt0w&=63#bOIgn? zXFIoy?fi1KtLwRLZ0Ehcndkri|9bzI+y*+HG0EHA#mbNK2*`_^1s;*b3=G^tAk28_ zZrvZC;BrqF#}J9jwtY8+4k-w*h@0+^Hk5i_A-}@#-u8e0`z;p~uBuqDI=!J|N>FQ( z=7rQU#fb)MI##*`ro?n)t@1NukIGgz;m8#F@5n8h*?m%b?mFWt1A|qTFE^JZH1Mh{ zQ)FIXBqZrPe?jK5a~>JbSWPPXeluz3yuHM{Y-;3V+1YtUg8vQKJ9BrPJ&|AUm{ZR8 z?)FK#IZ0 zz|ct7z+BhJAjHtn%GAKh)L7fV$jZP#4EUHx3vIVCg!0GYGf AY5)KL literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.3.top.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.3.top.png new file mode 100755 index 0000000000000000000000000000000000000000..4332bdf5de881a63743daea68a7a7e8697200867 GIT binary patch literal 670 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>#j(~DSxU0K{Lm@cp5JhO=P;tKZj%h@ii<8ZZLKC_7J+)~zyE7{L2 zV{U!?@K=yD?w&YNbC?7U28)hdHrb{b1&MaoRxl`cw zUZM0zuJlOGxBzx98x}_sMkiAyPitm>N0ysA_|7e7Kf9Fe|NsBYT)RF3y~CK~?e606 z?`F&mAcwQSBeIx*fm;ZK886+f`vVl*>FMGaB5~RG!t0Tbgj~w##kfh|8V_{&`<2yb;|c|Uou@_cKdt(+?(~MrgJ&e z{!{yt67^s0A2(mC5qB_unM@$i6RIVy5hW>!C8<`)MX5lF!N|bSNY}tz*T^8m(9p`% zz{=EE+rY@mz(C{4QJ{Jx4Y~O#nQ4_E4aT|#M!H6(Ax1`4#^zQgrrHLEKn*qi-dlkh n1VJ{WW#**jCFZ7Dl>iwG2Jsf#?pXo@lYzn0)z4*}Q$iB}y8-Iu literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.4.side.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.4.side.png new file mode 100755 index 0000000000000000000000000000000000000000..09e61670b277d456610ed29deaf2c9dcacacf154 GIT binary patch literal 577 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>GCEAOXkMPr-ex?%X3OeG0VxZI9rJr>hP;6ab-rztEjMLL`dhyD;Vht zXsU5(s`BK-$Q2|gW<|*sCoAX0Dg6KcU-DaqHqcd!N#5=*x@T`W+5$P81s;*b3=G^t zAk28_ZrvZC;8af+#}J9jw*5DS4k_@sDlcLZUG2E0P&4=L*8l%&H+{27QJY>pgY!U- z>jH!4ovtY-8#k`pC=|3(h-1Z{5Ic`URx_hsU$}9_=zB=etK6R+YObFG+VnJ!F)bE7WF&M2yd)rtghGi+-uJH zqqk1-@KcqRAIuDMxu3W!=$a06plXS0L`h0wNvc(HQ7VvPFfuSS(ls#GH8Kb>G_*1` zurf8)HZZa>Fwl5%6sR6aLvDUbW?CgkgR!oGk*<+xh>?+%vALCrskVV3P(zKs_g0_= nL68k;nK`L>iMgp(B|rv)LA>R`o1DNnXJGJj^>bP0l+XkKM=q~s literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.4.top.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.4.top.png new file mode 100755 index 0000000000000000000000000000000000000000..23ff2412b49dccbe7b07c5e3c2c33073d36fa537 GIT binary patch literal 698 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>F36V?UxbmW&1Wiiy{FHBUD7H3tGV^0p2)K=%oijpl#QnoY^P7apRROQZ#Qz%JMjq(zW z@DR$6SJc(yNe-4MN>a^?lr2nD)z#!RGZZ$|;nUONH8&P2NKhzBQpt&tFHBVV|NlRW zo!JSX9~qOp-Cf)h_MWT;aySb-B8wRqxP?HN@zUM8KS06#o-U3d5|>TSy$(9$z{C2W zA}Zzawuwzj3S31WR$ue)F1@1AuTf}H7_wY)v5%@U@(X`G`J>qS`uWQr>mdKI;Vst E0HdeV6aWAK literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.5.side.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.5.side.png new file mode 100755 index 0000000000000000000000000000000000000000..e94db11aee1df68c05afb1a048676038a80b839a GIT binary patch literal 524 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>u&}bSva_?x zF{)`Y8W}QK=`&eqGnz0nGqbU=DKKiNGwLfbYN;{lt1{{`F)`Iz_v$j4wK`9|ll}8n z`j1MBE;&Zky9Gb*Wc_TipLD(9y8Y`|0O#r5_?!^Yo#{u_5PPhJ-3 zH94Ye4U^KOx(2t<;ymlOw|o|~ICX^l<#cLt*l#14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>S-_MAm7YB3orFlx#$D$6peC^KsR|NlR5&HHGe`HV^4?k>_y30IZ?Ih+L^k;M!Q+(IDC zc3ETJ&b6<-{Y~Tjz-+?PAy$w1w^VlFnd`XM#>Hmfh=lp1%^$eU$ab?a#BgHJxkw zck(ly)t!FHby3I0+sZC$?!Eu8?Uq3C^{DxeEk2!kU;DpCwEjl&B7032mV^4~OIHG& zqgvt`QIe8al4_M)lnSI6j0_BobPddPjSNBz4XsQKtW1ry4UDV|3^bk`1*%8Vkei>9 znN|tXV61Ckq-$gvVq|1xY;I*@s%>Bh)KKH^y%nfI2xLQAW=?8eVs5Hc36Q~H5N~K? SA+gF7WS*z1pUXO@geCx(q>sM< literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.6.side.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.6.side.png new file mode 100755 index 0000000000000000000000000000000000000000..18a419cf08df6884ab7f1eeab0cf93961a3cc749 GIT binary patch literal 658 zcmYjMYec+E=8p_988~E3)Y7~pWbgY9HBRsT_2Zo9+@5ouQ)AG_%OpD`2q9Tw zf;Np|kk3T^%!e!F=?nsjG|3u-?6rX#d7D_iH$NdQ8KKHBgsQJ2w8l!+^9Y^i5Lz%H zB-A6cz3gFcYBX!u4JVDd1%MfVX@GfvMSvxMp8(4MD*$gPeTs1_#!oP|VcboKosf1y zItg)5+E3|#*Xsdr1AGIR1NZ?j3-FSVMvNO)S07{CM`_TaK~8WQxnkXrGv9A*6R|Dmf?TM0U2r?SAd?I0ykI?}h9$ z6YqB>DPAk+#UFhyipvtR&LI@I&1ZgJ-Iq65aUfBvF@}tXrp#r3h?S;S7I{(!6=GQr z9~Ba2aV`GMl}3%puQ;Oj`#YN@cLt?T>QuK|hsW=x->(@NU1&YJB_()SH!Nxi;H&Rh z`b1YNCicZ1?zEMb3>iGm;N{GNyOg!Z-I9Q$8fBfct1+w8F}Z#tu7G%(*QCEQMq(b^ z@}D`hO!9LyvyE$ARhOzxJLRXebA6+oD|;?za>Ze*Q9X*-dvyd z$X&Htv_3i3_D8q%3Z646m4ccR)T#)M z7dS3_c8JaYN3fI@6c<+b2r31~D|oe$=LJ=ya6}!!DH-8nN>Vo?Z1r6zEIw;4$+MUR YD+`b^H}XJ}{*`ZCqE4^19W!0~2gK_@C;$Ke literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.6.top.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.6.top.png new file mode 100755 index 0000000000000000000000000000000000000000..8793b2c2da73a7c071349c1be9741a56cb01dcc5 GIT binary patch literal 638 zcmYjMYe-XJ82&~UdFvvG6@?dEjmGTk=u(dQV=`0oJ}2uUxT!NnnYT%FMYhlOK(p2>%LRAbx(*}gN zCWL~@Zn(1JXrU!5O_w+a@Ec$nU<%*|zzo2UD83NIM}*wMxYg}$7X+IixCnVlNWUn4 z1(*eROvnVlB!FEIegfPTga;V+5@O}~HlA#@!hI0_er~IU(Z! z4GRlj06GQX9wFZW9%6hSMS&1ZiKNYz&l0 z!*f?+-d@S9J121&b|0=APD^k4qyM!?zCQ689l&pe@Rq^J99p=14u`QW7&XT?vM> F{{X|MGL8TM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.7.side.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.7.side.png new file mode 100755 index 0000000000000000000000000000000000000000..a00676ea3cbe47c9df2f9859638602093cc5a9e2 GIT binary patch literal 679 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>>tm*bF8<_=6&af^_44wZBb zm-dX7v+@>k3XyaUm9p>@Hg*v(a^ko25^)HUP}LKVSL2aY;g(b7ky7LmmEjPQU=x;P zlaS~1jaTr9l64H0Fmn?$aSX2`~UyHPt#UYpr;s^4RdP`(kYX@0Ff`INFxNFQ2r)FYGBvO= zHP$vTvNABxcybh|9!W!PeoAIqB}jv@u7Q!Rk!gsLk(IHzm5Hggfgw;sjlcI+pavn3 l4QZJ14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>bdQwriBkwjQgIHIQq<&=*WeYGEak7aoM#0b=V;TftK=CQxWG~ssSrIyu5c#SGuOX;Qjxw zciWbKRyKZq`prBRhJ35oRi)j>z9_u7ADPYWCu*b|Ai=x$yKnlE1FnyEuug2M{!}*U z#Es^~4hOy%&QtaO7kO+=ePQs780QkZi5 z-0PQXUDh-@N33!T4V{r))$Z`7`RC{Er!zIIxo&nW%C{9^(Odu6pZnY=<*Q2#nV&_) z&%D2X*$@6J|M)LmC^`NP=n>Tt*NBpo#FA92W^AdAYtxA9l2E%wmFVdQ&MBb@09$6&r~m)} literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.8.side.png b/forestry_resources/assets/forestry/textures/blocks/beehives/beehive.8.side.png new file mode 100755 index 0000000000000000000000000000000000000000..0087491ea3c6d7711b3203c289216b639b208c05 GIT binary patch literal 894 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>QRUN-=hl|v zGFIiY&=fFG;?a}?a=G=DcuT#-@?3<{Z1_^Fc++k9@?C`s-9?H#MDkn&Q>}S(oCKo` zxiq9X6-3$OMcEX^*tBFh)ucFNMcAbTSj735RV6tj1y~fs*rWv6#QB-?T!f>IxWaWg zk}P;)O}HWrIKy-~bmh6#q&a1T*d+K_6hzo$h1taTSj704rG;7bm3bujS>!}m#ratI zIT@A3*-N}cGwt~k%()ZId1FnuBlJ0gwK<}VxRu1%q=i@{1z2T-SmZ_6WQ15nd6}gJ zSta;c9hBJ}RMP*!}U1*)Y&|hSpzlMLv=XJWm#nTSyV(=y|g)lwAsUSxdb>F zg?X4|g;||c*yRM6)x}vQ_?Q($Sp_+n6hzoPG&yDYndL;-R3tbwWw}zV`J#%aV-iZ~-nAX^;d5Fa%;SMR`-JWwyC#n-aS3xxa+-k=I0+)l++Yeg&j+I zd1oiXv(s;`em(m(c4o)bzsxE>HlFZ5uOB56_wudmhEIVUO_QmvAUQh^kMk%6I+ zu7SC(kwJ)|p_QqDm8r3|fsvJgfyR@gK=nu(a`RI%(<(t4jCBo+bd5|yjEt;|&814Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>QsFaF<~3B} zHB#X3|V4b|b$lH<~l0Sa=dNpTdo35)YHhv{;N z^D#&0bE?a5)CS8YnDMAfbErykXv%U`_(>#L@X89a#+mY{N^!^tvx@RCM;meFxd_RL zu!{4uNDHzki?gdqacatPX4vtoNpot-aH>jhXv%QuDe{=9^Xn>b8>;aB|NpIXJgg5E@$hR+ z-y|}%lp#>CAeB{Q4{N?){@?%hN6&q@wB+RUWtA?SOP?Hm!e_G0HQDj3Z0znc)w>rgL)u$NB^&8 z1sNV*+4(yTSDa|@yLTbu&4VenCg()XiRx_;(pwu7E3I|cNA2<~=8fAEoXg){{CjwD z*_p_{Yd@IO)p=%Lt}ttEKe6xEvd>=ij6xq~XGbN-JHJ10{Q33rPtUL0{xkm1!YKKv zy-Xkr=t0#I*NBpo#FA92W^AdAYtxA9l Y2BUaGFDGrj!p$9r&6RK zv{5Oog-}CJnv;_sheN?h&O01FzVkf8`zeEdkI@L*n2raa%u~)1G5^i?Vy*#rc>dx= z6|b|pYXF~|7h7NoK-X2y3td-rRk=9Z)5Op1<>qC&bKd^>=Y4wP0Lbfb^8U4kL_QYD za>dB$(P6VulM$MYS~u_sqfu2=G6KsAMk8W6o^5F|f^BK0ks;LA(RaMtl$I9K!i9iiajS~)_ZtHQv mErW=Cnw9G$cWn)TWsqN6$d)aLYY!0s0000jC6&7I;J!Gca%qfiUBxyLEqng6t)pzOL+d zS=czl6yMaYr~wK^dAc};a9sE8Jt){>(JgFJ zu8mAb0P_z$)$h@2%c_5x#N5+6v%=Qwr{R;CPj@k0+9=sTP_JUHPV)fy67P4po`X*S#a?$uoT=}1UGeX5FC^ap_3q; zO8)~vaI0H&DMAx`K~NeJlO}gb?k#ucaLFa1UHncD&+p~?d%nN#BRyNYodC4#K4Z)m zEyj1#=Uh(16e`n@?%g_{@E_>3o17?>Ck=Mq-A`m$!F8I*vIIaJCul|ifac#83yaG@ zLKM0vs+kqn5B?xN@BJhQV*o5enc}i1iLGz+y=Z0<%TQ1h332t(IYRdkfXdcB08bv? z%or9HmvNm202|v?03NSiOUGAKWWV1gjuR?d`!qT}jgHUjw>ueA6b{ggJR959EWW~GI1OszE*z`4v!{$+O1(33iXzEY~wF`-%*8> zZei{D2LRqYIL-C5U2eQc1>Agj7l75L?~iTr>d|GSkCi(!^jGv6HEo3`bO8vwUKVTH zK1)kWc)bH*h}W_B$} z5=oK(U4R)s6fJ?cc;U=w3lq3b6SHuN`oVAJiaLk3&s{u(Wo@EI;5pzq0H}HnAqxXj%TuC}iDMSZGZQJQiR&~+?Bl=K(0$ci5XlpMG2VUyVoJrB-`>puf9GDT_moQUXBAN*4|Q@3-GsTL-E#kC|qw?!oyl zesugJ%OwCyu!UkUr~R){Qr13}V2lyIaqC(hUjXRsp8|OH_^wjwtgXl45WvoX3*hP2 z9RP%BG>t}5R=xex;W!L$>O0Udky0CW+T!p{gJIs^ET@YhdnlaIXz zOTJ|u1IUu8LPkN_?RJx?4`4FQxM8)bGFKeaMBS=l;kw-sjw~`=*Z{%Q=O^x25EZ7u z0K{ooKRF?!sw!XtpiZM{aenj0RZ8o~5Qm=WTp67ITxl8?LAug3RQAeT%96_>Nz<9S zC;(xv0u=zmy4=?1!(>T_Bm|%t4Nkc*b-RV38q0LrwHwpSIP`SkEdEk8&q2{TXTdB7 tCe4Nx%yMu1UExVKna&Ek!2t-J{sD!(=MH3P{ZRk_002ovPDHLkV1nMP6u$rf literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/beehouse.7.png b/forestry_resources/assets/forestry/textures/blocks/beehouse.7.png new file mode 100755 index 0000000000000000000000000000000000000000..812f28e5e9c29eb21d36e46656d2d8d3c3a6aa4a GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa2=EDU-7_O;ev9vx2~ovymYE^O zHA!|pwrcjC6&7I;J!Gca%qfiUBxyLEqng6t)pzOL+d zS=czlxgu{R)B=U#JzX3_IIf%aUgSL-z`-oZwTWSaW1RSgxqsbP1h0Jb{0Xy+*4pPS zVyiF8PH8;z;GmLcv-zdYyxNd87ZOidS?KWH>N;JeRF>i_@% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/block_0_14.png b/forestry_resources/assets/forestry/textures/blocks/block_0_14.png new file mode 100755 index 0000000000000000000000000000000000000000..ec992581366ebcf0a09fe13d1209e2a61bdf2a5c GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>@~ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/block_12_13.png b/forestry_resources/assets/forestry/textures/blocks/block_12_13.png new file mode 100755 index 0000000000000000000000000000000000000000..11f0404fc856eb1e40715a3d9d612d39e5c015ec GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XF_i(9CbOf!8A4 z|NsAQZPM5c6lX38@(Z5S-p>4ggFleVnB?v5!Ys(+1G0~^z$3Dlfq`2Hgc&d0t@{HM z4EJ<#4B@!WdtxDPgMomaPdIUT&ILA(w_Hu~tKH?V%Gaeys9Gs^$^xxW zEpd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cp zs|0B<)-^EFH8Kq`GO{u@w=yx+HZTNgsPXsS3e+GBvLP)qCp9lIH`S^H$Y3xuiZ?V~ SCirkF$Usk5KbLh*2~7YC1A8g} literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/block_12_14.png b/forestry_resources/assets/forestry/textures/blocks/block_12_14.png new file mode 100755 index 0000000000000000000000000000000000000000..1f9c3ae8b70adbc80a782ae6ffc0e90afbbca3b9 GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XF_i(9CbOf!8A4 z|NsAQZPM5c6lX38@(Z5S-p>4ggFleVnB?v5!Ys(+1G0~^z$3Dlfq`2Hgc&d0t@{HM z4EJ<#4B@!WdtxDPgMomaPdIUT&ILA(w_Hu~tKH?V%Gaeys9Gs^$^xxW zEpd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cp zs|0B<)-^EFH8Kq`GO{u@w=yx+HZTNgsPXsS3e+GBvLP)qCp9lIH`S^H$Y3xuiZ?W| SC@nDq8R+Ti=d#Wzp$P#0IC@n8 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/block_12_15.png b/forestry_resources/assets/forestry/textures/blocks/block_12_15.png new file mode 100755 index 0000000000000000000000000000000000000000..f48cee61b57e055cf240c82551e0bb50a8ff1b77 GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XF_i(9CbOf!8A4 z|NsAQZPM5c6lX38@(Z5S-p>4ggFleVnB?v5!Ys(+1G0~^z$3Dlfq`2Hgc&d0t@{HM z4EJ<#4B@!WdtxDPgMomaPdIUT&ILA(w_Hu~tKH?V%Gaeys9Gs^$^xxW zEpd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cp zs|0B<)-^EFH8Kq`GO{u@w=yx+HZTNgsPXsS3e+GBvLP)qCp9lIH`S^H$Y3xuiZ?X% SFLGG`GSJi2&t;ucLK6T3U3#Pd literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/block_13_14.png b/forestry_resources/assets/forestry/textures/blocks/block_13_14.png new file mode 100755 index 0000000000000000000000000000000000000000..fdef61078e3661df4571edc14795d39ece889273 GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XF_i(9CbOf!8A4 z|NsAQZPM5c6lX38@(Z5S-p>4ggFleVnB?v5!Ys(+1G0~^z$3Dlfq`2Hgc&d0t@{HM z4EJ<#4B@!WdtxDPgMomaPdIUT&ILA(w_Hu~tKH?V%Gaeys9Gs^$^xxW zEpd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cp zs|0B<)-^EFH8Kq`GO{u@w=yx+HZTNgsPXsS3e+GBvLP)qCp9lIH`S^H$Y3xujyE)E SI4K+qGSJi2&t;ucLK6T4@_McS literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/block_13_15.png b/forestry_resources/assets/forestry/textures/blocks/block_13_15.png new file mode 100755 index 0000000000000000000000000000000000000000..ff7dc937a25ccff1c4e8820e354b75e8c16909fc GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XF_i(9CbOf!8A4 z|NsAQZPM5c6lX38@(Z5S-p>4ggFleVnB?v5!Ys(+1G0~^z$3Dlfq`2Hgc&d0t@{HM z4EJ<#4B@!WdtxDPgMomaPdIUT&ILA(w_Hu~tKH?V%Gaeys9Gs^$^xxW zEpd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cp zs|0B<)-^EFH8Kq`GO{u@w=yx+HZTNgsPXsS3e+GBvLP)qCp9lIH`S^H$Y3xujyE*@ Reoh%|pr@;!%Q~loCIAy?d#wNf literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/bottler.0.png b/forestry_resources/assets/forestry/textures/blocks/bottler.0.png new file mode 100755 index 0000000000000000000000000000000000000000..37fb005d481c9a8436665fee009169f5db702f2a GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)vmm#X%8foNBcPCMW=KSdbAE1aYF-JD%fR4Vl$uzQ znxasiS(2gP?&%wlqL<1J6rbYh;uvCaI(ZAH$lvo0j0uLDrZpFzldU~+00=%jy=&hj zRoOB_f$h%juX7rKz|qrJ$hEP@$~umD$`ut!u*w$yi@&Gu=h(%vp0Vjs4hwIhQVO%8 z^NbG8%$ha>LFrha;1o%RiQ;Vj5(&mFOAHRAahz=IkdxN&&-<5>00cii{1WtXb38A- egF$)eO-Y6@SKaDuD|hgL9Pa7r=d#Wzp$Pyt`ek+i literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/bottler_base.png b/forestry_resources/assets/forestry/textures/blocks/bottler_base.png new file mode 100755 index 0000000000000000000000000000000000000000..0bc23c6f6e828615be0277317efaea813d3d735b GIT binary patch literal 711 zcmV;&0yzDNP)*N=OQi=T0im=I3C8Ln1Po29coyqHy(m&ox&#plUi=5@!An61 z5@Nkn1TUUy@N7gwMPv_JmC}fMu%}W`$!41m56Lc}*`Vt#P15XhnSE#GnU81Q_uU!k z)P+zT7pT`=(OpB5Bv*XdtA+g9tU2cFKOj8gcU6G+^cWX^NRkqe(Txftp;3&j4RoV| zS+}#Cd;6vC6~8AuKncj4xbxbwg(|3J+fOxLf}!~-TmH3Yznj*2OG~+}T$~y9EQEwt z1L;P^+PI0?ghIXq_tgo6DiEsR=ht9^~DtZ}dA~I(a_W-!b6!FW@$b^g9Ft t4qpIY0AB!K0AB!K0AB!K0AGMX#UHC-H@PV6&m#Z;002ovPDHLkV1l=(IQ{?t literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/bottler_tank_product_empty.png b/forestry_resources/assets/forestry/textures/blocks/bottler_tank_product_empty.png new file mode 100755 index 0000000000000000000000000000000000000000..1b4c2115b7aed5321b77aeb5f6521639ae7b139c GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZEi*ZX1>**&h`LJVfS=#49U3n zcKSxXCI_Cj{%1|x+$wD|B-q&RM1EAQ35s_LFPD|+=~PsCa6pOKDw9X+d0|1g^M1i9 z-{0-Oy>-8}9xbX#w%ruBRLq${oK+-J)#p*g1uMC&41qEm4*$C|P2rrr0 zUDsM#-Jtb^@&60PSkr!A7K4j6YJv~0JN-WN#pJ5hLpO@utsmzcy+rlTz f;wS(_&QJNSCA9IWOnYtz3?&9nS3j3^P6| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZEi+>UA>-%45~n(o1QL?AsP4H zPT$MdWFXR-&*>?yE-ZF=Ls|OK=^s36Ib&)W*x1C`Ci|^fB<$IHL0&uR@@HKg^XcE7 ze7hs##{Gu>=-jX+mT{7<4td%VS2A)p-Av2B{$J{`=c-*Qik5e;+=tq2pZ1ET^1O9O)d1Cv9;`DF)pGCZFB-na48^6T3# iCwwXd`ICWR$tmWVPq~GY!`Dp!aXnrAT-G@yGywqh4u22; literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_high.png b/forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_high.png new file mode 100755 index 0000000000000000000000000000000000000000..7b1786d2a029c7659d03c0847d2e6f55c9965a09 GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZEi+>eeSQ9w>BQTUORv+1T<{`LP-Z#`#iTeRuiiu;^T%b&G|*M49+ z!f?6L;d0n9w&jn1CNkx`{(p%1$?2O9qU4XTta1ET^13y||*b7p{OLd@sAdI3AX l{3?^`vEyTA0D^{yos3<(vv%f3-_Qi{Jzf1=);T3K0RRF!iA4Ya literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_low.png b/forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_low.png new file mode 100755 index 0000000000000000000000000000000000000000..0b197f8b84c2995d1a8857458f110918d65750f1 GIT binary patch literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZEi+>eTl-{?{+|;`<^b2AsP4H zPT$DaWFX=i&*>?yE-Zd|!?l^B^@sGIs+W9amXL^%@Ubcto#~TxU|Yn+S@$-VRN6dv z_H|#3oBj=Xv+}43$+f8>j5}95tiE?MW$U?n>;9Ww)7MZm&>*-HeO;^ z#Te9Z(`LaMuJq>5FF%VpVLnG zd>5OX3@eQoG-l;=N}SXe0dYND{an^LB{Ts5| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZEi+>eU0!f$0q@WZg{#lhGg7( zJAE%-lYvNUKBuR+y72b4t>@PK5VF(MS6t11;J|}J35Tvo&h_zX`4@0;*1Y`0ojbRv zZ-4&GAnHMholS$+g-bD*T3r${y|}^oF`Y>tvZ_TQTv5y34?K^ zL!{_6w(HN#W-?s=wf_Ud-y*#q*W3*mqj%T7xve61cu z_+gLO+rihr<=Y#56_{lGlYJWlO9O)d1Cs*-2Lq!514{$LeBb6`#$)F9XEROpU!TAH g;FHG&3?Se!Ro&4!^WtZB=4uev)78&qol`;+0P_KV_W%F@ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_medium.png b/forestry_resources/assets/forestry/textures/blocks/bottler_tank_resource_medium.png new file mode 100755 index 0000000000000000000000000000000000000000..077637b84dec1d3f4b0df504192d91faa0385c21 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfZEi+>ee+v;PNf5d?s~d7hGg7J zPC3As!{qwk_=12;f=Acl>v+Fc|Y-dH9vtbE1p%C(?0)BZ*_ zyI9UrbJe9*MP?04I}XMe8z@e{XY}fg$kbQy_x>jDD1U8vcyIK1Lmj7U&1Zd*PW4}m zN-$w?W5z}_?Aq&?BP$W~`}+^8kR>x*-`{)C@t&{0DbRq+?VyGP>*55Fo~DUh4A(Db VFYJpB`vCMPgQu&X%Q~loCIBG3eZc?# literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/candle.png b/forestry_resources/assets/forestry/textures/blocks/candle.png new file mode 100755 index 0000000000000000000000000000000000000000..07caf0d1d9824660643963ddd79086477e5edac9 GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFli_wVoZE1OOqpS8kcvp7%%V@Z%-FoVOh8)+a;lDE4HOMk}AKp=;+ zz$3Dlfq`2Hgc&d0t@{HMRPuCj4B@z*oS-0XpyeQWhA)6En`z3yzS#$7H3SckG8l~F%~hX%cndPl)78&qol`;+0MZ9<`v3p{ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/candleStumpLit.png b/forestry_resources/assets/forestry/textures/blocks/candleStumpLit.png new file mode 100755 index 0000000000000000000000000000000000000000..2bda96cab722ec24a54e89aa560e4a0cb7041636 GIT binary patch literal 1257 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Be`EuO;P33Jz-Z?z@Q5sCVBi)6 zVaEED_=!M4sS?+SlHmNblJdl&REB`W%)AmkKi3e2GGjecJwrqH&raq*Rf?W2jv*Ss z$v^tp*diKcvYu+-+%QS6A(1W7d8Wj{EC2s9gekoDeWQ{R2})j`u6{1-oD!M<)PzOT literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/candleStumpUnlit.png b/forestry_resources/assets/forestry/textures/blocks/candleStumpUnlit.png new file mode 100755 index 0000000000000000000000000000000000000000..4fe3fe878368c7d90ba3cec246fb6961e95ede24 GIT binary patch literal 1257 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>bpHv#SDQp0mIsvY3H^TM&d9 z>r>(<0tKZ?Tq8w14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Ealo5uE&^ wpDjb{z!8qr11vKl7w~ZLv@)M!{r8`pK~?-Wf5($Ak3b2`)78&qol`;+01P8R+yDRo literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/candleTipUnlit.png b/forestry_resources/assets/forestry/textures/blocks/candleTipUnlit.png new file mode 100755 index 0000000000000000000000000000000000000000..621afb16dd7ba99f31435fefa607dec903a12055 GIT binary patch literal 1256 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Be`EuO;P33Jz{uw;@Q5sCVBi)6VaEED_=!M4 zsS?+SlHmNblJdl&REB`W%)AmkKi3e2GGjecJwrqH&raq*RSKRijv*Ss$v^tpGPDky r;7C2dGGoR<9xk3%=2NWy{#$7j;PBz*N*6!)^#8&Uvc01?N+SCPg zjBI5e?G-)Kbeett*WYbxjqrQe6|8;f$N^FIi~BYSXZRN!%}m*#xyaUWk;-bDC1z}; zN>e#!NtoPqn<91P>tSgIpp)kw*y{f?W5;c+C)y9|{&f}?Rs~F9zka+wD0zSBO#W)d e&)++~{>p!?y6FAd3;()7LGJ15=d#Wzp$PzshssF+ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/carpenter_base.png b/forestry_resources/assets/forestry/textures/blocks/carpenter_base.png new file mode 100755 index 0000000000000000000000000000000000000000..2781d5a4f24d471c0f6a1eaca74b03689b09f482 GIT binary patch literal 911 zcmV;A191F_P)7J6Hye#e{*LhnL1D#)Gj0-R;tmu2nDO{#;wo2B8m$QK?K2#|9~#s2ttuk z>qZgWYjAA^LtRDiNohn7+Krl`u``p*jEi)x(^N5a0%>%<&7E^I-+g>J=ghfRIW)A% zCnCO7YXH<-A6->QnL3}o)ey?hKF?=`4UjVRw(z4si#kAGkH(R`o3UyhhAybuF6orP z{GyGa3jnINiz*ap2k$asN#`o&(=P8~DbwQNMx z0X)CqqLx#a8xL@L#9(>}ZsqnMasrVPeEl$o<p_69pLssgJP-7I2iyQoEf6GKTSGiAe06_oiga{Pq#d0nBQ>$f}|Aw*MrR# zOJ(k79RLb>7jM$z#NAgol?CP(ZONHmv~em6Ezj4?@3;VlE~E>OW(O$bT?%;@fN?T> zp4diV_?-+7%c;wZ-pp?`1j77vlLP}io|tVsWPwtdE4wX3PH;Fs$nhJ4%xpRE8@|2f zxz<$@JUwEt_vULE0^?*j|HR_ur9HCm;pN$XFA1tb!ANM_dv0<4%`PtTmQ$q!#Zpi3Eu>i3E lu>i3Eu>i3Eu>k)oegInRr4)Jj;lBU?002ovPDHLkV1gWTo>%|? literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/carpenter_tank_product_empty.png b/forestry_resources/assets/forestry/textures/blocks/carpenter_tank_product_empty.png new file mode 100755 index 0000000000000000000000000000000000000000..ae3b97f8db7a5848c3d494ba4ca1b320d22bf6f4 GIT binary patch literal 894 zcmV-^1A+XBP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iprB z2qQaSKR4n400RC=L_t(&-tAaTYt%p(er6_LGy zc=4=w5r09w^zNb1%c3Y2PsKtlD@(Vv#qL&iNwP`SLz(F$n`9HjO%8c3C6k$F=Xu{Z z&%9HD80tsk6Y`k?q0M83tn)DkET&h_!>U z3qz%W=h~7Y)-g%~ziFrxPq)95g;&64tB%#GE(Uk@PXPcA)|Q2<_bx55arrNY$_O6a zzdge_tU;HT`XFxP6Di!5FPk2-{$SyC7lGjA~j=Fenplfvl00J2r*&YUCH&J}MSrN~2 zu);jDsCKiG7=%1N2ihOn0VfB5wYmY7kyPRVU@&&Y=EFQ;QAt7I$yjIrYjE1}JY{=7|y&7X+S+T>1dHJvCGsS&mWS0f12=HXr7R6BWgkiwAI_mg5G@Yn}

@ql@K!9q>}Q)kx=i{#$c#1C|E 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/carpenter_tank_resource_maximum.png b/forestry_resources/assets/forestry/textures/blocks/carpenter_tank_resource_maximum.png new file mode 100755 index 0000000000000000000000000000000000000000..7e3e8bbb230ec3920cdae5ce70aa47f5f226af7b GIT binary patch literal 830 zcmV-E1Ht@>P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipo4 z2qgndy5TMW00O>AL_t(&-tAXAkJCUHoPBt`ih+wI3Xt6J5QvHf=_E=ddOH3E4U|{W zTn+z%pFo-FKqrtQ(QpMwC{hZfOMJnRpBswY`uxh>Mglv9r}KI}Ui+J!{f1xzMz5c& zq~HL6FiuPNs^d~{gmH>(=I`&O*iyMRmaYjF@W;8{`hU??+WOq8+wtWlNk=; zV~kE_c=P87M?d`h`XD~8{Vdb@JO2Zu;KmCr%Ks`fDWyx0%RHb-&Vp0?i}C00zLK3+ zK()#@1_E)aYU6^_t>^EI0^YxTxB`GMQIOVpVPT?>sTCZX<=40OY)ob$9GjKq22lpb zW|%KiSd4&Cl0Q3NrjQmbT@MF5e~wX7dZ)A~UVZr9sxmkL?B8`uave_=0D#Bd_0r@A zx2`qHdOTUcVg%0~-K_BhQHH1YhDO^%zqj=*P?WJ09ATmmM46GRYl%BHtMTY@0HtR> ze*2BL>Pv|`P8GsLwciKm4=pt+=dv_$cEM@B4VupRFi~rs_-Y>g-c}Xhxe`+Fl34{& zhWRozKCbk~H}Ob|8uJv3(b^A~`cX}~o-1K7VtlsGmnniMYvc){%$Ub>W&2y8C_7!L zsULw+Vq7_kk<#LeJf16!d8U5UjS1?CX$kA2%cOEra4Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipo4 z2qY1v7@;Qs00P}fL_t(&-tAXCZ__{+e(uBeDFK>D3?OAFr2;XrAVn}%>dsQ}Cn^>g z*}EaZzd-#5Wy(|#5>iGY1QCjqjU+9xeEteUdyYRY?L`7RgP+Cn`TY2N?{m-lz62}K zd-Y@?Yz_eM{4nz@KQ3$z&kwQA{O-{wf(-y)^+5epe(cQk0c6M3&#yCoQ$SZeP>bvh zCV1n2L2od@>p!PB{V~Jgi9~NO!QqK4Y?kT#jo$!abK`}k<$oP?N~sd$Di6@f+2$1g zVtoJISF-U6$Vd5B!-gNmg>jqHwdZe)0^YxPxBvhzh#{v62fbLE^BiH`u z902gRb2Bsf!JQjgS@%chuo%JKquT|Zxs34ae#_{1sPC4(0eKlK1t?elxcwdb!`A4!(`J-*b(1n!<#`>CsRvY59#cliGGdp}QzmE< zIX{dGCYa_i%_e>rS7L%(MabsMNHI!`J;3HPsRDI8d4*lY!)W>K0nbP1%=IBGYV6+W zv#aAVtpjQgsK^6&(_zIh zcnw3jVXZT(-oa~(3=1daxV!WGZZnhKf97JRBg2c-EM_aisY}d)_c^?Hf4?arz09p4 zasO>Dq1QYMZ5p}4oW3qPcdRE@Veg7y*+iquUlyHnOA7^THP1xe|A7e`IG^?C7;(iS5(9haZP6n5bS+6Z;@0e%=$;#F_j2dj4K(-M@cz e#r(R!bN?BcFD>frTphv$3UW_ZKbLh*2~7a(JIO)- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/centrifuge_base.png b/forestry_resources/assets/forestry/textures/blocks/centrifuge_base.png new file mode 100755 index 0000000000000000000000000000000000000000..f11c55b94d53891050de99abb109c6973b3526b2 GIT binary patch literal 938 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 W?aO)1ckTdVk-^i|&t;ucLK6VVbnH_A literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_clock_base.png b/forestry_resources/assets/forestry/textures/blocks/engine_clock_base.png new file mode 100755 index 0000000000000000000000000000000000000000..7e9173388e8e7e62a78989e9487a60b6cef02516 GIT binary patch literal 1007 zcmVC3W>;pkN7l@ZzC}g2l9jfP#NO zPCZpTh$y8!)S~Dg(39XH+QyJdNe@!d3Q@>3g|KVW$?oi9W<5;b%VamDiLVJIDlT7C}5ff zK_JK%MmTcVBM5}DHMe({e1&ZXzGDuMVwwiWChjQxqYq!;@+S{l#?4j1xi`Ko{_XeW zZvL6*5iRYFD@MDPjh6NYq9_j0Acz1D*W}`B>BP!!$T&T7UPG9O!9@1 z9nYD>?}-$s)i$@{;&eZ^ei{Ve!nq0npI>!2_F|6nGt1n({{Zp#Tda6>g<0|H969Xm zcs^10w%|J&0RWbzwS=(z^8JVkJRkq?1c2ZF2w3%QV^7ZFe?QB>V2Sm| zRh)^N|34Dc^$ezIuz2SQ-+a)|>B&`29Cs)bbNq7kAhqhRSh=HIyS}D&P}ehx1SNhq z5g_q02#*XGaflay-waZqV`Wkr3nlwF(?T>EU4;L)3^luhQa#NW8GSqdld+qLcDfYc5! zj10D|GrzE&xXk?a+{=t@>lj9St4oVdBbohv9oFQ;$<}oZ6<*TTtjo4s7V7(MMARFU z%OW*C?fSC-@4Y*K?}ym7PPr1&XT(QS7&eqGXKmG8N9W70AJOgjY!t;g^-8Ho5Hv8& zjAGg#5X#o9&o8ViuXZzDOBNHwVqZ(BHQSQ9EM&SFpOuBk-6dZ!u5Ih;*=ai#mSd8I zOt<1QQ?I!V*U{DUl4RTFvp#8yqWJhLS3>nJ*sb`~$6&XM#y*#x19}eVIiTl&o&$Og d=s95j%0F2YEjTQ}&{+Tg002ovPDHLkV1mJQ?->99 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_clock_extension.png b/forestry_resources/assets/forestry/textures/blocks/engine_clock_extension.png new file mode 100755 index 0000000000000000000000000000000000000000..8e40f7aef10be5b2027e9ee2719844e0ab3e94fa GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N>um8NL?gEEAoia(3qTbi%Bm?6P+V#XR>9_L3EdO}^fw=MdZCme~GcGT#^yyI)8c=fHm zn)U8qh6&Sxu+_D*4{ur{b7p@?r|EPCjVzh|+6FFGP5TZ3TrE7WnH7oP4`#;t8XmoKLF34n9p}@h@@OqcbyStyPe%4Hk+wZsi z_R<(V_3JU$pZ<8j*U+2We!RUyxPE%s?zx_GzA^eNe=zsmgG#wT5y9hz$0TN*RdfIS zedZ0IzU7x07hKKyn{XE)7O>#E-N>urTLNCeNqezj5|GD978hhy`6S3>$ZVNoBheM zq=3sMZ(oE~U*2~}LEy#N1sl}$wPkyp<|noujJg$)t#kUKo=xRRsbe9NADH~g&*`gg zKBqo+vGTFSvhEF2PE}NBFlzKFzvgT^-1Galkmmm*3~h&b6i%!!J!v(y?cav&(?7ke zng6oHZJzg*bryE7KEJ&-;kgjQTJ0%bKWe^m2t0Xj)39n4|Ctwu8{+JbicI_4?Cj_N z&Y(3n>ALx@kNb|@k7S6ed&uDLUux7^=rA`V`u{E!=lTNU_G_V&&+K7q-u28k@#3yS zXJa<(|IF}j>B%KAEB6aCw1}v5MpWhe?fdpi(^E+xh~>BWBK9XcbNaTde_T29keTd1 z(|^4hjQbbYiBGT1etf?}&7ywo&+`8<*I51^zyDLn!?-hub9%g5akKA6gBw1}ji-2d z82_xU;`zKjIO(=~;>wV=tqHm||4SmG)ici|ojD%9wsgJv-M~qkKUN=Ge79BV>*ZPf zu`za^zE&|^(Akk1RYoe7+o09r~_uN#Ce*(cW!yHOcfZf44$rjF6*2UngFXW_x}I@ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_copper_base.png b/forestry_resources/assets/forestry/textures/blocks/engine_copper_base.png new file mode 100755 index 0000000000000000000000000000000000000000..b26eadc444dde522778a867f8b1691e419cfa0e6 GIT binary patch literal 634 zcmV-=0)_pFP)G0VNPiX-aO1Y~?xU z_s-9DXqsw9!`PT&h@2S_5r&#deJ*5ss3{1(N$92nBoW~)9U!wntboh{>431>Gh$V| zliA`a+pz)`YXbm{@VlJbCBPoOKN)Fg1sDsAV}-S`Fc!Y={JGp1j}3uujQ~H;A+ekp z-v`NLA1s|r;u8Mj>9tm7v+X=o+E5`XAhX59+>*GoOk@~aU@VvMbwc7>CqU70ZRX5= zB2s->x42c9z^4PkIIf?H#J5g>G^sl31Hjr?toBFwR(rp?s`>#gFlqnN?Qr zGUJqNg3t42`P0K+hc|}(ptmF-`_JF06FD{XE)7O>#E-N>ul_kfE1NRsh7;`;c978hhy}f?W?~s86`-lJL zw-lx2OyX=R9u=B==)~`yedODKs^_)%HJYyY);)1(*({FWfvfBhliPRO%&ddD`%=iS^k z>-G2Fzirtik`3niIl5GAlUnK3Fje-v#O8~cU%V37g68UN4&AxjlbOLFzQUw*v(fW8 z&6S*|Pgcx(DS!O-X`YV1;uhDeelFg?z|nvm&55dIyu5nej5j`NzkzYV;OXk;vd$@? F2>{=U$GHFi literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_copper_piston.png b/forestry_resources/assets/forestry/textures/blocks/engine_copper_piston.png new file mode 100755 index 0000000000000000000000000000000000000000..ab38a6e5a1d337f5e1496e72166dc54d4bb87e8f GIT binary patch literal 459 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 I&MBb@00f%Ua{vGU literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_tin_piston.png b/forestry_resources/assets/forestry/textures/blocks/engine_tin_piston.png new file mode 100755 index 0000000000000000000000000000000000000000..88d381355f2519f66dbc5d7536483fd01bcedbe1 GIT binary patch literal 1158 zcmV;11bO?3P)LOAQc9$h0C?|l&f%OxN{LbmAUs=Zan23QA*Ez*Z;z`qdEOt+9v^gm+{^Y zeP3Ii=aglM5P~F0SX*1;I_$y#_V@RB`0ydq)6;nGNs@#(ju{yl;oZA;2q6$c1ljNJ z@AK%t^DuC$s z`&3nh_nxOI20jV*C2_E4^M1Ap~if(rUHB ze>*!n%+1XKkftfd7^@ zCEk0YD5Bf#hB@B9e^0B`LTf#cL2fhvV+>iA@#V`GzJLEtnx+&*!S3!Zj~_n{DNqQ( z=;-Lcp~|vEO3BE`2p>Lt2ui4dUWWqC9Rl^m*6DQUbUH*)#Q69)&z?OCp1*zjHl0of z?>$N>q9`JYBBYd5RYjI%JbCgYs7Pzgb=iei9vd5Dc6OGcC@9Mkr4(6~p|xgVVF4*6 z-g~_Flx0b;*JEO00)Uf~6NC`lxpRkhyUo+5PyZeO&N;mI+`oT69I#Gdb*x)!iQ{-c z_75IB7%GUWsv?eKj4=oyu0;v*q9M@l_rtr^8X*MEIr{xR)>@1)6h(ox7Aa-;CM+yv zfK)>?##}i7@%i)TpKtRk|g2ar;D7T zDDd8g_gYbPuONg#DTUTL?4j-x20Zs)*7*4G+!mH zQc9te8d|G{e0o2hK7G2J0xmnj-)@qB+!_E4fCfMVpaIYTXaF<-8UPJ|20#O#0q`%{ YFN&>0;3Ks-<^TWy07*qoM6N<$g8mO8MF0Q* literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_trunk_high.png b/forestry_resources/assets/forestry/textures/blocks/engine_trunk_high.png new file mode 100755 index 0000000000000000000000000000000000000000..848b7a7833a2da24306418c3980c81cfbf738396 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N>uxxtZHZ010r`JOJ0AsP4HUO&y-pdjEHc(gtid|1E4G2XlL?c<{|tp#^ad^r5zw)h#<^8dFSzI7MwdtQ0y z!+)U75RmX-YeTVKNNvNd;D^`5wM!Ub5+M4AD*L5E-HG1czQ%&Mp00i_>zopr0QZYw A!T{XE)7O>#E-N>uxs{6ldrhFwJWm(Lkc@k8uUqpqCPO4vvg&pWlwKR>fTn_Z~eOR(D7cq zbu0Eh^-2365_;fk>U_Ci#=YSU=G$xc?3l}yVQ%!t;Kw)C;*)pxn@#weH0OQgJcB>> yK#L(jqC)q<9PUv01>Zt;d_Bq)3lj&^btf5rFVx*S&3S4Pi0|p@=d#Wzp$PzC5M3w$ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_trunk_highest.png b/forestry_resources/assets/forestry/textures/blocks/engine_trunk_highest.png new file mode 100755 index 0000000000000000000000000000000000000000..b80063ddf045bf0751f4992053fbaf45ad281156 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N>u1xGf+qBNk;dQTU}kc@k8uW#gQG7xcl7~ISs z;3h7X{OGrRPiJA`L(^AE-D+DpXHEO^M|x+=f#Z9(v=qt+OM7N+p5x2WIL&yb;8`2-zA@$KHj-Y_CkTv_tOuy z^Uv^p_iJloTl|{O)%Vm({__erFfg)!2&;eM9fr$RnFmyB-}!aEOIe|Tfr$e~)Snby Wo$j$-B(f9~8VsJUelF{r5}E+bjcZi^ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_trunk_low.png b/forestry_resources/assets/forestry/textures/blocks/engine_trunk_low.png new file mode 100755 index 0000000000000000000000000000000000000000..d0f19e6522f982018d01faac4551b1cbe20f8c62 GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N>ug&==6*D|2cDo+>3kc@k8ryt~PP!M3TOlEd( z+?JrbEuk@p$?i(OVL_)`@j|EKA-u<@6s0gv)1fk|5GKs=XbN^(|z$$ z0soKK{eN2Q^w}2Z1}HG85f8W;QNp;i|IpU>unw3og#OSK##(D;%g?oMK1jgR)z4*} HQ$iB}l~Z0C literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engine_trunk_medium.png b/forestry_resources/assets/forestry/textures/blocks/engine_trunk_medium.png new file mode 100755 index 0000000000000000000000000000000000000000..c9f1700246a528d074702c3f8e305f72f616f41c GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N>ug)G}$w_c#oVow*xkc@k8uW#gSP!MQ+X#JQe z;O5S@Xp7a+JKE;XRZej1krlYo@UXsjXF^Y%6W^7n*D3#$7j;PBz*N*6!)^#8&Uvc01?N+SCPg zjBI5e?G-)Kbeett*WYbxjqrQe6|8;f$N^FIi~BYSXZRN!%}m*#xyaUWk;-bDC1z}; zN>e#!NtoPqn<91P>tSgIpp)kw*y{f?W5;c+C)y9|{&f}?Rs~F9zka+wD0zSBO#W)d e&)++~{>p!?y6FAd3;()7LGJ15=d#Wzp$PzshssF+ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/engineclockwork.0.png b/forestry_resources/assets/forestry/textures/blocks/engineclockwork.0.png new file mode 100755 index 0000000000000000000000000000000000000000..6db55645dd2b31562c1b3a2bcfb8195847a54c30 GIT binary patch literal 481 zcmV<70UrK|P)sJ5(03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00BiwL_t(I%axPCO2a@9 zhQI8_>_TXJ6>APEUi4Pzq4ePdLGWEX_ymF%@gRtJEuN&Mw_{?nGo1{$ zxqaa;i(^SRdwNGJL9#1-@bF-ZEbVoI@9tl*)*%3F>imPXu9nngS_?#00UMM183D$l zUMGn$IU-U5t-e6XP+?47OX?y?hN?coVwsT))vv@hlEpG3EUT9@EtXkhwehIes6qH6 zp!C82n8;G+HQ1d0uWfh{%Pyo08cEtTkTO8%$`-U1NEx(hut}n|K-kpP4yj9nCX!kQ zZ5p&~!&*mpb-e;$IvEhh(x3A2k?JIhl;Gjy3 zRMTnS9%yZxJ*~9SVO`2kuW<8EU+s2V_GtYPNe{^Q7%arF$x>^=l1GpHgc2*}3VUXM zD9}nNwwu@fF5&ltDnm{r-UW|CCssw literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/enginetin.0.png b/forestry_resources/assets/forestry/textures/blocks/enginetin.0.png new file mode 100755 index 0000000000000000000000000000000000000000..dfa868c70f84b4861c934beb85642242c976adbd GIT binary patch literal 688 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Xa&_yh$7#l^)% zMMaMtJGOuS{(bxQxkktYrK$!btGGtUadUHXa&m6nx^>HzEnHk&CT^l^Y-}tnEE_g# zSigR~k&6I3JG-_mFEcaqs#UAjty||9BFW0idiwNfOCK@E5DD7=iM4Cju358Y+qP{R zH*VaqV~2!d%cgy=%MK|Bw1{74QFK{!%)8s^qfl?h z+P&t!zy9@yTBx5}KR5r`8_5O*BMF5hi#AUw+XVhgEE#7uvbO|Sby+6cB*#2?ym87x z^Fv8N1$HNwZ{9OUpTSF{W@n7;8o8@gn=dM4vNRQbPT6j~m%U5l$U?0twt4=gwQV2l z9{bIFRb&&n*0jPUE#|}3t5LP<9H$A|?6-KnX7Ap6414AqO_NLxNxgs1{?VuN>lsA! zH+}ui@1*b4;j{8fIsf5j+cPzHPG0iz*0SH+y8rptvI|u{U-AGL#|)|^t`Q|Ei6yC4 z$wjF^iowXh&`8(7T-V4T#L&>n)WFKrSlhtJ%D_P5$x)zsBn`RwDVb@NAPvU421dF@ zrXfZ~R>tO5CZ^g3hCmH9{@z=G8U#T$q-Ex$<|XE)T9p7943_ccnj7SKK*o8x`njxg HN@xNA-beo4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/escritoire.0.png b/forestry_resources/assets/forestry/textures/blocks/escritoire.0.png new file mode 100755 index 0000000000000000000000000000000000000000..b98a16547046fe60659067cb3555be7fdc25e09d GIT binary patch literal 752 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 HN@xNA-beo4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/fabricator.1.png b/forestry_resources/assets/forestry/textures/blocks/fabricator.1.png new file mode 100755 index 0000000000000000000000000000000000000000..c993c11db277327e9c507f208dcc2484adc7c943 GIT binary patch literal 1134 zcmYk5Sy0ng6vodDP>_&-m{wG*gd(M-kPyH?q$rq}ge8O!kbpo!5<=L8uv7N1Nmv!I zMbQGSg34AA;{d~wi7ZVaVFD%4W%QxbKJ>lgl>T|^!@1x6&Ya)5bMD;R%IC2O_Gj$@ zfWYN21(-S=hn*F+diglUVPdTaiw*;r>cqd7*kImG$`M2ZRCof^HUj*ErE32GD5e7Z zDF$E+0Guuu)W(JY;QaVeLe}!~^1{Nx{QUg%^t6+c6G9lxMTn13JVHVei8MYwJ~1(| zw6wIcvNAU}*W26M+S=;i-~hk@U;{)T6a{b%>kSZMZ*Q+ws|N=MS65eOXJ^~n+wpk( zuX_^~)9{{gXxA{bZ+vuMeo7z^W@cu3y2>OD!AAEoQ@ggaljqj&w0s_quv*UY(f{ zy*A(YX1-1?joQ+8D`Xhx3lMH)CC1^R4tK}OO2k>2e5HaX6?0_i5lV$XDdT5IBe(V4 z0CXFhym!CM)z@a3*7^;)9z}Ze=2FYrVuNA1H76_1Y#1by$=25Lw+Am9>$7$?2Ml_R zTpFp@)=E;@2A!s^Cd=L3-PhOmcgt*7M`=ZA`mOxLvJ#1=O?9WI%G=v}V`F1-a`I>6 z=(fK1C!J`-a zx|om?`uktZ;;gJ~KCrd3J7JG^AP~XP>7?^166wQ_PP?2rd(QPde0;$To0jbUiHFBU z&rdH9!ONNa+2`J0`1n#NR6m;Yd2l=B9}swn9u&;D9P(x8m8%dIevQexP7h*pxDk<2 z(LAt=;l~Q-al-h78;KNAQZn33VWp;tCFwzQsfZ#wV*_%R3`M3gD?2AQPn6FpxCMnp zs^XH;vhs?`s@T}Cs%@dBu(qzgp;6sLZ)UZ$l5C;vcDtsdv#UF(ht+$BOu7rizW#xG zxd{n^ufG|*Pkumvp@$DbAALJKGWy;3Wb)%DV=(UM@bua9l!?hH5^4I$3=w{KG5d0E zViNmKq{l?!E8=QBe@@}~*JbSPE~;3GDw#wjXGja>m;eo%)`v>>p;3i?evCjWBhcTQ zN@Gx|Uhi~R{r`a6e3>$%{21`}q0)S4fkGOM;ZJ7-1bS2bFrX?X@&yK*JU$^qnIq4W bxTU5R literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/fabricator.2.png b/forestry_resources/assets/forestry/textures/blocks/fabricator.2.png new file mode 100755 index 0000000000000000000000000000000000000000..22202cfd001dbe57d0714d5e944937e57d4fea64 GIT binary patch literal 922 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>5 z+qQ1qI!;bbpur3bstgQL3=E3={QQRxA3kv4z>yFFUMAucX1K0ZD|LPAkdQJI;UWo2b8 zEiDTcEI4!KjJ36OQBhHHa&mlpyq}+6LPA1*etvOrad~-pWo6~6RjaOCxpL{!B`Yhd zoSdBO?Cg?~lDfLO%a<=ZJ3AK^7B)0AG&VL?R8+XSx_WqcG&ME3ySsOFb#-=jR#jD< zKY!lB!lIy{z|zvPudi?7#EI?g?Ms#{sjshZYipY`XU@!-Gk5OX`S9VxbLY;nu&^*Q zGqbU=F)=Z*v$IP`NbKFa_tB$AtgN8WG;tF&b`fA?WVG=Y_fJxeEzlDd78Vo~ynp|` zv8$k|yHH??>Xt2A9335R-MY1G*|LQT7fzl$dH($QQ>IK=y?XW5ty}NhxpVX8&C{n( zA3b{X?%lip|NmDlWv>Mq&6wov?owrOwKWUK;VkfoEM{Qf76M_$OLy!302Q!#x;TbN zToyg^+xk#|OvA_ZGh>v`38*jGyiN3Nh_;KO;7oyQ8#89k@Gjc__5S8~`}4o|FvQAS zKl{C+>h~{pw)Q=T4IW9$Iy2e7a}=KZZ)GOW1O78-em!eC_)|bJNupUrd*X{ji-fvY zO*ta$c_GMTZk*Dh9dn`-O%^()neJQ0;t_UcZGOO`L(68|58@EzzHJ@3UE`fl>3WyX zzjwu1oS1rdrBs*ei-!}}y*@s5acps|0B<)-^EFH8Kq`GO{u@w=yx+HZTNgsPXsS p3e+G3vLP)qCp9lIH`S^H$Y8LHH#Ar+*D@Joo~Nsy%Q~loCIItlZ8iV^ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/fabricator.3.png b/forestry_resources/assets/forestry/textures/blocks/fabricator.3.png new file mode 100755 index 0000000000000000000000000000000000000000..d5f132a06534df6fc710c69b6903d41db44e5752 GIT binary patch literal 1030 zcmYjOT`*&J6#w5F5s?_NU$Q)?nRcnvxVhQ*xI>jhB!uPO1WRc`q7p(x;v>b-VrRn) z719rDsF~GvnVMY>dcF1GoZtDKIlpse&hK$fc6xw+ zh(7=zKq406B(ko7lsQVNCLwJD2i@vZEbFD zuC1-DuCDIy?-vyn<>lpx#p3Mj?3kDs08+xj!h}L$Qc@D1&kqj|UtV5zI-OFfw56q` zwzjsiva+$UvAMZ9A|fI*G*qkAn$2dtUSC{X+|||Pa5&sL@?}!xm~&Q3z)xGxHd!kF(S1PJm%g!!Q{DS>g4n|#r&m6esl!$Xls zM5R(0494l{DURc4Y7mkd_yNIAmETQ#5X?ymc<=pyqoX4~Kfl)2)}^JTv9U3m%{DSJ zGCVvyJv}`>K0Z1+Iy5xY)6=uKxajqIH#Ro5x3@hW&-(iM)z#IgOi)W&4wYu63%`Oq zvEPw|t`|S71AuYkIw03!>lJA`04Tym zqmj616p?Yc7$3p-JPv|l2om|yNzVUIpsP`7%A2kQyl4cCM)@)n#dvYpeLe@_l7i+3 onRZeTbbX;*Q>Cs}>eQH#EI`6X@s2=v_14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>i7?yScetxpL+D_3IZeUi9xXaByE=UvY79PEJlZ^y#p$u&%DIqN1XLf`an$^4i+ki4!OG_xEqwwCVEY%blH_?d|P>fq|1IP3rFM z-mqaqM@L6fQ&U@8TX=Z5t*vcMO-)r*)s`(=Zr{FbV`J0W+PZr6>brOER#a51S+hn! zK!BH*mz$fLot>SFi;IVc=fQ&q{z=L{@d|#4DyHs&j=|DSp^~04a*iRAPN7nd9zBYR ziV_qQ6cG_gNlA&!(e{c}h%L}_4wFhxPZt&z-nw<``t|GAty{Nu@7~9cAOHXVKXS+a z5@4`0CV9KNq;9?2F(1g`EbxddW?TEOb_j=y9$LGJU-Nza*K}{{yb>^&j6K90XVVyBM zJ|bq))TdLgZVl?3%6RQ+?^#{nd)LZ&HYdGhx=}s#)xO79O0FBc;_Y|%zIs;Xth3Dy zwl<5p-?q&v^AXzGw860L*U6WXjW5{}-#FebySw7?g?Da^^FOP3ueYg z4e=kQB%d;FIxW_<`t|JFyQ>Xr9&kGR>*(ckG8io54Gr%|ZUJQm22WQ% Jmvv4FO#uB`O#%P_ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/farm/band.png b/forestry_resources/assets/forestry/textures/blocks/farm/band.png new file mode 100755 index 0000000000000000000000000000000000000000..4247e1a05af643114980ca8e6c95a76209210803 GIT binary patch literal 563 zcmV-30?hr1P)WFU8GbZ8()Nlj2>E@cM*00EatL_t(I%e9kDj^Z#7 zg+DuvNkZtfn2|=Ho>Oon#348dOK!nII0GBVf*3-6jXevdGmDvNA+`GLO0M@x?^RiB zw_Dn_C5j@fwUlK^nx^!9&t|jnK@hN9E(L(rn(Ot7loIbf`~4nuzuzf}f_E5WXqpB9 zDJ4=$@;nEi>pHa709b1gLZHgB#27OOWLbtW2CX&I>6GK~NF2x1bv=;FvZQI6hsa{F z@BmHQ5RD?9MQ`tfDnPyceB*BKlw}D(nx?}P0Hs4BJsN5$1Hw^ATQ_*;5cB!m^9iWg zZ1z-RRozIEF?C%L$I0IU|Fe*$DM~7e%VSfMNyh8z3m0SPY>)hCs&x+G9oAX;&i)om zkW%2hM+NGOGU(a{J&I7F#`fJmiC%bw7f)pH{o9A{pSQ4Dt;GAC4;H$Ps;b!ScD^VI z*6XzZsOy?IjxolNWf^&%qfV#OKn%kWYb{BVkYyS1C?@_9b2uCrkH_?V&-r`?7(Sq? z>-rIj|KsF#yWyN;@-hM7a=B1d70x-l_c-T<-e2Zl;|`G5I|Bd!002ovPDHLkV1jyd B@s0oh literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/farm/control.png b/forestry_resources/assets/forestry/textures/blocks/farm/control.png new file mode 100755 index 0000000000000000000000000000000000000000..0751bccfa1ded13d3adbb3632281b6cdf335fd63 GIT binary patch literal 440 zcmV;p0Z0CcP)6h0Yynf zK~y-)rISr=!axj#zxg4Ff(T;A0ZAVxrvBnTmp61LkdT6fLHaZI{Qr?=po!x)3Lwv!CteTNlA zL6&7yRmIKRo(nvNCyX$yHE|qIj}S!*nx?^8%Vx9bI`|!-H}-P5kY(9OVAw)kH-9=2 zp`y{8f64$sC~ys8;t$%!p%y-sdyBv$v5f@)0000Ez&R)MreG9MypP!$O~KKB?(qecl9>NCCf-t#{1*Bz9g-EP}ft7XeLqUuc+_;#K%xbUGaeK%P1l{CSe(+XQJa7*MO#rh=Qz=5z~rUI6gq5Tu_z3qtisLfR{?nR ze49I4ZvZ&#_xb3_asjP1VdRs2AF_IFl^~o$FEr3vlM9dG*CVvn6vm8WrX-X713tJR z!U`OzSYABY%;n`P$iqJSuB76r*#dDK(`a0v=>A}5cZVeI(X}pd9CKWZP{Q!3_n9yZ z|6M_KDdGkmuT9S5jk{z2-a(fy?)=mYCIr$f!vFvP07*qoM6N<$f^-1pasU7T literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/farm/hatch.png b/forestry_resources/assets/forestry/textures/blocks/farm/hatch.png new file mode 100755 index 0000000000000000000000000000000000000000..0613b5d6d46fd1391d3063716464b1fc05127ec6 GIT binary patch literal 504 zcmV*ut{p6^N)#cbiuw;Qw;uB2n_Cf^^a8D-oGOK=`IxZ^lv zX^Q80jK^aE;Ov^Ug^xEk2;pF@0U%iCXF>voCb zxba|}t?<-2h{IV`pm=(GIyP~$DS@q7`d$Mt`Th-kKRVR4#+0Tp#QA&Yco?(0)a~sj zs?v}bX0NX6$P;IL&CZm+Fa3I%lNZ~GrmjfR1zEN}p`eD@Y=#vbs7i#~GX7pJ_YhN7 utd<%799NfDHVni6|BcrluJL`pb;uu5!JuX_IxpV<0000{-z BL{$I) literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/farm/reverse.png b/forestry_resources/assets/forestry/textures/blocks/farm/reverse.png new file mode 100755 index 0000000000000000000000000000000000000000..08ec6e028e624b7c1ffd635ef2d49b1255f44077 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)GcTX1^4+qTlYm0Wo-U3d7N^f%I>_5#z`+`j;rnW- z-$mA4|0A-J_@C}(obj(a=4T~KQ%CSx(=YcPrcPp+I!T_hvEaadM&ri~FB;~DNj#2Z zXYkPcZM9(4A1($9h3CD@XViXsoMQZ5S?FN9>UKS&S(d2!owoPwKWFU8GbZ8()Nlj2>E@cM*00GrWL_t(I%WacQcHAHk zgg-G15*|%h`6lsEd;=fA=kdmu@d$=>)IY-xZxe&lw%Q%kt%zMu?O@t6oWm)FV&beH;EXy}k z`~Cg>J%_^qrPOZ<>B7FqIrq={a=B2~HAxQxh6AR-w-UDtWg?RGEMetuGxB~?{XRTbknQat>8i2b$abgqGjQU|sz z5JJFOOVc!*&u9J@B7$z(=8sVAx8$~MSZkT*84*E5^0V$kKR!Mdd+tf3wrzQPdyB{8 zk*BApB5AT08bCScaL(n#vMg9@Da(>1aJrlZ?O#Zz)Q00000 LNkvXXu0mjf)OQNk literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/farm/valve.png b/forestry_resources/assets/forestry/textures/blocks/farm/valve.png new file mode 100755 index 0000000000000000000000000000000000000000..c5fbe90be87f83ad4cf325ca53e709a79f71b578 GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)GcTVx+Y%T3a0UiOeNPw15R21uCp+dHG7xZ$e{|%a zr?=FCh6yiZ1-{!esb{VT;aF0*;jSyUl5SyOdTQps`gxN52ZdK(J*6wg{rqyvzLY=_ z5!Z*41?KR-{(9@Guk*B}Hzx1Y6bn4EaFqlPTaMXm1_dkiwawd$x{YHuPZ3&Mn$Ifk zAaUUF2S!DfV-nwf%U+9W5is#RTw(Jwo2@ToX?U7@Y<)l|`y!2HI`RLRSTfe$e0y*I z*{`a>*G&s`ZsvJ2T+(@4&zhZkyoQ&vY5h!j{^NBAB1<;kF?f^jcuJySTW+A&Um>lf ze;C$AGpJ2YKTxXRrP*U?DD&)lZqhva#50{L6ID7{WENk%v7g;O@bb-`uH->FN63n{+WFU8GbZ8()Nlj2>E@cM*00D4GL_t(I%e9kDYTPgs z$A5l$lErwD8R(`ki$F>tkP~DR=%U?rlUwv2xj=8x8}t@)gHjCHHOUM%lE-$sm`d0Q zGgKiCXWq(ezg#E)O&l;%pw|~mHuVl`3O-%F zW7~E(6#zE%jwTLVUo4rHcbe~M*N*^Hr6F`ZP6h8YU#?06z_*`~+w+zmzZTq{Km1!; z#HrB4Va5=;p3wD&@BKIfd|5JO@lHvKl230XgB=BUYtv*XKS@nNlm?%%JPXS0N@9sXHeXIF&qw zDa6ERq{!hO1@KPsR$eh}+wLGg&q4e@8R*Llrq#rOsx-6VdNYG*Riz>9N1O`ZKbJts zmn&u4T5diHP@B{mAb>f%+ljAH5a46*l#buphJ4^hVyFmHY+E56yGN_R#bI O00007J6Hye#e{*LhnL1D#)Gj0-R;tmu2nDO{#;wo2B8m$QK?K2#|9~#s2ttuk z>qZgWYjAA^LtRDiNohn7+Krl`u``p*jEi)x(^N5a0%>%<&7E^I-+g>J=ghfRIW)A% zCnCO7YXH<-A6->QnL3}o)ey?hKF?=`4UjVRw(z4si#kAGkH(R`o3UyhhAybuF6orP z{GyGa3jnINiz*ap2k$asN#`o&(=P8~DbwQNMx z0X)CqqLx#a8xL@L#9(>}ZsqnMasrVPeEl$o<p_69pLssgJP-7I2iyQoEf6GKTSGiAe06_oiga{Pq#d0nBQ>$f}|Aw*MrR# zOJ(k79RLb>7jM$z#NAgol?CP(ZONHmv~em6Ezj4?@3;VlE~E>OW(O$bT?%;@fN?T> zp4diV_?-+7%c;wZ-pp?`1j77vlLP}io|tVsWPwtdE4wX3PH;Fs$nhJ4%xpRE8@|2f zxz<$@JUwEt_vULE0^?*j|HR_ur9HCm;pN$XFA1tb!ANM_dv0<4%`PtTmQ$q!#Zpi3Eu>i3E lu>i3Eu>i3Eu>k)oegInRr4)Jj;lBU?002ovPDHLkV1lnkpLGBL literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/fermenter_tank_product_empty.png b/forestry_resources/assets/forestry/textures/blocks/fermenter_tank_product_empty.png new file mode 100755 index 0000000000000000000000000000000000000000..bb05307e2adff0f3a359e41b04a44a675c35fa76 GIT binary patch literal 846 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 QFaQ7m07*qoM6N<$f{LntB>(^b literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_empty.png b/forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_empty.png new file mode 100755 index 0000000000000000000000000000000000000000..bb05307e2adff0f3a359e41b04a44a675c35fa76 GIT binary patch literal 846 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_maximum.png b/forestry_resources/assets/forestry/textures/blocks/fermenter_tank_resource_maximum.png new file mode 100755 index 0000000000000000000000000000000000000000..7e3e8bbb230ec3920cdae5ce70aa47f5f226af7b GIT binary patch literal 830 zcmV-E1Ht@>P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipo4 z2qgndy5TMW00O>AL_t(&-tAXAkJCUHoPBt`ih+wI3Xt6J5QvHf=_E=ddOH3E4U|{W zTn+z%pFo-FKqrtQ(QpMwC{hZfOMJnRpBswY`uxh>Mglv9r}KI}Ui+J!{f1xzMz5c& zq~HL6FiuPNs^d~{gmH>(=I`&O*iyMRmaYjF@W;8{`hU??+WOq8+wtWlNk=; zV~kE_c=P87M?d`h`XD~8{Vdb@JO2Zu;KmCr%Ks`fDWyx0%RHb-&Vp0?i}C00zLK3+ zK()#@1_E)aYU6^_t>^EI0^YxTxB`GMQIOVpVPT?>sTCZX<=40OY)ob$9GjKq22lpb zW|%KiSd4&Cl0Q3NrjQmbT@MF5e~wX7dZ)A~UVZr9sxmkL?B8`uave_=0D#Bd_0r@A zx2`qHdOTUcVg%0~-K_BhQHH1YhDO^%zqj=*P?WJ09ATmmM46GRYl%BHtMTY@0HtR> ze*2BL>Pv|`P8GsLwciKm4=pt+=dv_$cEM@B4VupRFi~rs_-Y>g-c}Xhxe`+Fl34{& zhWRozKCbk~H}Ob|8uJv3(b^A~`cX}~o-1K7VtlsGmnniMYvc){%$Ub>W&2y8C_7!L zsULw+Vq7_kk<#LeJf16!d8U5UjS1?CX$kA2%cOEra4Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipo4 z2qY1v7@;Qs00P}fL_t(&-tAXCZ__{+e(uBeDFK>D3?OAFr2;XrAVn}%>dsQ}Cn^>g z*}EaZzd-#5Wy(|#5>iGY1QCjqjU+9xeEteUdyYRY?L`7RgP+Cn`TY2N?{m-lz62}K zd-Y@?Yz_eM{4nz@KQ3$z&kwQA{O-{wf(-y)^+5epe(cQk0c6M3&#yCoQ$SZeP>bvh zCV1n2L2od@>p!PB{V~Jgi9~NO!QqK4Y?kT#jo$!abK`}k<$oP?N~sd$Di6@f+2$1g zVtoJISF-U6$Vd5B!-gNmg>jqHwdZe)0^YxPxBvhzh#{v62fbLE^BiH`u z902gRb2Bsf!JQjgS@%chuo%JKquT|Zxs34ae#_{1sPC4(0eKlK1t?elxcwdb!`A4!(`J-*b(1n!<#`>CsRvY59#cliGGdp}QzmE< zIX{dGCYa_i%_e>rS7L%(MabsMNHI!`J;3HPsRDI8d4*lY!)W>K0nbP1%=IBGYV6+W zv#aAVtpjQgsK^6&(_zI14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Xa&_yh$7#l^)% zMMaMtJGOuS{(bxQxkktYrK$!btGGtUadUHXa&m6nx^>HzEnHk&CT^l^Y-}tnEE_g# zSigR~k&6I3JG-_mFEcaqs#UAjty||9BFW0idiwNfOCK@E5DD7=iM4Cju358Y+qP{R zH*VaqV~2!d%cgy=%MK|Bw1{74QFK{!%)8s^qfl?h z+P&t!zy9@yTBx5}KR5r`8_5O*BMF5hi#AUw+XVhgEE#7uvbO|Sby+6cB*#2?ym87x z^Fv8N1$HNwZ{9OUpTSF{W@n7;8o8@gn=dM4vNRQbPT6j~m%U5l$U?0twt4=gwQV2l z9{bIFRb&&n*0jPUE#|}3t5LP<9H$A|?6-KnX7Ap6414AqO_NLxNxgs1{?VuN>lsA! zH+}ui@1*b4;j{8fIsf5j+cPzHPG0iz*0SH+y8rptvI|u{U-AGL#|)|^t`Q|Ei6yC4 z$wjF^iowXh&`8(7T-V4T#L&>n)WFKrSlhtJ%D_P5$x)zsBn`RwDVb@NAPvU421dF@ zrXfZ~R>tO5CZ^g3hCmH9{@z=G8U#T$q-Ex$<|XE)T9p7943_ccnj7SKK*o8x`njxg HN@xNA-beo4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/generator_base.png b/forestry_resources/assets/forestry/textures/blocks/generator_base.png new file mode 100755 index 0000000000000000000000000000000000000000..3c80f3d54816d5230a91e4744499f22ad8204dc1 GIT binary patch literal 875 zcmV-x1C;!UP)w2*^?gWBheF$f{R7y}W(S_`f9%6CdBSi5Qh z5rHuVtu>4>V2stSb9Z;w#(W5LB(vFU>7H|r@puf+^I)xoQfleFF$O0mC$;)oYxus8 zJkOCN38E;15UZx1pP#q3yAuEwivR!Z60c8;Dz zYwgm)7_+f{p68v|(Hj7TNGb9D{@&aAqOXP1GE@Lv_*_g$&mR7RuG*6Vf(fKsZlMz53I-CY+6MD%l0z*@UCBjGvVQ>2&HU0q4B2xiQ8-YmFcXT=+^U5y!DBsq31eYPxj60qpVd(H0C`KA1=;VXa-- z!NQ2@DXjRmaD1I%WhctB04e2KKB&GcfU0YT%E#|wji!GKYb|E88ImM%N*^B|u-0Nc z9*I z9RCHN2oou#8)a3;TXl_!@B57n4CmZA#5rF|iy~!;aBZ3gl*6_dtu^)kRmZJJ zQyNNI))L~1U1deFL0aAFth?q;T3G)8W+uhOBmbCLXb!KUeU+_wp7HzMd*AzPa(a5o zA+fEkt-?L$9E>q=E_D~CX&N+50{}ccJShFT-7coVjK>^KPEHWVG4Aj0l|K9X`{Mfe z_!zcrV>B8)$-i#XCM||xh?5`x#4q>1!t*@5d-now-n@k8dHDYATYUHWb-{l)9O92x zf8nRm&rkB7dI0Y3?m+q!_74jHfcNj$@cHv^7>~#J=fejix{f%G3(q|Koe2L=pVsl^ z%kN*WKYoPSXgt~)&uv7-0h^nf7!HTxK21|;|2LaWXqpCH*U|6yVVWj%T~{8sw6p}y zIj*j*rk?|rmzPDxCXrvp4{K{{6Az=5f-xpYaw;ky48uZXyrfN-1`CccuG`$72A%U@$Jrpc*dACqn_vC z?Ch*?hU>c1A%v17kutun>mY=n-ENEE4Z{$uXg;qbL%Y_kACZ;~Z@ts!33` z`T2Pz;qC0~Jb9mQ3c$+B3M|Vil(}ITSY2IJ2A`&B1)NOjW&0S0fxW#w3p&2Fv-T#zmN)KCMfeCI ziS6L^uXew8y>>!D?62=>;&|8Vowsjh-k8SYaSn@}oSY!ftwR8SEXyE-001z?;5bg@ zJlA!#dyeDa_4O5PFt=(zIzJkXN@GcqAW0JS|N8n`T^HxiW;1ZkF>A=PxfW(H3KM zgHaSA3`0CTJgDE((^K5v-(xr&VmuxL0EkGNe|L9>!^1`Z&U2yW{EurXq_ zT9p@Jf0v2l7=yt;yVqu;svK~9e2gfH002S=q-k1ym2m$~A=N$iv(dXx9Wk7y^f0yFbbk3Z!iStBMnFqGb z4A+*uFD@>WV>dT9%CViD9qr-SY=%6~adma2=E$%q(!IEL9LM0Cml!19*+>$U**gqF z?Nq1Jsmk`}=jU2BKRPZeIK6ZRaOPpbt^@XqM7T~hSFlOXh#{G&*$1kZJB&NpKFfUz%k?9M(tub zZBiGwHpl9uZPEE&uUC&QV@fVdGyk_j2*q)%PRsXwtMf&G0HELR*Dl=e_pQzr1(Heq zCdwz1R3svJo>y|-)Bsfir)Zw%X}!WabxA}Ut@~>Xkj~qh9?6bkCs!wPJQu~=xEXN;A~oavn7 zI2u5$e5--CJ*m xw~ct)jNw1G4uB4T4uB4T4uB4T4uJpH{s7U;n`IC=vDp9s002ovPDHLkV1lQBsapU5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_high.png b/forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_high.png new file mode 100755 index 0000000000000000000000000000000000000000..9c86c0edd74bb9b01ea99c02c7cf0eb8c8447630 GIT binary patch literal 970 zcmV;*12z1KP)tSM2Fm&z{UyZAwh(m6c$-a`@3^9m^9;NSp7p&SALFvgJQ zIRHS@H0ZisJI^o-=|5f9aeI4x@l%n77 zOV^*Co?=}>YZ~-@ACBYT$NSIX^YHKx-`{y~T^F9`0RRXgmHE57yZHIx3yzMC#PwHK zR}#5vPe54_^C(1?Wz|KrzstmNj9C~!(=@yp46yD&>T1CL{yu!)2LR-Gjxd&Yh@U!>V0x@B7j|7TnJ!;Qcln3a}-5^v$HcXho{Y=+!xo5 z;~13Eih}q(S5gFd^>!Rb+STcF3fFb<>(e(JA0JEIU~g{^H#avTB`BpBkH_$RUm}6W z_4PFz$HDaDSGcY#t>rilCX>lZx@D-gaAdX|P zTf^Z{34W2FzG=cV&BldI(`*G_mi{W*r^cNfAq19XRlqaG#LkmHY0=Xg?E@^!lFkZk z=M6$gt#Rr^0UW&Q(8Ja70<7O!@GQ$x+U2@*s=Ie*1W-zqa$YnzA~nzqel!{hSJ)Jb z>GXDBfiZ?OO_w6>pIhNP&!q=33FG%VwoI|(;FBb2eTl;I9J;P!WDOBT5waDyKcxb~Fq9r%)3nw$r|Y^zkm|%(PAjge zSs1Kr*OhIsymM{EuGi~TDtDWqVT_?q=~5k{v(w1 s@XBLDz=nVg0UH7~1Z)V{5b%2AH&uVLt*EsoGXMYp07*qoM6N<$f?tNU%>V!Z literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_low.png b/forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_low.png new file mode 100755 index 0000000000000000000000000000000000000000..b76fba48de244e3e0c1d18f57ffa417b615f8f12 GIT binary patch literal 890 zcmV-=1BLvFP)U-wB%iQfu>X*hkv||!3V)0{clH)elfq33 zE0PtY{Q#foM)P*^sLcn;O*@VRWLJafIB}N4pU>k@5A?faX%Og#C3B1YPAAm46Rm6TL1X? zh^m;8H|V-9Y}>}~AHQJRHpb&IZf|cfnM~j~4qjhh0RTjln&0d7Fq_SAcXx;Jcr4Z@ z!L2+1I!5gG`}8Kp-)%h4OFgTyQC1GPzP^U*x&VMEiVy@rdNC2Y-L7E3VzCfoD($&l zU0neH=JR>Aa{&L?D2fnLv6{r$a^&HMd6X0w?H3C0+P!y#PPl|bOe*G{KXIF2Lkd4*Xl z7AL6=sZ`BRm0PFN$*l^eX=aKbK{GQq)nL2bR-+7VHXF%#T_)dbHqw2&-7bvxB5I#f z7nnN7@}zCqQ|0?`xm;B_~QUMb7Kwa?zTTg#cqrOJ`N!WL1NtU0hsb z_6vF86ow&!Aow26iFXaHres!XSdsxemMu#^SqNKOQ{U*b~~)sYss-P$&Nek z`+nh1lw=rv2dslLV7uK)A8!~2&d$yXH%J1c>loFrO0ud7B~p|@_2i0@oerELLBknP zra~O88~phAh?mQycwkwUsK+`@PehXQmzS5~`sL+CYHrlOOFDq9_6Y z7>0pHqmen!G)?JVqtU=*GC>v0%o^a%kH_QGnD6`WeP3KZKR=8A$@#A9f-#2k^K)ta za5zL&%*Y#b90#^-cFv? zVd~U-Fc=8OMx&8%tkr5si(S`69LIQidJ=PZ*d*zm+}ra!Fve00;?F#Z2y*qdZCg6k z<#H+1{^8+4QuCXe8@P{eA|x1N7>~zr97h6y8(;hT%MbMXeQ7V-wlSa2Pm&!{Qq515 zTc^{>%?hSzW)?w$W@fI`V6)j&BMq+CYsqAKx+7sh)LwNF_Wm^#PuO53uh z%J<>ra#hVp7B57EPN$=FUOo9{vzfbbv)L?kUZwsi(x<^IJ0e26-A*~L)&N-rjv5xp zUZIHkL{w_ugE4?RuWNcZJCdDTk@LE8xoFMFLVz)*rL$V#WMzY-U0hsb_6vF86ow&! zAowtF2PuW4D3V^Jtl079XS>~&emDo!^SqOZrIZG@+bveBmE>3%vE$DBzF+teB^gE^ z0qful*lae^%NvG)v$M0p4Uz!qIz~0DlB}viiWF&3J-H&W(}7b|&~OHn$q+~D1{aG( zyj(8D4a>4bKGxOrL?k(Xd3h=Rzr4Ii&5inXDF}kxQ@1P&v)SzU0F*68h$xpCStV~A z#~>o@w*~dtM{kFZjd&$X;TnJ%fEs`rfEs`rfEs`rfdA3{03T6`wn~fMV*mgE07*qo IM6N<$f&w6yO8@`> literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_medium.png b/forestry_resources/assets/forestry/textures/blocks/generator_tank_resource_medium.png new file mode 100755 index 0000000000000000000000000000000000000000..255bc1f9c12e12a550b577b55f3f59d2839e6391 GIT binary patch literal 896 zcmV-`1AqL9P)T6T0}V+; zK~!ko?O3}`<3JQW*YOaNNPGYik|jz|NM*?le8T>~?ms{o@c}dx`4~EPumv=cHVs9D z6k%z9zQ#8TMq53K@)zy`#2CnPk{QMlx&(9(x7-N`BCh$B@0)ZQ^1W!*-a2!Xf zEVgZ9KA-QUI^dfkjNxLU0w=XIHUwOUEn{eHhP z-m9p+PhDW@94nKybx)P=!{u^Q&B%%uBEn!W&^oW4e7D;z-MHKBRywaze;?)3;L47O z(C_zi&Z`=rNZ_bpk?j?#s82+-_Wd#jaOZVR4`)ZVldE!GCzq?%>@5TsV_G_^0;i}N zWbNqasIXrs3#T}a5k=9bf%_6EoFs|#B6X7;Z+hu@E;b%M$fir|F4Ea{l=ESp2`gzn7XD_3Kg;MWv^1Sr%Sj zUw02cT`@vLrOYUjylI+(h_v4p)MxL!9o{wKjg-PI04)G504)G504)G504)Ijqx}K? W^Ne14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>I!ktS?L;nB&-y(U`6KEo1NswPKgTu2MX&_FLx4Vnvo4lhkfv%BBh@p{{v5A$5iMD}}m4QK)hTQy=%(P07 z24h_VLtO*Y5JNL712ZdApaw&rhSdxr%|H#xARE#$b5ipXb5pHKfDDF$#Pn3XN_|7K a*my9r0>sR|kyHRw&fw|l=d#Wzp$PyqeUs4u literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeBalsa.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeBalsa.png new file mode 100755 index 0000000000000000000000000000000000000000..17e102b9190e4eee996287230e7f62aca5a3fbee GIT binary patch literal 452 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF1vc;Vkfo zEM{Qf76M_$OLy!300mP$T^vI=t|uorFt|xLdp0x%G8{2T5=vn*oY6B^WC~9sPule- zO-kwt&J$1GIK#4NTA+oa;F7jbPs^E{Cj`tmjmp9pxHL4{!Zt80ZD>08)W<79*xF~t z3=xN(NhvE*bo=IjdTqSbd5|x z42`UeO{`2zv<-}`3=G;t8FNuIKd4a7@Aobm|2+uH5dXltY#2t z25L|S*^ri*lbV;9n`%`8WH1yYrl;yv>KmHH#)Fv^AZGTBqynIF22WQ%mvv4FO#m+D BfXDy< literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeBaobab.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeBaobab.png new file mode 100755 index 0000000000000000000000000000000000000000..8b1bd62b7bcb899d29d2db844d82bf359a158010 GIT binary patch literal 710 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>iTCFh-Wz<;4${CG`k%2R$S;_|;n|He5GTpo-6gmxU6u{V;VkfoEM{Qf76M_$OLy!300lceT^vIs zE+;26FuAdX95~UU#Pq~qvw@M4=jKgDn~gRqglyPoT(F@?>Gi`$&m2vsPVbLrn5nO! zqNAkM_MqF_!^`vZiBktzpNNV~oe~;y^#Ri>saa9CtaeouFxE0VD<=yF8}De?*}8P< z*50+UF$eA)ym<2F(W|_Py}R3&Pv6cz$-3t6A7-ZJ13nCskMQOe&vpjJGlOc0YeY#( zVo9o1a#1RfVlXl=G}1LR&^0m%F*LF=HnB1>(Kax$GB9WpWz0p9nN|tXV61Ck zsB2&vVrXV%U}j|s)L;nIu$n=n8K^-SWJ6kJPHJ9aZmLxYkik%pn4YRvsc&c&8xLky WfSB1gk_v#z89ZJ6T-G@yGywpyo+otx literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeCherry.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeCherry.png new file mode 100755 index 0000000000000000000000000000000000000000..2fb5166bdc502ee14b068177d17c35bcf72c7bd3 GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFlL`8Hs;r6UgmM=bxGU(p-9fp)5vxJHzuB$lLFB^RXv zDF!10LnB>716?DN5JMv?V-qVA6Kw+{D+7ZzQN~;p4Y~O#nQ4_E4aT|#hPno(A%XWK{lji=A`B&=B8Se02vGgiRr0&mHLKevGHJL1&En_BdGwW OoWax8&t;ucLK6T`sfcj^ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeChestnut.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeChestnut.png new file mode 100755 index 0000000000000000000000000000000000000000..5dcb615620f78cab26ad2e1e1d68c8c873ad3944 GIT binary patch literal 577 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>8i>V#|1@sIV6P#m!^f4WW^LDg$CN%m!^gLSefM}Mb#H1 z)a51w_&O|}+O?>s{{R2~OR7$_10BIw666=m;PC858iY%e^acq09xU)lh z>J|onlTVB+W)Im7WO@^MCeQOpe{!dhwduf-(^qHBese#_G~J|8z~SK97SX$J`Hy@o z+4n_EZ?efx(=`<}yMN!Q=&ZE!D%6mR-{^P0a+=S<)tSK`{*^5J$+Ss{#r2SYtu)Xn zswJ)wB`Jv|saDBFsX&Us$iUD@*U&)M$Rxzj$jaEn%EUz5z{twLpiPu97ezyEeoAIq zB}jv@u7RPhfoX`LnU#T=l_^kzAyC6=29ai<24#>9X_+~xd5O8HRwY0NLqTGCs$QkO cp;>G^m{|d0X5UCE04itjboFyt=akR{08`PxumAu6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeDate.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeDate.png new file mode 100755 index 0000000000000000000000000000000000000000..e1471a6dd10799a90c492ff5326a54fd274d353f GIT binary patch literal 410 zcmV;L0cHM)P)xEjfGZM zc#T$^246uFCE>&vs0bA55Y^G&Vp<#mT8zM@MZA4Npy_WJbV zw?B#(fVJh4?A2H0%N}^POi{SH>+ov=5h0%*=T8;91FH0LkJI8Wr~m)}07*qoM6N<$ Eg57YZ`v3p{ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeEbony.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeEbony.png new file mode 100755 index 0000000000000000000000000000000000000000..5abe90c29823e8646c7998ac4c4384a56cfeaece GIT binary patch literal 547 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>VIZVSVK-gb-H(b zwtquz;PL5!i<<+@?6~IF`&OoT)n)s476&YA3t8G4GOx~ONlVb?p0H!n0;)57{{R1f zWZ~@hKr0zbg8YIR9G=}s196hP-Cb0+u>G6~vL>4nJa0`Jj$(uckp*7Fp=KFg0rVzpEeaHMC_hyKm;FfkT5|m(7><9@e_AC%y zTB^LH?d5_u3vYi>-*wyFc8l7=7kv+>1hX!+<6V6ALd#7#Zd>i!YbADdGatEp_5Zdz z@A!l5;=MojU48z1zpX6us)D80Jb~7$mbgZgq$HN4S|t~y0x1R~14AQSLjzqSlMq8A zD`OKY6BBI%BP#=gHc`f06b-rgDVb@NAPvU428Ox@rXhxARt9EPra%pbKn<%IM4Evb zltDJ6W#**jCFZ7Dl>iwG1&QgYdX@TyX0h>LW(A0ueIuy=sGPym)z4*}Q$iB}vDvzv literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeGigant.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeGigant.png new file mode 100755 index 0000000000000000000000000000000000000000..403a85b6223a416d81d815fcd5a7baac9d134222 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggq79k-GLD$u(hk-)>JzX3_EKZ-Du+i&qfJoc^nEW7J zEkonzKi6uhokVSXuR zmlVT-8DbX8qGT1KCr#VEmCd1IN@^yn$Lt8P`5fiE4ePS*#UBehAkJYPH8Z&TTqiIn O7(8A5T-G@yGywqNE}Cip literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeKapok.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeKapok.png new file mode 100755 index 0000000000000000000000000000000000000000..1f25f9b416a152117bb0155d1e73d098ca5abafb GIT binary patch literal 598 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>7fQ@x_Y|m zK~awGepY5SdeL!V{y|Qm5$=A04keX2jvnS-K{ipbKBCgRp%HE=X<=cJjxMg&8TqO4 zDG8amHQ_OZE+C|DXCUXC2Uej3q&S z!3+-1Zlr-YN#5=*#^zUR;(#2^0*}aI1_o{+5N5n|x9$&6u+r1TF+}2WXn#20AqO58 z+anT85=<@koH_U2{a>IXl=SxJC!1dBi~b7wAu^n5i7qXxJbYit2+uKF^3u(Nds(v+ zZ*KWNm(6+pzju0SupPc=u|#Q>Px|Mhm*#CcbW4u=uEy=P8r!VdJHE63kFKk(Gf#n5D+4ntQ=kSzpoY~9BF#Vz${-uk vGILV%5_40nN`MT8g2ePxy-IyUv)FhrvjW7-zL8V_RLgTe~DWM4f#zeX? literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLarch.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLarch.png new file mode 100755 index 0000000000000000000000000000000000000000..6ff0f57e07bf28a604cf8825fbd40d6aa870689d GIT binary patch literal 605 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Jw(_7VQ z@_`JAglJDQml^5FA`xNJS|-o$nyn_J+~VilR?;+~Z%$)%2P4o9F{!GUi2UTTuG(oO zzM&a$c|~O%0zm>bVd0T}K^@6St;KD1>G>7z_AxH*A@e zqLba7(h_R2{X>Gy?NaP5jYMQTv~+@XRQ~_}|Iug;(5(ziB|(0{4Da34j4lFsj7i?^ zF8az>6a;}B&H|6fVg?3oArNM~bhqvgP_Wz6#W6(Ua&7-{p+g2dE~)F8mZ^McxtA^T zk(Gf#n5D+4ntQ=kSzpoY~9 zBF#Vz${-ukGILV%5_40nN`MT8g2ePxy-IyUv)FhrvjW7-zL8V_RLgTe~DWM4f Dm1xFH literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLemon.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLemon.png new file mode 100755 index 0000000000000000000000000000000000000000..bc9bdb8f2d5e5b9b7195c78c9fca62928818d8d3 GIT binary patch literal 591 zcmV-V0+mql~-j%3*`?4;QdSnx2s9xsfID=*_Httw4b<JsTS>GJkuK8Sn+3Y&$%lAobg%Cp0mURHWHeLZ>mMq6a=|0@OzHAh6drso@9mgmC zzP7Ek`yd9*_{}>v7}>8%Zy-SXz{TRy%8^=SkiqNaRa~wPd-XlksyXm8DZ_r+h}Vxx dwy}n&eglUfywqEl7;69k002ovPDHLkV1gN=599y< literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLime.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeLime.png new file mode 100755 index 0000000000000000000000000000000000000000..f727cc0d3f23373bdabff25572d3198b37dd7407 GIT binary patch literal 451 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFDpBPuWS|NnmvwuRq;su@dy{DK)Ap4~_Tagw~< zU3kB3N&E`ra29w(7Bet#3xP1>rMq>1fPxX8E{-7_*OL<%m>AhO5<*%o@u)Q=v<0kK z$u;BPBoUTSVHJ)*-4hXPVQ1H+++z{c44HK#f+5XRQ`50!hKi&j+q9_;zF|gUO_QmvAUQh^kMk%6I+uAzahkx7W5 zk(IHDm5GVAfsvJgL7OOJE{cZS{FKbJN{|L)T?0d11Je*gGb;l#D^s8bL!gG$3?j`y z4ay)J(lT>W^AdAYtxA9lhJwWORJ}@lL$la;FtY;0%)XIS094N4>FVdQ&MBb@0H0lY AssI20 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeMahoe.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeMahoe.png new file mode 100755 index 0000000000000000000000000000000000000000..e39fe638db1ac5aa6783e31defb62352adfb6960 GIT binary patch literal 601 zcmV-f0;c_mP)|W zK~y-)y_3Of6HyR{zqh6mh?OQZkt!9nC5;q3l$sEvkb@wK7Q~wuA&3_*h5Q|X3Z6U! zylU}K@KDLYq9i6agMl^0TDxf*vx_8KcVk?`^H7o|>Dr_3IP+uPe7~82|M`;Xs2q+d zZX!2fG98tMW)X>p26CQZp_;2RKIt3y(aZJN^DoF>{}L7 zr?2$#!p*Gfi3O=B3QcpL@bo2qwSQyVHq}mtGjp`*MIFm45z8LGLC2 z@a@bne|~|D(KmdktsR+`ny(*DVRgAYTpfUO6BGRT8sx|BE7$u_jys<5K!Bf?jo14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>75n1alReZ*~)%GE9Z94>ZshXX!4?oE%PTduU;@= z+04!@3nx!$DsCxCuFZ~V%8xHe4D71NSUS0R_sSXj*Up{SQzI_R+EJV`x1&5S(tS>Q zS$$?iLsq1sDQ9b5?1b|4&eHUTte9zy1ruwsC6(Cz|NrlIJpkl3#*!evUYedQ|(fs^60fZPKbPf^ z>o)H!)aW`|BpS=P*8KL}e+i4HSlrrhVe+QEU7w%6Vkiv#egDu~xg2S^^WmTWE#hBW z&YJpA=}QvO392Qo5hW>!C8<`)MX5lF!N|bSNY~In*T^Kq(8$Wz#LC1(+rY@mz@SZ( zF&9NcZhlH;S|vz>v95uku7PQYp_!F|nUyI}gCS7EY6g*Jpax}-4QZJ! zrK1~~n8#OmN^6Lp9;a$Qg1;3@0o~B#C}Pt6Zjk1eU93#*D*$Kbaf0Emn7c}fe0Qi0 zfR)L8#p6@SEqKBF-Z;9UNg{TM)0s|nc`fQ|!5{F-=*W;X=Cs*wVW785%8GM{CLBnH zo4MUFDihT-y=`GB{GBazIpq+*d3T86iy(ErDYlju*+^U9C}Pso-cH}l2g_CdBal=c zrc)ZSTET?IH}8qX4sjQ{9)3vvfLA;|m5z!5qUH&+-$ns&7rI#ga-iJnAc^fzRPhJA z63L8ETv}pDv^=ES=&0{ub7PfP1sd0X(^b07*qo IM6N<$g7#kN%m4rY literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePapaya.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePapaya.png new file mode 100755 index 0000000000000000000000000000000000000000..8c14f02d456895c57a9d25305a8d12283f1adc57 GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggq7Isb%tq;%TR2Uc-H9cJ%Lo7}wCrGgN7`O%QJ@kM2 z`Ff)c?@h*EOzjd>t}&?1c=ma@o#7F!mj*4X*&bXC2wDF@emS>Ig^6TY&CYWNfS};t z74^2ix9=M&ML$qoeq_OFjS~+7H_jG3$}pp;s5+Sq1nM|L+a9a?8)uy0G0t1uB$q98wPi%PoJ9mmfq9gx;*!%g$ zEk>)1cbwKRdQr$>cqidE1OMcGZ)a?5Hs1Bi$oGG?Hka|A|KF!Se0=>rkNQlx2_kz7 yocqq6|Ko2U`+!+K?oQ%@6AX-;qHMEvF)+AqD41Qmx|atSjtrizelF{r5}E)~$E+d% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePine.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePine.png new file mode 100755 index 0000000000000000000000000000000000000000..e9f6177de8f1f04f13e5e227a27bcd866e1fc770 GIT binary patch literal 436 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF1vc;Vkfo zEM{Qf76M_$OLy!300l!mT^vI=t|uoPV3QDCz?0~x(X7hgW2m}@P6b9m z_Rmgi6N*Gt1=R)FC(PNs+e_1<#dE1g48x+cE0-`PZKztva>QXG$BL8djs~!4pWtH1 z>*9*LGK2pt&;r#G*NBpo#FA92S literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePlum.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treePlum.png new file mode 100755 index 0000000000000000000000000000000000000000..22e4be35932884d636579839a73a661c2995797d GIT binary patch literal 588 zcmV-S0<-;zP);N+`_S$kn_%o&0WB&xy!VKR#``E_<~uDI zxe5SFh9lxbicILLY*>CzRfkDpkrRyXZ6o&aFgY@bAF2e-%jcOOu9Zs%wHGvQr-*5=iE zb5MKT`1-f+yj@!%v?qeF?SRUjhvdc6(sN$Fe1-F6g+sA@J)cSa+ozp9cLCQC)V02z aHNOF&_{3FDkYX$V0000cE@$_Jou zbo{NhyHmJ5(W}KRM713#>I!ODXs5zq`M>zc22*apk=lOjL%>r9tOa3T!1$7XTZvOmV2kl+m*}R$u)rXm5-T>VJ2f( zX`AMAQ@6Bj0h=2IhSCWDh9^hy9G6fegkP>xyXhf5@`_AJrX~hk2efZtbE5#j6d=bl zgsmrZRpL1=su-gA+~nf2#N2WQ&K`mv5uo}$q*bwkO!XrYiprJ7h#Bl{?TR0Pl%39L zD{UhZ3IO-~B@m_{4ut2pn8_H8+6yuz0mQ;`=I1ESEY0fosKSVcdA#rCaC=|;io`#u h{8~=u*K!?y;|GTBjdjgl6;S{H002ovPDHLkV1l0F&|Uxl literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeRubber.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeRubber.png new file mode 100755 index 0000000000000000000000000000000000000000..09f7bf036afca364f4f0e09cb5edb25616e5c172 GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LY0rWU6EtWvS<> z7honO%)zWD%XKW1X?`eUnH}T*|NpxjK0gO4Vk`;r3ubV5b|VeMN%D4g;mWx1B@D>n zEbxddW?UO_QmvAUQh^kMk%6I+u7SC(kwJ)|p_QqDm8r3|fsvJg zfyR@gK=nu(a`RI%(<(t4jCBo+bd5|yjEt;|&8 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeSequioa.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeSequioa.png new file mode 100755 index 0000000000000000000000000000000000000000..9254883e44518b583f17a02170f6fce5dc465152 GIT binary patch literal 482 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a> zomLm6>EWhbo*I(^b^8PK|NsAA@7VqrXeeVzkY6x^!?PP{AWo9EyNgt5`V%7{hqJ&V zvY3H^TL^?1FWs&C0~8GKba4!kxZK-k$=Be(!(3e898tFO|NlT1CYP9p$7X7-5%|l? zy}_t@@>6*MRn1eI<-{(os{7exw)XymbAQtE8UINrb(l2GNE0~Cb;wNQcdg8XSB#TB zoVfQKXtrvJYeY#(Vo9o1a#1RfVlXl=G}1LR&^0m%F*LF=HnB1>(Kax$GB9WpWz0p< zkei>9nN|tXV61CksB2&vVrXV%U}j|s)L;nIu$n=n8K^-SWJ6kJPHJ9aZmLxYkik%p in4YRvsc&c&8xLkyfSB1gk_v#z89ZJ6T-G@yGywn>1dvq# literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeSipiri.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeSipiri.png new file mode 100755 index 0000000000000000000000000000000000000000..6f4118e74bcbb4ced7fab5c190188c3d3ce53c23 GIT binary patch literal 595 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>d zVSIprj+W*`&a!wnl?D!H8^Z)2lXcU&IXKFU_g$FpKJ7_NIt(@6jogW`O zxjxs$PAAgI?9IbtJLYvox@rbFnk59ep4zx5*j6*zRz1O6Z~dHZOFhwthgUy7y*ob8 zF3R03Gt@1{!^ALw<>Qszm$%Kzj`p9@T)B5~|C_7ZUmjcc|Nnp0gUcTQoySxX;OkH}&M25un`X1sK_?hjC~&eO#)MB;L2-*cg61D@vO z!0U70-D}oUxcmNp*;5YH&ia%0J*^~z<^LTDDD`;I!u<4d(gMbe?vf>^?;YH`kLM7_ zNddh;cZUlXcf7oCvSit3*9QSQ;jevPev-X?_g{g}L&muUYAlDpERxaPdv6nmz;jmD z1NY?37_QmHzdyg-$zD!}&Heq>IeURFQ7v(eC`m~yNwrEYN(E93Mh1pPx`qb2MkXPK zMpniqRwgFe21Zr}25q8@xhNWP^HVa@DnS~Ibqx%44NOA}&8!T}tW1F#41pR}Gl(<; zH7J8@NXyJg%}dNpwJHHJ7zz^8Q}rtK4b5WX!ORK}Gy6tT0Z=)Er>mdKI;Vst03AQl A`Tzg` literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeTeak.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeTeak.png new file mode 100755 index 0000000000000000000000000000000000000000..100095ac035fa53364a9078e01d03506b8317f57 GIT binary patch literal 632 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>32_C|vp3{*Ee#E= zHO%XG)=-t#P?JmRv^CIC(NtAXSC-S(R5CTuGtyHv)KfFk)3h+s*3?u|R+g2MmvFQ< zH_+8EHPld7lT%cbl93j(vNX1}(D!sUcX2eavM{hR)igI&ceK{Ew>H+%P|{XcbhX!V zv^93L)^@hjbFekAvCuLxP>qlBv^LkYFj4n*F|sk&u(LF;3=* zdpunnLnJPT_FWe{WWeJrx>~?2^?m5KdmsMSyE&cE{5Vx_rkofqy+c$0lp0pR9Qp z7g&|K;p(jgBHt(M-F5TU!d4%ljki~G{4cebCn53twCRh&-S$q8e^yz4WSr#3*7jm^ z+e@IkR7+eVN>UO_QmvAUQh^kMk%6I+uAzahkx7W5k(IHDm5GVAfsvJgL7OOJE{cZS z{FKbJN{|L)T?0d11Je*gGb;l#D^s8bL!gG$3?j`y4ay)J(lT>W^AdAYtxA9lhJwWO gRJ}@lL$la;FtY;0%)XIS094N4>FVdQ&MBb@02cPZB>(^b literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeWalnut.png b/forestry_resources/assets/forestry/textures/blocks/germlings/sapling.treeWalnut.png new file mode 100755 index 0000000000000000000000000000000000000000..50e60305e9f6acedc6c2f05b1a365d9d404b2bd8 GIT binary patch literal 623 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>A%4O3wBvD2vI=_Df9kj!*UT46){ZnRkPo2@YW!I99p7PG#lDUh! z|NsA=mv3(mbSPsEak7ak;kNUC7Ch$65BJ^NYRP{on7s^FPa?g=aEvTxN>>O|hTB&z9R=YB=bzK#pam z!Gx_M2GjLx+yhivmliFJ;`Z5lF=wlFZ0|>orPs?3DvB9N^d(qM+rT!t#OiU)#+aYM zJ+a!`Zfbe`Xufmp?mbi4C7x3bUsSm$zx;FS#KOIIAN$LnpDvznFU%(9{-Hz{=qS|^ z*NBpo#FA9214Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>m5kt>>;cRV?8XK6G5f>SVT$YxR;NRa?S(~3xm77{ykXfFYSezPMni}orZEdEn66)(58R!<~>k<{<9TDJ} z6d9JE9{vCSe~W*m>OkumOM?7@862M7NCR<_yxm;3=*Ydu{YLnJQe_J<1{a^P{!ZJpF1rLe^$>cKzrBfF)`IGXprG2fKZ{YUrjOh$i` zPb^HcKQK!4svERr`d{jqV`< zRdP`(kYX@0Ff`ING|)9N2{AOXGB&X?G0`?KvNAAe6J^Xr(U6;;l9^Ts(qOD>V5nWngAy3e;c-)UcXCq#39|8Dv9RW=?8eVs5Hc36Q~1keHsTSE+Ak78?&{R)Cn< TH14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>331J~ufJCRziZo) z%Js8?mP|=oF;zlR=H2rLu`8#fCL{?9OL)7x{rvjz!qLOECB;U1n%=G+6FSx*+&&!0QBr|-y~t*J3l zYnLxMynSO@eB6}I&j0`a*Sz^R4d`s9k{~~z*UKiKwE*%Mlf2zsEEcdYy$0lP7I;J! zGca%qfiUBxyLEqnf|EU6977~7r}jPPJ7mDami=3M%3j4Yo4(I`|3A&bb7jaw`H7{M zVr5wBonLOKl}XsX=>fY_pqk1~mI6B_POhUuHWQ2-R)l1Kbz2m$`RcopYB%FJ#;@#V zIh*|!KFrV&J~G9`W7+1POsB6_9ggeVw(9M-RZb!sBo^oenLjWQ~+D)xB!(rWr^ zUde)b8%^f8_xY+l literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/conifers.changed.png b/forestry_resources/assets/forestry/textures/blocks/leaves/conifers.changed.png new file mode 100755 index 0000000000000000000000000000000000000000..d316478e43d8a3f804f12a167e3ef2a665de9b2b GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>DH8Ke?G_o=_u`)5yHZZa>FlZBH%tg_Vo1c=IRteHztZQJTYh)T?1k_+| zWn!vrU;OkH}&M z25un`X1sK_?hjC~*we)^gyTBznT@=M6+~DrG&4W@A>>v6t0+eK1A~T6!bwSm-{A{u zk2-f8e4^5~&&XORLS^on2|u#+#dS`yR~+7TbbEfK-sNOlh3vpArq?ChQ!T73Ps^iwG1&QgYdX@TyX0h>LW(A0ueIuy= PsGPym)z4*}Q$iB}&5x7# literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/conifers.plain.png b/forestry_resources/assets/forestry/textures/blocks/leaves/conifers.plain.png new file mode 100755 index 0000000000000000000000000000000000000000..7c692d6a9126a0fbd6523200602873cb6bd349d2 GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF8W~^`i5q)@nB{Jh?#vOsQ{>)!PC{xWt~$(69CM$g;)Rp literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/deciduous.changed.png b/forestry_resources/assets/forestry/textures/blocks/leaves/deciduous.changed.png new file mode 100755 index 0000000000000000000000000000000000000000..6a9a05c90ae7a9df2a707d9b64bfb16d2ff98a24 GIT binary patch literal 750 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>1_xA?|2CiSf ze$k>u^XAQ4wQ5y-eEi0Z8>dW}vSGu9uCA_Gvu64G`*(MDuk2P@xNzZu1q+rgT^bY= z)Z5z&v}^L@$!%?Iv9Yl&EiJ*p!4VM=%a<=tO-+rAjEsqi*|u%lvSrH-%u}B@apH;< zE0U6ucI?=(cedJ_J4+v)D405R>Y6ocCQX{OZBgXPl`A)G+SJ+EIbp(tB}UogXNErsPEPctTYySsRNV7l@O$l)yTh%9Dc z;1&X5#!GkW{s09pdb&7;^8+eOKh$*o$A^ba%tc1|NmDU zE>BA@D@!Y%H(l@CL~fbrhl(#Adi$;6f5Cs~nxRUN;o{35XQnAx%$clk$;Y=?z4bHq z49OHnyZQP;GjvXNdHdXAiwVp+)b&Fu@4%gP9q)IXmk&9+I6kT3QRRu#uXjZ+&i>#o z=jyQU-I8gU&D(Pmcq*T-O-kp~x~cSlhfhQ3qVlbY8>Z*{{?PYN;YUj2ZG+iPE$8;- zyqCUn^-@{gA>QB19&MNP&}=pOcHaIg{~kA?vwt%7T?2YfwZt`|BqgyV)hf9t6-Y4{ z85kPr8XD*tnS>Y`Ss9yHnV4uB7+Dz@w23n2qG-s?PsvQH1ZgnVH89dOG7T{TYB0Al zG1WFO1Zt@9_udNBpbWAhEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1K;;ac Lu6{1-oD!M14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>8yg!Q9v&SX-O|z$92^`G5wU#v^3>GS$jHc;n3!$bwk=z>Z0pvo6DLkwv0_D1 zQqqncJ7&+GJ$35THEY&Pnl#DV+k558m76wg>g?>CFk!-yB}>+=TbGuWmXeaPc=6)@ z|No!=GH)BuON=E!e!&b5&u*lFI7!~_E-pW}%s2?-a29w(7Bet#3xP1>rMq>1fP!Z{ zT^vIsF3a}6E^0CmX|bOu)TzOA&8_L`gQco#w=ET4dh7S^{lU%YY3bk2zxz3jFYY?K z-W(2rFC411&z0E@?8ezv;$Gx8=`e#`zmdKI;Vst0PCzLM*si- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/deciduous.plain.png b/forestry_resources/assets/forestry/textures/blocks/leaves/deciduous.plain.png new file mode 100755 index 0000000000000000000000000000000000000000..966407f9de298c35e32de11876a33961bfae082c GIT binary patch literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>g%a^C7rbb3a#>B*I+qP}lvSnMhZk;%B;))e3 zl9G~k?AS4T_Ux%sr>OK$1*j+nwC8lqF2xNXsjbsD_c>vm3z5;jlSUcmk| zP5Y)Tf4}doPfxB-u{nKuM!2k3cizGI6+x~!T0M8S9KKzCV$1s4YzvJHCIR;JFZQYq zydHd$ig|AEKa~CJ_(jwEPTx@(p^}eFC*&7w*M9x8vs`AkTitI4=e3tE{fk*%|3^?T zD09^v7NE~mOI#yLQW8s2t&)pUffR$0fuWJEp@FWENr<75m9dGHiHWv>k(Gf#ngTe~DWM4fxI7=N literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.berries.png b/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.berries.png new file mode 100755 index 0000000000000000000000000000000000000000..7c01fce91cb481ee29c36a22382c7eb39bfedaf5 GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF}GwI#~aySb-B8wRqxP?HN@zUM8 zKR`iuPZ!4!j_b(@4y;`cXH+ya4x})pXjpS`8CWq$D)lrmC1ft>QJSKd!gN*X1;bKB zuZCL-c@~s$IJY=XXynv7v4AI(Pvj^QgNF(8?*q!Anm{8}OI#yLQW8s2t&)pUffR$0 zfuWJEp@FWENr<75m9dGHiHWv>k(Gf#ngTe~DWM4fZHRS1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.citrus.png b/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.citrus.png new file mode 100755 index 0000000000000000000000000000000000000000..757a75cfa0cde75100c034e96a4ba96d065ce559 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggq7G6$SW*)7(sX(D+o-U3d7N^%vcI0a|;9)s_?EUHF zzg81E?|QFX5Tv-}ZZO}+W7fA0^iO*G;N8@jE40>{?tJ>_-Pd&&BUw-QFjT!i^ZCrK zbvu4f=ww`>#USVyI&tP6{X)r&tF)A|BB#CDd%doCbH}$uno8%pJ5D^DT6?79z?p*Y zS!+ArZvWx(UuRKY!>yjPJ(;r%j9s4GXcml^uk`OqyK_tauLX-YwDFuvh^<=|z2V@j^cufER literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.nuts.png b/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.nuts.png new file mode 100755 index 0000000000000000000000000000000000000000..62026ca99cb329264a7bd4ac8d8eecee235f3047 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF{vX42FWl^i;h{eM7U@crdd9#LT{tQ~*@Y;OXk;vd$@?2>|dcaC86w literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.plums.png b/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.plums.png new file mode 100755 index 0000000000000000000000000000000000000000..dbc78e42de60a8849f9bd7594a5df72995fc04e9 GIT binary patch literal 424 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF ztE++J|Ns9#efk7sKYR8}K=6JyP#H@}kY6y6X4pJAZ5EJXO!9VjVf~T+@;H#gS>O>_ z%)r1c1j3A$?$-SQ3VM3FIEHXsPfloHbaUijFq*P}M^RkES>=qtDGzNCkwTW0g5n}2 zX9Zeb6umBJF;Ge1aTK4BvNATYGBMFMFtRc*XcJ}3MbVI(pOTqY3DRJ! zYha{nWEx@w)L?F9VybOm2-HyH@4XeMK^bI2T4qjaUSe*lRSA&6P>`6Os#mFRXcij} YW>$ch**B63fXW#>UHx3vIVCg!0F1zV?f?J) literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.pomes.png b/forestry_resources/assets/forestry/textures/blocks/leaves/fruits.pomes.png new file mode 100755 index 0000000000000000000000000000000000000000..6e0e0419594958aac65ca915786ad59669bd8b81 GIT binary patch literal 454 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFg6g4@(TviP*A); zA_K@|O!9Vj;c46)m<;4_7I;J!Gca%qfiUBxyLEqnfjKZ8H zgVGoByxh&t+REb?RMgZICC#eXbv>rh=-WSLBNySuHSG>=M_pE|ThSYEY*u%`v3u19 z+H!{^npW^IOxi8d;wtUl3^Z4@#5JNMC9x#cD!C{XNHG{07#iss8t59CgcurG8Jk#{ zm}naqSs56#i8AJ*Xvob^$xN#RX)x9`Fw!+L4KV_0Ft;)>)iy8$YN+w|-U`&946-3D uGbc4KF*nt!1jt}0NK8-FtJF6%i;V{}D?rTb8%YH~14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>QD$c5%9Sfmo;;bBme$qP)!N!RW5$ezhK8o5rs>nC zx3{-fS6Bc4|G)98&wijm>?J{dAV+~fXv(VyAjO#E?d~F0b8&?vki%Kv5n0T@z%2yA zjF;}#{Q(M2_H=O!k+|&I&&_wpfXDgn$4=)oiJUwCS6R3+t$j5s{JpNDf#;)Xty5Pu zG;%8ZX*?ax7|E9N;BQ=i9e?^?i7Vf}ICjsOmvFa9;jQ;OEE5lG+mH1CwrR&nFUg?pB{&n8c zXd4(=85p#QGUlRa$jwj5OsfQGFxE9N(ls&-F#>8Zw=yx+HZTNgsPXsS3e=zsvLP)q tCp9lIH`S^H$Y3Z)Oi$IT)HgJXjR!L;K+NnLNd-XV44$rjF6*2UngF+pzf1rC literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/jungle.fancy.png b/forestry_resources/assets/forestry/textures/blocks/leaves/jungle.fancy.png new file mode 100755 index 0000000000000000000000000000000000000000..0b76034250f631bfa876da1f9cf7915267fbef39 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>QD$c5%9Sfmo;;bBme$qP)!N!RW5$ezhK8o5rs>nC zx3{-fS6Bc4|G)98&wijm>?J{dAV+~fXv(VyAjO#E?d~F0b8&?vki%Kv5n0T@z%2yA zjF;}#{Q(M2@pN$vk+|&I-^h1JfybqPP#f4jzt7|X!Iyj5v z!orWW`=(5bzqXh?j#aJ38R$OM64!{5l*E!$tK_0oAjM#0U}&UkXrOCk5@Kj%Wo%+) zVxnzeWMyE`Cd!zLq9HdwB{QuOq`_F%z)07~G{gv~!Q9HkRNKH1sG-K+dn-_bGRTIs v%$(G`#N1S?5+H-2ATd2vuTtO8EH)m@tN<~yZzL4}l{0v{`njxgN@xNAN>0Ah literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/jungle.plain.png b/forestry_resources/assets/forestry/textures/blocks/leaves/jungle.plain.png new file mode 100755 index 0000000000000000000000000000000000000000..5279c53725cca2eb7bef9e8c64d0943e9c5cbb19 GIT binary patch literal 499 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>gsB3ZJjY=MngkGQ&ZFQ>C@ZW+pDXq|NsBrcuOS)sGTv% z+ucQA>Ly+tAcwQSBeIx*fm;ZK886+f`vVm0@pN$vk+|&IAIR72z`fD0N{~`2Nrq5t{}(JFP=qQ3>`x6muMS z{>+=Aw9bKZXGt8#GNqSURr=zWn|vCRzZtw>w3t(QUW$Lh-0Jjp)BSRmrxiczxb42y zc%2OC7#SEE=^7g7 z8kvL`8d({eSeck;8yHy`7_^Bp=AvlG%}>cps|0B<)-^EFH8Kq`0%|a~GBMRQFa&C- z@%P>e)SwKqAuTf}H7_wY)v5%@U?@mTPt~i`H#Ccl2Qw=`%zopr E0CQBMlK=n! literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/maple.changed.png b/forestry_resources/assets/forestry/textures/blocks/leaves/maple.changed.png new file mode 100755 index 0000000000000000000000000000000000000000..e7a04055ce3e5eb117ee695701ca0a6313df4cfb GIT binary patch literal 931 zcmV;U16=%xP){U+010qNS#tmY3hMv>3hM!aiw#-;000McNliru-2)L088(wu{_p?*03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00Rd}L_t(I%RQ0JPV#CP z0Ou*C7SNCSOB4w~S@@HfXp9>-UVu9<(0ehuap49Uv&_`Z+t`*@y*WmykHR)u`CPMbrBKP*4Ah?oBaO% z^78V6{qyr9B7&+C$FcPLeV(44)c1XiF%rkIhGEG1`Z~Q{kLTxSq9~H<>uVJetZKEY znM_6jj4_CaHX03#F=APk`o1r{UJuK%2*Z$%j}LJiM_tz?o6TY$92@}9Y&O-lZ9LB- zj$=xtk~W)7rqii*yIsjlCZb8 zhpO`O^1^U9)ZgDL1==}UV z-{0SIeSM9bpP#F$N;;j^D2hZ?DVNI{1c9VdDNT|@0JUwKi;D}!<1w91hx_|`QB~|h zp@1<)7Z(?KeSOuhuP=FfdqY)8l0+QG(e3SR_V@SyDo`jCsMTuB&CRKOa&m&>IRA&M z)oT3w{9ugHxw$!JvzbIuq(Km{y1Ggn$K2iB0pNKa{{U5($mZPS8a)62002ovPDHLk FV1matv<3hG literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/maple.fancy.png b/forestry_resources/assets/forestry/textures/blocks/leaves/maple.fancy.png new file mode 100755 index 0000000000000000000000000000000000000000..e7a04055ce3e5eb117ee695701ca0a6313df4cfb GIT binary patch literal 931 zcmV;U16=%xP){U+010qNS#tmY3hMv>3hM!aiw#-;000McNliru-2)L088(wu{_p?*03B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00Rd}L_t(I%RQ0JPV#CP z0Ou*C7SNCSOB4w~S@@HfXp9>-UVu9<(0ehuap49Uv&_`Z+t`*@y*WmykHR)u`CPMbrBKP*4Ah?oBaO% z^78V6{qyr9B7&+C$FcPLeV(44)c1XiF%rkIhGEG1`Z~Q{kLTxSq9~H<>uVJetZKEY znM_6jj4_CaHX03#F=APk`o1r{UJuK%2*Z$%j}LJiM_tz?o6TY$92@}9Y&O-lZ9LB- zj$=xtk~W)7rqii*yIsjlCZb8 zhpO`O^1^U9)ZgDL1==}UV z-{0SIeSM9bpP#F$N;;j^D2hZ?DVNI{1c9VdDNT|@0JUwKi;D}!<1w91hx_|`QB~|h zp@1<)7Z(?KeSOuhuP=FfdqY)8l0+QG(e3SR_V@SyDo`jCsMTuB&CRKOa&m&>IRA&M z)oT3w{9ugHxw$!JvzbIuq(Km{y1Ggn$K2iB0pNKa{{U5($mZPS8a)62002ovPDHLk FV1matv<3hG literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/maple.plain.png b/forestry_resources/assets/forestry/textures/blocks/leaves/maple.plain.png new file mode 100755 index 0000000000000000000000000000000000000000..0f429b4c5a4df58df7a354d0f680302d8f25eebe GIT binary patch literal 765 zcmV z000W>0fLJSS^xk52XskIMF-sj5e^y-ka`uZ0007Dg@7wr$fi9LIGm%fc8VgnZxs`1k+-Y&M%Xj(MJ^ zD2k@(KhUzQvMhbyr*vJXDC)1c-EJX-wrv+hA$wv7<#^?FrRjYcEOvLJ+x z;|PM_I1T_n)3m$0yP_yiS(g9){rmj<91e%3X^Nt_-EOO@a$Q%~b%fB-(UI@_qA133 z-0$~M5CpF4?shv#k~ogb^PFYb(P&hbrD>WNV@Z;NASjBWuIo6CJ7E~ERx6fevn+F6 zx323biYAi@&+}Q9@jM^LF@$h7o4vig^?E(3-|qte>blPJyevz@Ff7aRJa4^To2L2m z^RrkibX^AkL{XHcDK#FC+qR`?8e^QMX_}^s#e!wox~|{f--94{e0&@X24z{saU6yr z8V-kq5LuQz&r6ad3`2wv#+c{%)6>)Q^YgZC<2W9TM$_q36h(A3hM!aiw#-;000McNliru-2@903mMr8=&}F+0rE*i zK~y-)jg!A>DnS&+e{;OcA_F3tRnlxHK8f#;YCup3LDIQ`q_j$7mqtXe@(BWI(x(Yx zBR+zim_nA(o!i`5R_`tDfoW#W%y+&&qn@9i-OtYtm&=9aa;f-JFE1}H2m+eTCgpOO z^?Hr9mec7(mSrp!3pE@Lon%>th)^n(DAr^$QRQ+O0BbGN=~Ve%5dq+QJ|nlAzPjD6 z^Ot+Qo&wNX(`vQobUFY`r&FZ>`u)DER;xr&L>$L#HXDw|BXJy)B#8nTjYc`8D2n*_ z_+YVEC;_O|YJ_1(abyu;yWL`paR5OOAwW?Wv#sekYam27`f%tzOJ+g!;tNE zn*$sUhn)M{+nWN&;gcj$K@cD!xfWTLp|$4y{rxZQ#uzu7&6Ik5eRXjh^YHMXy4|kR zT2rZ15E0TeB~4R&QtS2lRT}T^?hrrjcszDm>l|q^nW$SgirgEG24NT?eq28uz<$36 z;Qs!eTQ@v+Z@b)Db2^=J?~^1^{=$4dS3cge*-Uxse_3mJe0)>@Pft&-XzOq|bUxlu z6uIN^h%v?$f356xyF9K%w9#nf{uOWUfPdgO%K98BFVgrN00000NkvXXu0mjfiJKSG literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/palm.fancy.png b/forestry_resources/assets/forestry/textures/blocks/leaves/palm.fancy.png new file mode 100755 index 0000000000000000000000000000000000000000..87f2d43a0d0fa7b8b1791f94a08eb2827666ead1 GIT binary patch literal 613 zcmV-r0-F7aP)3hM!aiw#-;000McNliru-2@903lA;cUE=@%0rE*i zK~y-)jg!A>DnS&+e{;OcA_F3tRnlxHK8f#;YCup3LDIQ`q_j$7mqtXe@(BWI(x(Yx zBR+zim_nA(o!i`5R_`tDfoW#W%y+&&qn@9i-OtYtm&=9aa;f-JFE1}H2m+eTCgpOO z^?Hr9mec7(mSrp!3pE@Lon%>th)^n(DAr^$QRQ+O0BbGN=~Ve%5dq+QJ|nlAzPjD6 z^Ot+Qo&wNX(`vQobUFY`r&FZ>`u)DER;xr&L>$L#HXDw|BXJy)B#8nTjYc`8D2n*_ z_+YVEC;_O|YJ_1(abyu;yWL`paR5OOAwW?Wv#sekYam27`f%tzOJ+g!;tNE zn*$sUhn)M{+nWN&;gcj$K@cD!xfWTLp|$4y{rxZQ#uzu7&6Ik5eRXjh^YHMXy4|kR zT2rZ15E0TeB~4R&QtS2lRT}T^?hrrjcszDm>l|q^nW$SgirgEG24NT?eq28uz<$36 z;Qs!eTQ@v+Z@b)Db2^=J?~^1^{=$4dS3cge*-Uxse_3mJe0)>@Pft&-XzOq|bUxlu z6uIN^h%v?$f356xyF9K%w9#nf{uOWUfPdgO%K98BFVgrN00000NkvXXu0mjf4fq$A literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/palm.plain.png b/forestry_resources/assets/forestry/textures/blocks/leaves/palm.plain.png new file mode 100755 index 0000000000000000000000000000000000000000..3362512e27577a3f8f383cceefc7c436c7a2ccbe GIT binary patch literal 557 zcmV+|0@D47P)3hM!aiw#-;000McNliru-2@903h!znG5kf$G0xKWGSMb#=1hEoQ+8D7B?QA3l1kpld zG`rQz8r@(dIexUp92ubF^=Qdse&LN&vOKT@B6r}TN+si z!FIbvDFuMzIQH3WHb^N^N+Fa|rQ+l9;Q4&=>CLAnrY0(t%6}PVptUXui1!AqHH*c9 zcDqd&hE%Iny4^0L(a83!R;#i=mSwiMTrNvqxUS1~yS4SpAU$zuWASB(a1n%j|g{k4GE*kJg&$bP7PL)hgv4MG>`H vt#sZ>snTC7cDtQD*LSrzj{kYy#!!PlT#EylFz;ka&l_8{*80}khl`7606@Op`z6uMhK^^(<*n0XFH8ZsgYJ;!3$t`|#- zu&p}Tv6JimzH@BsKfkZ2HrwSclTu$ESDVPG(RdP`(kYX@0 zFf`ING|)9N2{AOXGB&X?G0`?KvNAAe6J^Xr(U6;;l9^Ts(qOD>V5Dng8e#<0U~Xk% zs%>Bh)KKH^y%nfI8Dv9RW=?8eVs5Hc36Q~1keHsTSE+Ak78?&{R)Cn&Xcz2?+sV1-=bIJq2Bjj82-`1{VT(86>9gO;j=9ybV;T zTH+c}l9E`GYL#4+3Zxi}3=EBQ4GnaSOhOEetc*>pOiZ*5jI0a{+C&+1Q8eV{r(~v8 zf;1TG8W`ysnT8kvHJDqOm}(ms0yWh5dv675PzKqMmYI{9mzbMsRRUx%6eOmn>Q(9+ bn#IP0nH3;r_KlmdKI;Vst0K)QT7XSbN literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/leaves/tile]-98.png b/forestry_resources/assets/forestry/textures/blocks/leaves/tile]-98.png new file mode 100755 index 0000000000000000000000000000000000000000..dea306a170edd99bba322ef38888d45f3e9508dc GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFC$l;LA;VgMb?*&hXRIrBg8m3bM zc}<2>Hb`|$XJl~S$kE-+>jE-KwZt`|BqgyV)hf9t6-Y4{85kPr8XD*tnS>Y`Ss9yH znV4uB7+Dz@w23n2qG-s?PsvQH1ZgnVH89dOG7T{TYB0AlG1WFO1Zt@9_udNBpbWAh vEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1K;;acu6{1-oD!M0>!3RJ*Y666=m;PC858ibiv$6U@ zfNu8ZrjnsWl~+#}Z@sc@y1=Pxp&!B?|Gzo+tF~U)>EDYU zu@)aKcmBuxUyDyi@?%yk&^FZ)*NBpo#FA920>!3RJ*Y666=m;PC858ibiv$6U@ zfNu8ZrjnsWl~+#}Z@sc@y1=Pxp&!B?|Gzo+tF~U)>EDYU zu@)aKcmBuxUyDyi@?%yk&^FZ)*NBpo#FA9253fDQkr`R$08Gj>*xd;PSjQtrIPie=lq4+hQ1=Q$@> zW;yR_#4YF5Q{~!Xwr`!DFn|5o&3U;}Q*QETeKRVONLuI5TQOJv^@6pxSU%ogP*c2y z|N06}wn;$iR7+eVN>UO_QmvAUQh^kMk%6I+uAzahkx7W5k(IHDm5GVAfsvJgL7OOJ zE{cZS{FKbJN{|L)T>~RsBhwHgpayd*6H{#iL!gElfA6h84ay)J(lT>W^AdAYtxA9l khJwWORJ}@lL$la;FtY;0%)XIS094N4>FVdQ&MBb@0IUUwS^xk5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/lepichest.0.png b/forestry_resources/assets/forestry/textures/blocks/lepichest.0.png new file mode 100755 index 0000000000000000000000000000000000000000..26bd0f31eb07f17fd0d34e5939009d2dd3859b91 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GGLLkg|>2BR0pdfpR zr>`sfT~<+k1L3*f_s#(dJ@#~Q4AD40b&{i>vmuX5y3FMG(6ttfr}HKx9B$pA<(J8H(XkxR#|L9(!E1hjeof@tWe8*sCV_{ z$y`aH!f3Xx43{li|F7;?q;h;^ypX4zoLt#$UIs=UmI(rELeJj|EU0LaBpG3rePRt&^Z2=pfjs(4|F7 zpdFG*c8&iMzwgfB`kjr&#b>(ry}Rdq-sj#EXVWK5*ptFw5D1LXXoG_kAcW-0w;%L{ zsgC{LFohaAah#iHj?rwz1fBrESF%eS(jRyo`RBEtD1dgPnR@n~iJsq;_cmu48881c zespUL0HqK0G;90peO~6x%sT)k*9+`z&T6KV-A+@KIc;1T=DG?#>9>PXc@;iDHdZo~?dx z?FJ7X-*F@f>X&Z2_0uWentHEAJJKjmB8}GgN|Ju{!u3v(juyJ16&sA!NFilM3jmW7 zg^oD05dTFGc!JnqJ@A!eb?hs1d0ToeUvz7L`a=)EwV2EXfKr}Su(GkrT)xQSe1-d; z$_(!uK4Esql7!RF+|1iF?P$2DjbedN@rzoCaWcXO>2;jDPijR&4AX z{OLg=b7^q9t9gmCz!L~5QN|e8PjS1KDkWAnmZ=VusA5(1pFT&kw(m$9->nD6M2O25 zFPQ76JpKnSKgNjB^J&u;rmP`AjQwdIhS+{^cflZtH5|?!+8BNT8|%;RjM51_00000 LNkvXXu0mjf2F4fL literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/lepichest.2.png b/forestry_resources/assets/forestry/textures/blocks/lepichest.2.png new file mode 100755 index 0000000000000000000000000000000000000000..3e27ce8e7511ae7a716b9280166f9121e232185e GIT binary patch literal 341 zcmV-b0jmCqP)weS0002=Nkl_bxOP zM@KkK?x^xLdmabTORD?W^WS-av-Z%qbT3-CD%s#~j)EKJnh&#TdTf`3Oq1yvm# zfeGr?<~|dPXztCPU;88=a@a~SPx^a|c?|HiZ}KLkyPX$vASa!}@%z%8<#4;)RkN0~ zE8bdENsc+*YZYB4Tg08S2e~&pt=3IS>uUux+}78s!f6>qG)Khx3_+-ftj{2b++1Ic n_kkmT5{^Jj-^@u0@ZGdOI0Uk_zG%<{00000NkvXXu0mjfJI;yY literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/lepichest.3.png b/forestry_resources/assets/forestry/textures/blocks/lepichest.3.png new file mode 100755 index 0000000000000000000000000000000000000000..2241f5ff542bac34d2c4f84a3ceb5c8247b354a3 GIT binary patch literal 445 zcmV;u0Yd(XP)Whev;S=~0BKQ(|_1sgzQW1qNp_u{1_A6H&%_-BC*aMvLoX$JLyq7C;8E5l_)Nzx*i1rf7R=BLmP(h>ZXi zC}8k81#r}Dc#6v1)>k0?)LuaeG*lanOV=G#pBS;a>WE7n#|w`qH3zczxhgc8*hUB_`szJ0$L7ig<00000NkvXXu0mjf9jwR1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/lepichest.4.png b/forestry_resources/assets/forestry/textures/blocks/lepichest.4.png new file mode 100755 index 0000000000000000000000000000000000000000..325874ce8bb29d24f68154b1177085e31f849abc GIT binary patch literal 341 zcmV-b0jmCqP)_bxOP zM@KkK?x^xLdmabTORD?W^WS-av-Z%qbT3-CD%s#~j)EKJnh&#TdTf`3Oq1yvm# zfeGr?<~|dPXztCPU;88=a@a~SPx^a|c?|HiZ}KLkyPX$vASa!}@%z%8<#4;)RkN0~ zE8bdENsc+*YZYB4Tg08S2e~&pt=3IS>uUux+}78s!f6>qG)Khx3_+-ftj{2b++1Ic n_kkmT5{^Jj-^@u0@ZGdOI0Uk_zG%<{00000NkvXXu0mjf8_|ll literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/lepichest.7.png b/forestry_resources/assets/forestry/textures/blocks/lepichest.7.png new file mode 100755 index 0000000000000000000000000000000000000000..bc9f9fddc315b431b1615e65be39ef3d1d8c89c2 GIT binary patch literal 608 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 K!%DRsUj7FuWhnXp literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/glass.png.mcmeta b/forestry_resources/assets/forestry/textures/blocks/liquid/glass.png.mcmeta new file mode 100755 index 000000000..0c36dcaa8 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/blocks/liquid/glass.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":32,"frametime":1,"frames":[{"index":0,"time":2},{"index":1,"time":2},{"index":2,"time":2},{"index":3,"time":2},{"index":4,"time":2},{"index":5,"time":2},{"index":6,"time":2},{"index":7,"time":2},{"index":8,"time":2},{"index":9,"time":2},{"index":10,"time":2},{"index":11,"time":2},{"index":12,"time":2},{"index":13,"time":2},{"index":14,"time":2},{"index":15,"time":2},{"index":16,"time":2},{"index":17,"time":2},{"index":18,"time":2},{"index":19,"time":2},{"index":20,"time":2},{"index":21,"time":2},{"index":22,"time":2},{"index":23,"time":2},{"index":24,"time":2},{"index":25,"time":2},{"index":26,"time":2},{"index":27,"time":2},{"index":28,"time":2},{"index":29,"time":2},{"index":30,"time":2},{"index":31,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/honey.png b/forestry_resources/assets/forestry/textures/blocks/liquid/honey.png new file mode 100755 index 0000000000000000000000000000000000000000..1930202f877ef060f57bfeeb73d8d840c60a6212 GIT binary patch literal 7230 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/ice.png.mcmeta b/forestry_resources/assets/forestry/textures/blocks/liquid/ice.png.mcmeta new file mode 100755 index 000000000..0c36dcaa8 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/blocks/liquid/ice.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":32,"frametime":1,"frames":[{"index":0,"time":2},{"index":1,"time":2},{"index":2,"time":2},{"index":3,"time":2},{"index":4,"time":2},{"index":5,"time":2},{"index":6,"time":2},{"index":7,"time":2},{"index":8,"time":2},{"index":9,"time":2},{"index":10,"time":2},{"index":11,"time":2},{"index":12,"time":2},{"index":13,"time":2},{"index":14,"time":2},{"index":15,"time":2},{"index":16,"time":2},{"index":17,"time":2},{"index":18,"time":2},{"index":19,"time":2},{"index":20,"time":2},{"index":21,"time":2},{"index":22,"time":2},{"index":23,"time":2},{"index":24,"time":2},{"index":25,"time":2},{"index":26,"time":2},{"index":27,"time":2},{"index":28,"time":2},{"index":29,"time":2},{"index":30,"time":2},{"index":31,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/juice.png b/forestry_resources/assets/forestry/textures/blocks/liquid/juice.png new file mode 100755 index 0000000000000000000000000000000000000000..680abbd0547cd708aca41ed3b7316b2af44c504f GIT binary patch literal 11823 zcmV+~F3{15P)T!&2H&vZSQ^JIQ%evYrld2+2IHud#|;Z)RLOFCO{C# ztja9^$Tvp|`sesq-JQ+H`_7=Av zcr_D6#{sY@&z}nQsk;Qx>nF?q8e^fzCvKZ3AUL*h;5|_XI%P%!*$2nXR2XH@EYwey z@9Fyb{n-z^1Nk=aQ*b!I?jk?@%Co)i`0_OH{WP+Vg$S_j*p$pk-w^6-ye1xdiwlk` z>#%;~xH=WyO9mi(U31r4HphYeTYX`YvFQP89ie1SDRT;jt^fU<|5w)mz~g&e7lZt; zlj)qtDsz}jo$>@nFQbf^<}qe6*sjikmH$Sb!0T5GuC7oo)0Nv#(J2Im0q7=3Syp6S zD>h}07_6>Br=Pa?Ia&M;@jOP z<4`6ek8B`7*LPgq2ELR+`5O3_-xL2l4xA>#;De(Nj*aZJ5*(Y`z^76uPmu>8rOfH! z$RDwAlyza{2|FJgTUqBN7IG{+za<`9JeW$Ivfko=bug^&SA1C;R{kyVsPk$dPlhfy z)`|lwP$;r=6%!2JRIEHI9_aj+SQvpmI99-^`F}wk zy(m5!zz4^*4p@T+gZxZ);f#Y@$LCcb0NpO~?1N$Z%Z4vcC%&hNgN(Y}cH9X5=|U?& z*=L^P5!-ict;70l;ObD=%MM%J^nBS^HiyDaHqay)lrJfN8k-L6i7$xJZ7KplA} zo9&3f+UA9>#et80CTEB4+H59@pA3DorJZ7eY@#7CFR&R8nlZY>19?{mbw5lM54`Kx z+<86$?mqChKNG(mhq^9&aP+`R;X4@C+rTZ5pCV5{Dw**q^E?$&f+5tiaUBau@!%-S zc!+R#d*@G}Q#_C(FNb@54N%@z3dAQj6Og&EbySWtbrnjuKpRV!Y#g4Jovid?ltk0GKW|g0=T}L;eM1ez6jCy5eK@yV*^;f3iQW;R|*8j`o8CvU|H=4 zo@E)2@+4lKxJ#Ks%EVw;`^R_wKGc2h2FNdohxT;sgn*feVKTUs>r9!6QSrca)BMZx zDQqS=Y^Qm8dzqo3;Ro64)@(o3Ofyf&&GsFHnIZgOocV$5^U|`E<{OkHHYh1Elk7$z z*)))5gTP@Dez5J>0wxaZQiGXZ4~X_t%tRR=Hr!~n@~j09e)===x*#{Ato4*lS&8fkco%P+ncNx#RL2QhX*dODw*-x5%vT7N#ljy(h2jp2y+0d zBs@XxD{o#2KhQ(SdVR4zi9Y^3*Jolmf{cS>Z5>y~;fx1aDP9vVY=9(SimB@*f}Bd3 zw7A*aK;5m)>zQS4QEA0ssT$*M)*!ahH{?Kt4fS1Idi{0d8oxH~)RKUKtb4JgM-ZRjmsaI9_v zKW`0J7kHp>El2oK#wJ3=3c-WpA@lZYJ&HfNS}|R5+=Y z(wSLTDJio{xsngx)wQiyU}EiNX&Q4>nJc@4oN2x%F({Ms}sHGJ1<^@F2co6ObzibT~|2Fcc#!Zu%&qNywhm<+!JQ(3m!VlhG63>bUT>zKNe7GLl zk#F$eR`8%tnZr~d2_AH!(6uvRJ2Q)wRv_&J5Qp=N6_umRc_;Ly2g*?2a8#g?kbjpT z8jIg{+yG9A<{YiciQ`v+FZqly>8{9NjMRBV~@kvG)73;DW>pzqj96@qj{%sV+7ZtEa-~+xhOM%TsuP2Q)fT3=374 zak}LAAK*c572tt09&}XEu{4p2{_XY9`GAPH$zT-^j>|xzfiQxj3y#eQxnxp93#($? z@Pk>rMt5UMZdV`=fA>&`OZyxRm1 zG!vv^^--g{77yll;Uhed4L1Mxtm;l?jy#I&FkKU)^5g{`T*w479>}>cXE>&_CSU~* zt|a&zmw51_mBwYk%z>yV`d+qm|I3>HS=Ppk2fe*){FqMmVQKS0X03{guG*$g%rn<7F2P2C}BDI<3sW=y) z+d~SCy5kj0G~d`Bq)Wj%8Cfe854I_D@S22B7?%a&ufsXNxR3^Dv9iSj+D)SQML7dL z!h^~Wj3ulcSEVx0fr^v8;K8BEYGA5<@E8Yr!Gp>VN?oFU+p*qyZU*2q@xuH>50kEGqBG?jiK~ZGM1oOo-BCKwJ%mZQSo4ah?()g z#ZqTMCcXaEUGD!@q-(XsEK!^DouQxV{~Q53H4&Vq(A)IEU-*Hs1kNYZ&_2GL2`)G~ zCEZQ_t!TWUc#s#GqT+!CY^iv#{$`3fFTWr8cUddzSU4&k z90U)JvQ!c3e+!t?$WcO_LGZx-9Qc?(d;_E?$~&+`+@yi;-#fMf(MZdGd~E9 zwdM+9As&aiZCf>0QiyjUQ*L@TyU2?Uw%3G1iwC-3NtMog_o6RINW%eoa18U&e#Zvi!;z5F#hWg1m=Sh+k z5*{cXJb0N?+p3wpWfKf*#e+6ovLA?XpkD_@>zIQo1P{8EX9EnoI3us^4AymQu01y$ zxTna|Y2;`f-m7jZ9AOYW(JuHw&%nOq`ZZj~O5724*48EPa!uZ`YxqHIG$t6xnjQA4 zWJ)5Ubevhbxg;Dd9-z4f9~@VqvCK?Oco(P&PZJWg0ZE<=od;I!Nb4s}2A3+RSW}n# zEXYU*I4B-GFZh9LREpLeQG_4-tFf$9hxg5qR>WiDh2m?RfK093MV@~@^3PBc`RiDS z{xk4|s17+r_ow``@;Q2xt0sf*V2FFIyfMYBi z_XDrGU0V;rw&N~k#xFgec5zN_dkG-HDv_xquS!VkwemIlZz9$4jtALWy# zv&vm0@7kwanW_ewx=x%pL#{MlP!VE2FGN3}f#;~&c`QWvCw~wxe252{Ce5;(yWX-= zGNr<#N~D4ZejWH6T;&IvYxUOQuPTrvQEH;5%uMwrTzAmDjJ%viVh}(n^2wvgu&0_> zTK~ahxT0{_#fkyJu}W3(?p4*zji%T&NNm-#p<8$|*r`yA#qS4x_<;){Zs~ZKcV?S= z93akF-;Lu&$mUV-py+`kEaZY84CjEP@&mw6g|s+C#>rq~srqSSs~bbbgF!RmHf4Sc zQ;iW9X;TFc9Z=;5|IO61qL_)e!~-wKcPN<>9G-&P25tbJA`gNG9_V7hDjukzty=5q zzjwi~#!~hpyOfDS?L5HOHUAbGJUAaN0wQT*uZhbG^e(;tuZ?ySF$*uRAoRJOYMB!W~I8Ft&j!&z=y0?U<#ABOl zQwCb`z~NG^L0A(n_doq&MD zeO>c!9^3^U1n}Fymy{`K;;_#=n(L2pu@namPl@lUu?tVKlc_m( zAa6Z)FC$MSlR}kCKwdPjca7p(+OJN^mVh8&a^X#uL3ND`bfIKOyns+4+vXQ$i)nDI z#W{LVBY4YNQzq)v`&nqO`oUVGx7PI`cu@6&iU)lM{maPH1*MVW%}PqtCm~)kpo0M? z{=}|#+ zF6opRu0302X*7eLyM=P6_M!peRPcfa{weW?Z*;_u_`!UP>uwz<2El{s4qWhqGMx|E zb+c_*rcKnZ=x2@TtRv}+w0NLnHFR~iD$rOfr18BmFSOx~KB|XmE&XZ3zv+MfkMKYN z#I8Koz2ypUuZcfj6W@g&e251{@gP8FJ$I*(_Y)i&&uRz`bKmnX)?!;cu)U?f>A6dp zavC|jCjM9?Z-;@IA3Sv6{B_{-%CkNtVwyNS9A{F|Dtg`4vBkn|;Py4~B5HW=0UnP0 zDKE&2I6+n3_%;#+51yN{jN+ACH2yT2Bfkv;XYqEbTFM$2{gT>g-cc2tR2{01p=w2n|F;!V$HmVnwLy}KOPb~n0M z(CM%b$BGBa4~8b-Sf&AH;c}eFV@;=7n7l_R}4#%}}n4@Z92BhR-XuO#vjJQ%GbTzhVM%gRG| zO8owscoO|!oJytlpBw+dkib%EV$K)3w~^fm4w5b%CG4{|J^uw@_9HcT@Fiv9X(aA5 z&t{yzidru#msCCRI`C!d*$kCPzRLGQmM&`MSO>n8iSagY_j=-0GF`o=z*FRpdDs2b z!_EMC5T!%$K-g{Z`>Ns;BTPiF!7XZ5ToV>q)mGIRH&@M==`vmrJm|z$($YTE80mY< zMz*YP@L*W*gUvF(0JvRb=chB3EejB_O$-qm{XqSR+u(5CSk`@&1lwb5PLFFHi*YsV zr{J*UAO;WLP<2-nokl?6z5EZT(eqcW+MaY5&P8rR^k?)EJb9%Vd z6I+U>5I;`5FXM&J!Br{z1AZ`9kLa5;^-Z&$nBs6wi*l~%Yi*__7IKr^?&eIF1duI_ zY4Jc4mP-Hq)^qn1d7u)|*ybD6{W%*rCDgm?E&Vn0zn%DFKk_8;LN^sU^&<^1C#n$L z(5*b{w~?0y{3XabA9V>>K7L!AzZ=`R8 zAI#iANamcp@+mVKi>ELQHC`Coc%k73%B9yLq3v(_8ZTVnK|==00Jd8wIk7Nm{%wf| zb4FvCplCMQ(8LR8{XqD^du2Maey|Zs&3o&9=$Zg!QVArMi)!0*1Sdh4NW^v-fT{;W zo%4NTk)YW`>upyDTXx~iF7l|_ORFam99OYi;=z5-Cu><n2br4Ln5=t_J^$`5)y+7$AU`o_PoQdM^QjMY*+MXR=KWioV{Z_LUM zrXpLoIh}zZ`Nq8MxUr_n#%bc{MR;!G1zpN+D!32u;76-5_`YL5rFbxoRMa^V~&IH^1&mdoTlO(7US2$0l@J;?E=bqn)C zQn!m@pAML~LKWhD<3HF?@K|EXjNVwRfCpL}J2TXpgN)*gP&}xG)Ke`_@?tZescf6| zTzoyNhF2k=XFL$8TYZY75uK#tvJgO4=^9A8$S#YJ0&0dk1&_G4RjRI7c#F)ekBjkZQ5d zC>{jcTkK8G&3@#^%Cq{Gc{`2l#oUm9U@WwFum=3sH9wuknnx2UVB8O9PLwi-hDSQZ zgWFgbPb0fsg_2mv~BDYE6muA-b;8^)!*kUUl$S3-_MD_A%Y=c_< zrsoEjY??TT)f6*T6N^-o46_sJT=zGp(RYy_r;($NrB2^RctEp#J8^=jOrn%X@qmxI zF6i`X+|Y0d+sWSdoBH^xSU8A?D}ry>cu>`es_@TmmLOBhQ|6WTmUz`-31cfBY_RO7LWcqKF&@l_ z*U9hP^xT#VK25~nxY~=ELpqLJbSr9l24$(zA9s-#>sWayfcuCaWZANr+Ak$Hc%Zu@ zws^otx?*=eB8K*N6*K&m;Yz=^#tQ+u-mzT;)~As-*(d9%%$3P=`m8q6sF**ypoZFQ zVb~wfUUfCHEEC$k_2Yij&Y|H43VB{Rq^`u7%899^Ad;7{g!_7^PJ##j5PmS9TE0zE z%NXd3{e921t^iJ%{Z#1h zYQe1XgXA^H5PRuJZJ^<`G>cNbnVQIbOEveZ8iE!+9UAe8DE6YpLNl*I!GnI~*_KT4 zlI~gW2X-2vH|Jz-5;SVy=z($?tBc%gL5Jb55Ts33m?}0*W;Xehwog|65W8e|c8yJcbUblS94~T`_yK~ZN#)H6pDNOg4&ka8q)FtQD8Q&(bbw%Fy ze0@FfV-?u^QTV1AzD5%8K4tb|7rITEaoe#@nISm3ZqS-1Urf| zdJyiY=AP@XYyPKLW;}QkJQ)0a;Fp)7%AE~A(D-r2gI^E)`?_OuqG}9)q0sw(yzzf5 zT0H%yc#sE9#m)vFE~-q$o7y$yS#iM+4nQ9A`P7=4&V6my2^ufjD5E~TW!|R(cO6%n z@l!m|Ojc}5RCTV~UU?EPR9PU`5A<5-px&F-eylIj<4luUy`9V3FYw?;(@2Iz#ei~z zED`IFkXB#+86I?(IzsNIIz!qbP)r zUK1&wXKMB*O4+G43Q;_mwdUa1Gg4LKR1Mbu6_7kX;Q;YlNI%{Y6YUxtnac}Mv?NPVWA%!ML&qGo7%Vi0h?Y( zrLmUvKo&g6+m6o^EVjPc5)Y!hnGcmrMn!EE>?FTX$W>eR5(ggJPfr?rn6vO8L59ku zR&tNE9I538&2B78#=>lF3`KStjqCCbp8x*y~l zXloth0|tLV)y{C-tpj)4j;)GRqV%eJN;`CPe%abcKWT`>*L3#oOD?XDrT)7vGTRit zT>qusTWWlJTN!%O3npI#98)d)j6wVdO}*p#>st7MWA{+=cdl-X`)RaZue=4otH ztNWh2*Au%{!2kWoK1~ebj#7`iy~Kk|>Z`^~aM*bcaQOfL4X{Z>K~!%?eidinxw5Rm zgOqE%v(_&Rf=UO#?az&;TySiDS@W-l!tvg6_f&W})vAio-}n5yA9>OpH`l>8^B)Vx zZwLO}R6N)#?F)|1|NhQ@pG%gT9(o=ujRa<@fA5rPThtVQec|AnR&Vp)i?)!82T?}h zU6!%a&VBwPeh?h1lqtc`VK4C@m|C`$CXT*wz8xEW&`+gSTc@T^jA70<7VVqi<&#cL z=arJqO(HHj88&CgjAmX%W?^V89{i=6K$EuW2GhXwJd)7|31Bwwr({or=Rr`N=D%C+%aEF4+#0|CwUd%FSNhmrX9R%`oI z)zRct(`=)tRjOOyfx74kj*YbcL7ii%aY_1%8kRF_^_3QwgVcJ5lVc}O zYJ(&A$9MiQ&+B>nj?~7@H2jHFgN=SFjK*U3L&bxS_<>I2tafW>uDM}jZ2@Dw%3S(g z^-Y8~PFmmbR`tZJ{Zvb)yp8O=wmB7kaL}x0Vs=BlEb!oYKg@dKj7XzaN;EM;1LagEI7pjnv(So%MdgtH*gjyw92$CIb7B=KC+gS8!~^4L4|Qr(}eR3J|WrgTC3)Gvx=&jb-~=;@6Zp2qInJL2F=Zb4lBMVuz)? zz@z$=rM7PqOpO=zO^5T;qLdi_+KjNy%B-nr|AWvpj~cY~r>sEVTl%kS{uT>qYq@zE zco1oH^fx_syIAc2O^2e{lVqkUK0O@y6|irPAM#bI1oHS^uYzdspl_rEPXGn9OjD& zDw*8JLT)S1)vvrC=DhQ)V5EkfXm%ql8q0J7KB_rk?0L@p5)ZnDsflMlYPUMgegtq{ zVa!~%K%BGt(*Gd0EzSmNOgT`4Z@4U&W>FB-8Xr|p%v0^FXXj+yqS2P^Et~tEyO)ud zk}EI#piSbrtZ3#&B7de#{QaF*<%-(DlyeV+lBjqvPNw34H*|^#O((ytxL*df(`jU9 zrt@7SG%&6;3;?T}o=+XP8_V@?iGMc5ly)+8H{J>dKHKZ-IP}5MpGNk_%=84mi@u@^RjIx*7C#jZ35uz`E_!n=Pbs1w{1OYt zjpgKj?O_lklh*i}!D7mOCxyYc)z!WtPg5_-hjw*SGh?zwr>=$EyOTxL6!m9}Mx7u()1x{$P1)6GrK=UwDk zbeMm2qVF!Oq=UNxL z@@zMb-oGVYni~(a$0FLrSFP8owG1*}hsuCcY=R zcF6Y7Yf}dqF^ZpqGctM zp&O>!C!uvi09kLrxUiaYX)mNPHkCFfqvAZv1YH|sNUV^T%7!d5?*;R^rZ3iPJr@%C zIu*uX=LUTj;h_)E4_vl8lN{vObm8%R$}1_e}S0`r56ixAYH3o?>P%Ph0tc$bhHzS^#ZW4y>d}^QfJDwbtcp&uvG& zpJ~Q}sSu4jS6Icu-sFZaLw=VzI=r)M`>D=715Fhu>j`bn`oVqA&oT4fJFevFsWBD? z{bc0_?LwKib1WPmkNjpVUTtP``?r+Y4;5htQEmFUnNX9M8qRf~si{mp`UVT;9Fvjl ztOWqNbep@< zKf!}GG*mpeaE&iY)!m|4dM<)!F8{C>mNGrQ^!mZR?vs5}zY?1U|3#;fbk+1f$W1xQT2AD#)ZT%2dV;rpBu!lU-m1E4k(l$Lrp5rS~(~N9~O@ zv<;Uubu>wqM+sOga`j+ybdB1CS=%19adN6f<%3lE)f-{jb__az+NB6;TN_h1(m|Ti z-B?pk@p@mIV|~-}lbAb`)+z`doFZp^MeyK9g9mtE+C`qN!}fK4?_utFVx>GW%M&Rc zjB`<#Ak2KR-Q)Xw^3-#ZIV}+79)`JzIg9Jo%0ddzX0`3jD7NjpKJSG^0RT-uoQwMR z1&=6`q4y0ZV0m}vw&Sz5x@vl-wFnh`XYfOQ(Rcf{Qlst8@W^r?16Ydn@j-A|q(ot~t zJ-u`=YGlu?WwAv;J0H%sg@sXBoQZ!1VAGlz+#nwHeeaKY?vaL$d z;KAI@dMdbNIaunk7Mcci{)0QM-4YLyVK7y}v`z2PZtkz#&VR~8#RE-DDp#DtqDeXx zhzq2(ns=DF(}0y1`$p|Af(PC<{9yBSUGHy{W2{iAZJ3mJ)mez5CqAlFhThkvcW@a? z_}X*d!Fr$ACtJPj;!*FLu3a^Xb*$zjjqb?D_ZlxWm4++?yP23P9@r1M6L#{CB2gz7 zg!XfjK6i-+OG$946=YF#M{_QOnDJoQgn4En3lchqhb1z8Ujg3ood((5X@?8D2neSsM^9|E_7Had9mFGq(MRvM$Pb2Rl6a3EE z9X0rE$4!*mVN(r#kJ2Wc=BAV^Rw~z9HY?BOuH*9xIxqJyx+X@ni~HWQu7AOUm@@la zKb?%27N(? zvy1F}Fs$!4{QPv{&zRXuR6=vZK}`jSEWXbS@krNqwHc@11~!Mn0ZTCx;ns7vaa`{c zyJV$%oyB+cYT7y9m}(cxb$j2tj`ojT;}~pG1zC7PmhPt2KG1fmYv{b*@#^N(fLu|i z@s(VHH~2;MB+C+ZQ8V%|F_1464NR?fUEaOq76}L|cepLPxH&U1+QqScad+e5z*$RS zv6awZHavfLW30&I7O?A%?VaZ{Fx>}!`TfXmx~P0-=v`Ou;ZOlenhoiFuBBwsQ|7zg d@7%@<{~rMC$q;BB%K!iX002ovPDHLkV1lROXEXo+ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/juice.png.mcmeta b/forestry_resources/assets/forestry/textures/blocks/liquid/juice.png.mcmeta new file mode 100755 index 000000000..0c36dcaa8 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/blocks/liquid/juice.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":32,"frametime":1,"frames":[{"index":0,"time":2},{"index":1,"time":2},{"index":2,"time":2},{"index":3,"time":2},{"index":4,"time":2},{"index":5,"time":2},{"index":6,"time":2},{"index":7,"time":2},{"index":8,"time":2},{"index":9,"time":2},{"index":10,"time":2},{"index":11,"time":2},{"index":12,"time":2},{"index":13,"time":2},{"index":14,"time":2},{"index":15,"time":2},{"index":16,"time":2},{"index":17,"time":2},{"index":18,"time":2},{"index":19,"time":2},{"index":20,"time":2},{"index":21,"time":2},{"index":22,"time":2},{"index":23,"time":2},{"index":24,"time":2},{"index":25,"time":2},{"index":26,"time":2},{"index":27,"time":2},{"index":28,"time":2},{"index":29,"time":2},{"index":30,"time":2},{"index":31,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/milk.png b/forestry_resources/assets/forestry/textures/blocks/liquid/milk.png new file mode 100755 index 0000000000000000000000000000000000000000..a0e5d982b8cc6139929fa6d8e8da6ca27daf0ea0 GIT binary patch literal 2935 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 M07*qoM6N<$g8VcgS^xk5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/seedoil.png.mcmeta b/forestry_resources/assets/forestry/textures/blocks/liquid/seedoil.png.mcmeta new file mode 100755 index 000000000..0c36dcaa8 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/blocks/liquid/seedoil.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":32,"frametime":1,"frames":[{"index":0,"time":2},{"index":1,"time":2},{"index":2,"time":2},{"index":3,"time":2},{"index":4,"time":2},{"index":5,"time":2},{"index":6,"time":2},{"index":7,"time":2},{"index":8,"time":2},{"index":9,"time":2},{"index":10,"time":2},{"index":11,"time":2},{"index":12,"time":2},{"index":13,"time":2},{"index":14,"time":2},{"index":15,"time":2},{"index":16,"time":2},{"index":17,"time":2},{"index":18,"time":2},{"index":19,"time":2},{"index":20,"time":2},{"index":21,"time":2},{"index":22,"time":2},{"index":23,"time":2},{"index":24,"time":2},{"index":25,"time":2},{"index":26,"time":2},{"index":27,"time":2},{"index":28,"time":2},{"index":29,"time":2},{"index":30,"time":2},{"index":31,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/blocks/liquid/short.mead.png b/forestry_resources/assets/forestry/textures/blocks/liquid/short.mead.png new file mode 100755 index 0000000000000000000000000000000000000000..595689671f4d8acf146d9c5b2ec263d730e72f87 GIT binary patch literal 11984 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/mailbox.7.png b/forestry_resources/assets/forestry/textures/blocks/mailbox.7.png new file mode 100755 index 0000000000000000000000000000000000000000..e00bad9703a23731197b27df35982a987fb5b172 GIT binary patch literal 802 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>B2F`w3c6rV*v#o=tiYr+eEZz3H#)(`d?aqUt-NuhuZ3gkaXA&2AOGebmid1A ze(AkG{0tTiJ0<%Q9{lod>`$G3*kFr8jnvwJoT-M>lqbYLzGx+CruTp0hK)OyZaeB1 z=n&&{A|-jHGRv!X({w|=Rcu}Mn!{#)y@LX0#p0S9E(;8;t=d%9N)}zpQT%W@=5~`+ za_cWkroAt=9Q3@Zn!KpARlL_vd|mKbi`|;{zWw@p@NTWR!i8TCKYH4H?=d_)ku^R$ zb=8zU^`KMJSKj?;HGA*g`ZLex$9ErnAwAvtB>$gB>^A*A{~4|(%DMD1)b0X$Shd78 zq9i4;B-JXpC>2OC7#SEE=^B{p8X1Hb8d{keSeY7Y8yHy`7-&2>3RI7zAvZrIGp!P& z!C2S8NY}_T#K_3X*xbs*RNKH1sG-K+dn-_b5XgqK%$(G`#N1S?5+H-YG~UqQ;R$PP Oka?c2elF{r5}E)D039p< literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/moistener.0.png b/forestry_resources/assets/forestry/textures/blocks/moistener.0.png new file mode 100755 index 0000000000000000000000000000000000000000..a99fa4b58cd8a6b1cc35eef0a158620d6d581172 GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)vmm!Mcb1Ep7EnkwGbEzKIX^cyHLnE7WngeFN=+y3 zRMTnS9%yZxJ*~9SVO`2kuW<8EU+s2V_GtYPNe{^Q7%arF$x>^=l1GpHgc2*}3VUXM zD9}nNwwu@fF5&ltDnm{r-UW|CCssw literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/moistener_base.png b/forestry_resources/assets/forestry/textures/blocks/moistener_base.png new file mode 100755 index 0000000000000000000000000000000000000000..545997175ede8b9ca3df8abdd2151f0374476300 GIT binary patch literal 842 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_low.png b/forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_low.png new file mode 100755 index 0000000000000000000000000000000000000000..8bd981d8a8db9fd00f3df74aa1e6277a917b08ac GIT binary patch literal 758 zcmVPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipt> z6*exTEpF8S00MSNL_t(&-tAbyj?*v@eKU5lY`c^bVnIS;_b0gU2b}m%PJF}u1kxfv zsxu~0dmOX> z?B_sYi~vwte!p$BrvWwXc6_iHShJwDIg;O^eyc7BCrv&ZfH zs&`qr`zL<^iYWV_VfsIYRHlpx`kMx%(pfR#U#x%n_M0Z30o^Fqiea7aN1y5F{gcUn zcQ4OyQF0o)kZOWj4ykw86$tv!@XibpOX2aB3dUjpIbBvOrW zV9Fm^nc~BTJd2vMc^c!!5kZNVq_84_^O+hz1g68`Q#`Vs!!w2kXwy+&X-%T)Ib*Q& z`4msC28=Zxv(&moOcAvrm=h5jbbu63uKBUfk0OG)_3}XkWunW8iVCK{6pzX5?}`tl zG|K-0VT5+pwb9G1UCn*}AUuFC8Zc!I(A9vG+dK4}T#g2G2b+p1n`ewmptmoc_^w$I zQxck?Ap;|RfeA?QSnqK;(^)*LjXk{^teEiQe&5!;3@(bOb#rZ}7_iJ|>hP>Fu4kEr o=NOA!P*6}%P*6}%Q1Jip2M9VCjE{bMZ~y=R07*qoM6N<$f?yn5Q~&?~ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_maximum.png b/forestry_resources/assets/forestry/textures/blocks/moistener_tank_resource_maximum.png new file mode 100755 index 0000000000000000000000000000000000000000..405b23547844461f69a4140c0f235658aa32ab69 GIT binary patch literal 752 zcmVPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipt> z6*fE0@QOYF00MAHL_t(&-tAbyZqzUkeKSr{T2{*mQINRs6I}QLDh~W7C%%E-Kmw^! zL0bu_8@k%{+UBsD)J_~aE5RlQzgukQ$??p*@e5%DAKxs3Ap!un5R$q6xFLcI0mrQW z^mR>`0jjYH`KbQb&Ut{-wes=Dte*>bY(h49-R^OFwZ?V3$Ith7xVd-T^X=7oa9G;) zvp)bsq~2(p{*NJ-DN};}rUAKhHca>zqR}_u|D9{(@IqytBsqc1mZLnk+NQ=>XPDJ zW<)$P4j_5w``Y5yhc@AMK1?Exm5pjNzNi?|wJXEal|io0Ydb_vM^2If%Z3k8j}F56 zfUVOsXf zZa(H&Hmv4pt)E5&C1R4oh6p|=HGl|Aht21BWL(2Dg$7i%r@qpfMAbFdVCnNY9<2sU zbvO@cz5f^oU9FNxgI3Fev!K(A}Q3T~ir-_P*Zh<)-tL*QF52ZB8|A06` zJLkLTX=}IQp??q_AQTOlvj$Z4h?CoU44j-s1Ns-6nn}$w#Uaq!7f(XptcWRz&Cr;E z5x>9$Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipt> z6*mfoHM>Os00MVOL_t(&-tAbyj?*v@eKU5l?6xW=#Dc_O`3Ww30f+)Pf}P1a5v)|H^i!S7bbd2&26Z|0RSfRC@|UJ(HRtoPBg?z$p^^&ZFU z|MX=|m;m(91No@#+Ri$F3o1pQ3|Qt7Oi@GsUsfBj99&wy@}YsIk6_oL5r^!~|Y zz}pw+zMIC@dpHkN{P25TG46H_6~~HioJYlkt@U66n9#nvwH}(|-)HLKJ*K!rC?Z_n zZcchT8UQXYbd;{EjfEoM*|~}~Kdn_VtydchCg9b)>hT!o@p7iK%44;$D?HPCa4B*DNUg|Dtjs)s4Z0(_BQao}AIat(u`Vt5aCy{E5 z15^IU$`l_y1A9G)>WK%0*GN^25T&l!WI z&!>2DHDIjqn5EVwVv490!JLTLpaZ0Ma?Ou*eiRYZt(OlXC=*>yR8%kprg%(de^-1c zrBVJ52qUz!u8m%9?P~7(2jKyH(SRvyfUX9d+}@$*(!HNmr@Aqxp%iyAjS~u5riUG@frVh^<<9e1^ pc#g5y1qB5K1qB5K1qJ^fe*l5G9Te8U^C14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>YS?E#<4VxRmq|O{@f2;~%3a6Ma+IO@;Q#;sd#zT_20Dx}$=lsUFXXa7 zJCMU!;1OBOz`!j8!i<;h*8Kqrc6hothDcnt^<(E_G2m#bs(!!s`=9^c&m~oba3x;_^!=qZ_Vt}y38(cZiA{(&`nKmYi=v_v&* z{+|~u_KbfR_=;H`^%*^!0(6sViEBhjN@7W>RdP`(kYX@0Ff`INFxNFQ2r)FYGBvO= zHP$vTvNABxcybh|9!W!PeoAIqB}jv@u7Q!Rk!gsLk(IHzm5Hggfgw;sjlcI+pawyZ k4QZJEC2ui literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/ores/copper.png b/forestry_resources/assets/forestry/textures/blocks/ores/copper.png new file mode 100755 index 0000000000000000000000000000000000000000..84efec7afd27f4537e57ec9bf763c5c2dd7ca3ff GIT binary patch literal 567 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>smr&n3-SrV|Y#eByUn@!WyZtn3szdiNf zn!Wlt(ps4Y!^&(S+c-v&SaN^8#8y! zPdR@y|HPJxgKNt-EzDRwHF0Kh@Zwc*+xM66UY~nO>_%)r1c1j3A$?$-SQ3U+w9IEF}Ew)JD@V=>@ps;Yj!_xqp!-_IpgsVoa~ zV0q!-HEmI`N@E<`k0U3#g0D&iv95uUu90bok&%_Lxs{2jwt*o~Lyf=pR-gt! lkPT^>IjMPxxv5qqKn814Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>-TS6zkBEA^XE_R-n{(!`NL-qZoGba_w&cspFh2Q^YX!yhc{k4y7lDV zwfAoxfBE$0^~=Za-aUH#{Pvd*PhLH_^Y+!l?;l@2e{%cjqnqzvKmGXb>GvEf zMXctjR6FmMZjFyp1Wb$@_@9iA?ZArhBu{o46l3^|&9<-OngUGD$?+H^x( zpJ9Sj3M@Ol-0OXSZc;6AjVMV;EJ?LWE=mPb3`PcqM!E*(x<&>ehK5$A z23DrV+6G2e1_l~Wjsn#qX~@k_$xN#RX)x9`Fw!+L4KXsZGB&p|G1WFO1Zt@9_udNB nAOx}@Ei)%IFEKaOsszYjFpM`e$vmEs3Np{r)z4*}Q$iB}pF#Kq literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/philatelist.0.png b/forestry_resources/assets/forestry/textures/blocks/philatelist.0.png new file mode 100755 index 0000000000000000000000000000000000000000..053849719b269c2f04a9c0c41f936906d986dbac GIT binary patch literal 716 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>p2b|_FYcXE%P7gc{t$Du&W+BLHFW=!L)xW-!v z&9|cKZ-&=g|NsAgoWnISpl2DAyxm>AoCTw5@TLx8%#UVjCuW5A>?e@H@tT zBHJjC@4@5C#b<8Ki;JnKeY`8?)FK#IZ0z|ct7z+BhJAjHtn%GAKh)L7fV$jZP# z14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>4wh?TyH~8`1SQqZ)2$SUOt;PO%D_ zViPjWA#$cu^el%6AetFmc|*YwsD~ zd`r*4+c9#MYwTQ?n7K|-vz?=7IRV|1FwZ%5w!V|EzLSrUYk-lfzk#!_fs?O+v!A73 zot1yRg>S97PmP&(_5c6>9Ydy01O^{tlD9k1nfDDCfgH{PkH}&M25un`X1sK_?hjD# zfv1aOh{R>xb1%aV83?pJTqx=h?c(9tnXvGh0*4mMl(Vg_jz@VXoPG2+zWwr{&+n_x z&z!@sV8WtRuN*CeRA9UzgXS|H-)-+5yIM;S#apm(XrMwKL z$@2^qJrrHfepZ?{Meofffr+P7OV?X`zrW*Lc=o1y8CRB0soSyh>86`m+pRP>E<7#& z&VQDH?T^Rzjn^kv+sLuK;D4jY&rn?@*JxH&)|fd>IgXr^QiEBhjN@7W>RdP`( zkYX@0Ff`INFxNFQ2r)FYGBvO=HP$vTvNABxcybh|9!W!PeoAIqB}jv@u7Q!Rk!gsL zk(IHzm5Hggfgw;sjlcI+pawyZ4QZJ14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>HI0H}|PA z_NXxRs?v8UF>o!7th*7@cq^viR($iVh}s*`^*8mLiyb3py2sCRiJ9vbKhG(8wnM~B z11BHnnA!jT|F;d9W*0WiDQcFkgO{#jp+opg9eYnbry}d1DYl_gwe39gor|pkr&t9| z(X?{Wbt+P~bhZwfs&3(A9SkI$bsP%p!e-cpOt%S{reWz~8#>*>x7Idnx^wg#`|uf> z)^64T4KavL>4nJa0`Jj{A0?Wh0% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/philatelist.3.png b/forestry_resources/assets/forestry/textures/blocks/philatelist.3.png new file mode 100755 index 0000000000000000000000000000000000000000..5139f19d29a0ef7d2882737171905f4c797355f6 GIT binary patch literal 723 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>u#8MR%+Yl>o^n`x|QiV7V6k}gjU_` z<>&9<(~a;AZ^ubFo> z7oQj>uLu{fFei_&Q}irD7e7{ZZdNuvL>4nJa0`JjoF%cO)FkEHF%G9!=x<^yEDqYG{ZJ-^UKRQl%K2Y(4|&Zc5?5!>2ce| ze)G-pxGk`L(vIj!*vGe&mbc`lC-?S{hbYZq>SX?EU5=$DiNf*uU?wl4^*3urOq zrmoWY{EN9hd8+syv-!nef&Nl0ag8WRNi0dVN-jzTQVd20hDN#u=DJ1(A%=!lrUq7~ z#@Yr(Rt5$dPmTiBBWcLZPsvQH1ZgnVH89dOG7T{@vNATeGBMRQFa&C-@%P>e)F1@1 jAuTf}H7_wY)v5%@U@(g}H27RQ1#F(DtDnm{r-UW|($n{K literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/philatelist.7.png b/forestry_resources/assets/forestry/textures/blocks/philatelist.7.png new file mode 100755 index 0000000000000000000000000000000000000000..e00bad9703a23731197b27df35982a987fb5b172 GIT binary patch literal 802 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>B2F`w3c6rV*v#o=tiYr+eEZz3H#)(`d?aqUt-NuhuZ3gkaXA&2AOGebmid1A ze(AkG{0tTiJ0<%Q9{lod>`$G3*kFr8jnvwJoT-M>lqbYLzGx+CruTp0hK)OyZaeB1 z=n&&{A|-jHGRv!X({w|=Rcu}Mn!{#)y@LX0#p0S9E(;8;t=d%9N)}zpQT%W@=5~`+ za_cWkroAt=9Q3@Zn!KpARlL_vd|mKbi`|;{zWw@p@NTWR!i8TCKYH4H?=d_)ku^R$ zb=8zU^`KMJSKj?;HGA*g`ZLex$9ErnAwAvtB>$gB>^A*A{~4|(%DMD1)b0X$Shd78 zq9i4;B-JXpC>2OC7#SEE=^B{p8X1Hb8d{keSeY7Y8yHy`7-&2>3RI7zAvZrIGp!P& z!C2S8NY}_T#K_3X*xbs*RNKH1sG-K+dn-_b5XgqK%$(G`#N1S?5+H-YG~UqQ;R$PP Oka?c2elF{r5}E)D039p< literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.black.png b/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.black.png new file mode 100755 index 0000000000000000000000000000000000000000..82ff6a01c9a944807e826fab940b9ec4235e20b5 GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFYfHTh&;=il{@DV(2w@sjHa96&QwOI#yLQW8s2t&)pUffR$0 zfuWJEfrYM-d5EE`6Os#mFRXcij}W>$ch**B63fXW#>UHx3vIVCg!09|fK zVE7LN%P!1350qjm3GxeOU?`h>)&j_5O!9VjVd>Af83^QX7I;J!Gca%qfiUBxyLEqn zf*zhOjv*Y^UC$mAY%t(qb_{HK*|35+_Wxc%nez{>*R7eHBI6lux#U$dd-t(f!j-G? z1ms%WzIh#9B*^xx{{HC=eoa2v*ZFt-V+!ZzU%cdc0te7c)e_f;l9a@fRIB8oR3OD* zWMF8dYha;kWFBH@X=Pw+WoWK#U}R-rp!USI4n;$5eoAIqC2kGjJO3U6YETB*kd~Q~ snwOZHYE=ScFcc)Fr|MPe8=A$&gP9c|X7-Jw0-$mRPgg&ebxsLQ08zz%Bme*a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.empty.png b/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.empty.png new file mode 100755 index 0000000000000000000000000000000000000000..f38573fc2ed6c2fe51f94efb5e0f3089f77041fd GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XKd}Uw^Is|K62$ z|NsA=-EFM{6lW?4@(X5QD4TrN0?1=b@^*J&7Ub~(S;tx65n0T@z%2yAjF;}#{Q(NP zc)B=-a9mGL$jC@a5SS|_c1poY*hPm`Xmvw_V~*AYRZgXlWI4d zv}y>>m14bOXv*v2!_7LIiQ&`_i63*K&+P-6r&{6~QIe8al4_M)lnSI6j0_BobPX(Y zjm$#~Ev*cUtqjez4UDV|4Ah>u)}d&~%}>cptHiA#eCOXoKn={vX l42FWl^i;h{eM7U@crdd9#LT{tQ~*@Y;OXk;vd$@?2>{uYa6bS5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.green.png b/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.green.png new file mode 100755 index 0000000000000000000000000000000000000000..7124311e95f7dd939cc90565734b9fe88dd53b24 GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFK z_|NeF|Nl)JBQ^o0m`Z~Df*BafCZDwc@)(o6-CbDvGj0X~Ih+L^k;M!Q+(IDCc~Y?g54 zsyqR?7PoI+hZhO5J*&TedV^n+Pxf{GUH_QE`S}+wxt_oQG*h+2HKHUXu_VdYa19@85pQNajiqqkei>9nO2EgL-@|WhkzQCK{lji u=A`B&=B8Se02vGgiRr0&mHLKevGHJL1&En_BdGwWoWax8&t;ucLK6VeSbnnr literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.red.png b/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.red.png new file mode 100755 index 0000000000000000000000000000000000000000..b8b86e8fd4bb795bb2b5f66e4cd6c56d9977cd72 GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFo=IjdTqxbdAhI3@xn;jI9jKwGE7{3=GtsxYnU)$jwj5OsmALA$;fGLqHA6ARE#$ ub5ipXb5pHKfDDF$#Pn3XN_|7K*my9r0>sR|kyHRw&fw|l=d#Wzp$PyZJ$@Mg literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.white.png b/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.white.png new file mode 100755 index 0000000000000000000000000000000000000000..86ec1d3e0135a46f65721e3fae80057aef5cc26d GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFi z`t<4l|NrezzF7s7Vk!yp3ua&_n|#&+$YV_Mc6VXv&$t-~vL>4nJa0`Jjo-U3d9M@gX9u#aa;9+(QY#m0k~6(DBzjidsgat2RVKbLh*2~7Y1Qh<~I literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.yellow.png b/forestry_resources/assets/forestry/textures/blocks/pipes/pipe_prop.yellow.png new file mode 100755 index 0000000000000000000000000000000000000000..b7ba66f5105651a3ed053784eb8c35b93b5cb448 GIT binary patch literal 409 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFo=IjdTqxbdAhI3@xn;jI9jKwGE7{3=GtsxPlyw(2$#-l9^VCTSNHHzlVStltDJ6 vW#**jCFZ7Dl>iwG1&QgYdX@TyX0h>LW(A0ueIuy=sGPym)z4*}Q$iB}!^wYv literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pods/dates.0.png b/forestry_resources/assets/forestry/textures/blocks/pods/dates.0.png new file mode 100755 index 0000000000000000000000000000000000000000..2f9d2c7a724a9781418d115c0c75338f4b7dd90a GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggq7IqGEj#+PG^3-s_xr< zXPG>!;PHy=>mv>P>n2!h-XVj(N$ubtj6NC3nZO{(LaoDRS5MT82Y=o7vZ= zHEh1jyItbTidN;eiSsyCI9yq?SzvpH$^4GTA{BFL9&}$4+wefgjk_VMY3DJKZ6PAB vdcTB*`A^vN#93v}66SmM$Nzjz|G`*%KAmmp!Y`+R9%t}$^>bP0l+XkK9tV_l literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pods/dates.1.png b/forestry_resources/assets/forestry/textures/blocks/pods/dates.1.png new file mode 100755 index 0000000000000000000000000000000000000000..55c5ffdbe001b0fa66b26ca8578c5946823c3d73 GIT binary patch literal 481 zcmV<70UrK|P)y&5D^Hd1MX#7fe{LM$4rY&?UFx9|`a5{YLZHX^}RENC?d z;!-r)s?oHa(&_X+7PS#k^8mi(Ir)9(kqg3e^zLu$eYKql8>FWY2o*OchO>dLfp zcJYcj8TT+f?nCoR_+v?C25Xe7C*88_Y|J}{$7P;NHRS$?jOLXH4A0@%Cat$i6h-r;L%6XgPC6i+q;k0wxIA@2SBZu0{iU>B{~9tkw5~Df(!pq{q97rwRXY60C1s zbOg)mm9A|A7(aXrYr6R0iR5}Q6ztxrB9C{npJL#ot{)Tg7lq*et61Fu}xGfk$uP$^1HhIj~hM# XgqM_#afsK~00000NkvXXu0mjfjOESS literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pods/dates.2.png b/forestry_resources/assets/forestry/textures/blocks/pods/dates.2.png new file mode 100755 index 0000000000000000000000000000000000000000..4680395a7d7771584b5d760f2d23186f23101d9c GIT binary patch literal 563 zcmV-30?hr1P)0l-N_ zK~y-)-Os&l6G0e-;dl0DR*RjroP-5JVF`&UAfQUgZEzJ-hzp_QR* zQi6l+jlJIA@ytgNBO2rMoc=sIN9}gIl4{MpD8g3?Bf_w07&Z+jMWOgd-o1V*hsPs= zRBN6m34=K1ZWK{F$H8=p15S!!W%>P^XYyhHlJT{{dl<*;_4{;#fPNSJ?J#QuO>EMd-wIMGp0D*{5Sj**P!l0@+EeebX znK3+yW7*c4$oGkqBJe!wV@RAPt119IBf@@`QCUl7481VqqONJ3V_R!pZf$X2YhLZ_ zkZMiq9J?DE4C44^!BL(wiXzU+l1;6#A}pNaM^)i~$DIzT);vj5e5E)mOG2f%YTG3+ zpR1$!eC6L4Ng}>d^uiDoh797EVbhQV0aIgcF0dwlX3iH2T-#zrXq^LKQ|sG-j_(6t zL>SFxC!`Y11IlkmM-^-HR7(UNt*d_2EHvk_db&7YGpY9Fi$QCC4VXrzjpsY6_}sT{*4i uYJfYI3>Dn?FcTgn^hcqk)0M)TW?Cv>2e+EGP z_s@SuYwOu)A!lHu9?|m#l!{$qLLCW`Q!0mF8~D9Tu9`kG8I4NG{Y$WrGkE{u9g-wb zs^oe7_647}zmEhPp9*8Y4bW-z8Ac%@o<&b6B=uPW{|Eq?35cSIgqFeYw{I^)96KBp zOd^QI6};dNe*YS$6XJ_DW?GxPAg(KTfkpYEfN7=(LYI2Yo4nvx!6qq=saHJ`qDA@4 fL4U09z&&vT51x||!P3pf00000NkvXXu0mjf4zSKH literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/pods/papaya.2.png b/forestry_resources/assets/forestry/textures/blocks/pods/papaya.2.png new file mode 100755 index 0000000000000000000000000000000000000000..bb10f28a8b1e40e4eb775c894b62f3da948a8a2e GIT binary patch literal 601 zcmV-f0;c_mP)|W zK~y-)-I32rlW`o!U(a{Xo?+V>o2V=&611OkX!c#mKUC1llQ9?YRw*M zYC`c~HpXz&K$#;{s>0)k0VdLemoL2dQ(oR~7^YHSs0dd0Cd$e%nzYdF0YgLGfq-10 zO0C(Wb=tQxT^Gb_(5`0*UcAEbk0MA+e}MaYxhX2&shP>AauuwBpsv0GX8Hv9a>_ zw2tF|?Fd^%jn;7Mx{q{H5s1w3WPXvt7Z1x1d;7W%Sjl_FN`COQ=kA$e`QdWh04!8s zhDdmW_^?5xDgY?X$ZyR?QxNHZIM}wJ3`mX`{{}=O{h_V{+9@KsL9HS5dP4d8ISg!D zXr4f;Eg+hc<{_2^rLu5TI|rat77i+!wM`Fk_X&sms|4V)WRH){&y14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Xa&_yh$7#l^)% zMMaMtJGOuS{(bxQxkktYrK$!btGGtUadUHXa&m6nx^>HzEnHk&CT^l^Y-}tnEE_g# zSigR~k&6I3JG-_mFEcaqs#UAjty||9BFW0idiwNfOCK@E5DD7=iM4Cju358Y+qP{R zH*VaqV~2!d%cgy=%MK|Bw1{74QFK{!%)8s^qfl?h z+P&t!zy9@yTBx5}KR5r`8_5O*BMF5hi#AUw+XVhgEE#7uvbO|Sby+6cB*#2?ym87x z^Fv8N1$HNwZ{9OUpTSF{W@n7;8o8@gn=dM4vNRQbPT6j~m%U5l$U?0twt4=gwQV2l z9{bIFRb&&n*0jPUE#|}3t5LP<9H$A|?6-KnX7Ap6414AqO_NLxNxgs1{?VuN>lsA! zH+}ui@1*b4;j{8fIsf5j+cPzHPG0iz*0SH+y8rptvI|u{U-AGL#|)|^t`Q|Ei6yC4 z$wjF^iowXh&`8(7T-V4T#L&>n)WFKrSlhtJ%D_P5$x)zsBn`RwDVb@NAPvU421dF@ zrXfZ~R>tO5CZ^g3hCmH9{@z=G8U#T$q-Ex$<|XE)T9p7943_ccnj7SKK*o8x`njxg HN@xNA-beo4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_blade1.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_blade1.png new file mode 100755 index 0000000000000000000000000000000000000000..6a7f0f352ea567e44a80463a3cd652fbcd24a85d GIT binary patch literal 657 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|i|~XCYjhYGnB+WN978hhy`8oxoKrsngO;7=e!}=k=3TJFafO{ciXAH^Df9}m{9SnU%^Bas zw4|TBVe>BQoYrA}e!KX5&#!MEdF$`jiZy(#>fI{#T;`mm3kyTG?lFnJzP<>(=?qUQ z`>shf_$_x1Udqc8fN;a zmF$i^ckbMWdyn__cPkyrFiEnJE3T?KRbq8i;_$(P2hXXgtE>0=I&8a{15`8TaP|40 zKl9hE+h>2wS#wUYj#&4Pe^>szeXINWtJSil6B*_dhlGmy=9tA-R=haQ|7zDU3Fmpw zW#r_J`R&-b^WmdMi!MH6^zm@GQ1K@<{hw>gB8^99qO%1BtM=aeuN1gyCuc>L+=EY_ zCe`ilFMc<1f}x0O<29>!JPRe7f0pgOo5OHEIcM!%!~CAkr4rYgem;KuIIZ8|$7RRz z^74->m>*rPK3}$5^|X;oivAhql&IGhhf8BWzq*`VRe$do3(MhimYZ~#AN>1Q2a-Lw z=eyiek!Q}1-+~i+99_!vT$K(LSS-=;{^rWIVAU##@A2>JkKABq<%r5YwW-IG!&bm* z(ZukFuU}_#hTkoC!g@JT$H{8m_SzR*OGP%{Tr-oCLs{U~-{XE)7O>#E-N<|iwr~l#=Q&-jHf+a978hhy`8qd>$ZcyvHde; zJ;Q$p=4|MmqM5=czEA0a`HpnY`D(876#IpHSOXI;sa{nySjl&0=?2I8GWAfgmrJIE zuer$|lF`OmyI=AwU+wRTetUVl%-rcYmAQCG*G z#wXX{!+QO-X~vAjA8+%#x6wi8U;fB$|< zB}0Oe)AdpXrIg6F#~&@CT7Es7DY;tz{e=Jb9*G^f78U<>lg`GQIW?cE_VTUraVa>b zSh<7w|1Qq|6aIyMyY=VwTYiQRQG5A1o}$QU4~urT?Bo)6HT*U4_BPoy$6Q)WeBBGv zzFkk=u)1J{{J&+h6IcWoT^Ix%uu}zxe{u7Lobpb8x$_M$rWrh4{an^LB{Ts51|a9* literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_0.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_0.png new file mode 100755 index 0000000000000000000000000000000000000000..30060b5167716b89014b5eb9722138678ba37b9e GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|n*l@P{yRXSU7jwEAsP4H&e+I%M1jY3?hC2) z&6^k{Zzf0dJQR&llYLYo<552KmdKI;Vst0A0IlX8-^I literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_1.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_1.png new file mode 100755 index 0000000000000000000000000000000000000000..3bf293fcda74d8856f89940ceef665ba20927975 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|o7IDmutPwhgPtyqAsP4H&e+J?V!-3dyQp(T zq)L~|SvH>6hHH8ripD6e>$Z@c?omGV@c+4g*NXJd*GNftHd(LBFv!<3{gvnA*kBhA zmwngnGFMDmwmZ#hWz_d2j-lu4#Xi)j^|-hk-*#!^+NCR3Em^fR@8>(lH=mt;@0p@z zyq|Y#&G+<%nW61b`>GifTV4g6c4wNvpu)iE0HF%1Ma?$%udmtrZd=VC-l}^{du<{PZrcC= literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_2.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_2.png new file mode 100755 index 0000000000000000000000000000000000000000..6e17ecc0d8e734cea51c9af74bd6748e5ac3b373 GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|CzqpW)k2`qO-~ockc@k8XKdtcHV|;NZ($2u zp1|93L`t%K?;}HVJTn*V+6mUD6kCWgE<{k_lsn&nD?iBIRVN7xH{G0Zs5_}OBOuV7=xnyt@fvtKY1 zz4dG_@421*if7I1+3v{uGaS$~TJrN5V@zH;!vRw;vqfN%^Q?S1huG^U70;$K&0tV# z;7kBghr=HV9J(HTFRt8leth$^aE0yhG4^X27zI#~jGumWTYB@<%U5;*J;~td>gTe~ HDWM4f`~`Su literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_3.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_3.png new file mode 100755 index 0000000000000000000000000000000000000000..1159b4240dc27bcd145fe02e39f8b3c413e86227 GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|r?6_>r9`06Q%@Jikc@k8XBhG|IS9DgdpM^j zA2j9Qy#9ejuJ6({+hc9XJ)KkUnhC9O>De$j!}Rq3yKnw4tgzmEQ?>Y9?~Ik}vX5N( zZW|P|Z_A6l?ceLR`pF%b7NVnT<}185I7m(DvAz6;I<+SZ1|_;}>*k8NvM3o{os}== zuvI_c?fuIS=KSW!-1pP?K~+5iLz%YXS#$meTX%1tI^o%7<~7U~^Y|GWPG?#!`T2~o zMPLy~c7e|643Ez@8Q(CJF<2k?5^B-%Ve9G7uh%{MY?@KY67>7%*UKCN42&q~z_Twb X+5B1M-#>f?1q_3ytDnm{r-UW|;v0nI literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_4.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_4.png new file mode 100755 index 0000000000000000000000000000000000000000..52a44a3099f458b7a74f7c55dbb45001c020e154 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|r_9!a=RW|2o_M-AhGg7(JHwE#$w9!?-pkon zX9t_&!cTm0r$6s7UvRge$Ix)&J-4Q*9fD;-Ytw%2pZ(WfBtPA3cgne)g2q=%duROG z=k9e&SGVf@!@coqC$n!*ed^uqd)ejnlqsDjew=4tGoRC%L1LGf^L4*&B__d{S!d1p z7iblSJgt_RQ!KA|*1VoA<~={dfjZSCKc6w~Df_-n=u%A?gLQ*!g7krxH4F?feW!t{ z_!U|Ncr*7^GPnl1IL|uIm%uKupQ~M9Us+|{-K#bG*mV0Hvi9$&lVW62U_e1P=FH1w W$q9e(B>y+izYLzPelF{r5}E*AFniYk literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_5.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_5.png new file mode 100755 index 0000000000000000000000000000000000000000..c739ec24f84381d9a34f0f0d9ca272ff78cb5954 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|r#j0iwJSiOC!Q{jAsP4H&M@R_HsEo!pVGQA zxIKnhv9R}@ZCY_pN3z69Y46P<7gtVMr8x1{$%p^X{u4XgEjvl%+AT?KQ{UzpzxKKN zX*qj7mzh&MyYL&swOMY8IrXm zKF?#ze(N51DttdX&tYbU0*kippnX*g>#y#;d)QTTzU%?M1ojQgHyCFz&e2zAI8gfd z`@BzAnLpff2P-R$1<}72Z}|Q%d+PP$cc+}cz2KSPiMO4vmkTN|FrlD^yDvGL&y*hS T_$|o`^e=;_tDnm{r-UW|cxr&b literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_6.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_6.png new file mode 100755 index 0000000000000000000000000000000000000000..186b5707f91b6f29033b4acbc710d49c807f7b2d GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|r%|T(A$y?Ebx#+^kc@k8XE<^-8wj}WzovYn z^^2I|1H-C?_f}cDaa43_PIv>M?@cD1!@Oy3m^8tfz636Q7Lo_B&+m-%%&U$fUr4f-L6P$uJbDe*N+98_zopr00-57VgLXD literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_7.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_column_7.png new file mode 100755 index 0000000000000000000000000000000000000000..0f96167f56f74f02edb3d63cc8d1d1928147c354 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|7gNgPg#kdJW1cRKAsP4H&N$24Y{1jX`}7Fg z8bQ}2L$}WoVaE)D*dMSgYWG?=HAv^;;Xd^cXGsx)ic#AUf>JVRAO&u$DY=U*Ui^{PEt zYR1piCs*yZXP#DB>)u~987QIf{@vy~DOVpdSTOK4Fh77$cj8*7SK5~CEV#S%RRwRA lT;r{MJM?;iu0{oS{PfT7%K6OHbzmMy!qe5yWt~$(697iIa!vpM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_extension.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_extension.png new file mode 100755 index 0000000000000000000000000000000000000000..c8c43032f99ff6153011d9729fc1c18d0899eab9 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E-N<|3)^2_kK;h0a!(h>kc@k8uNZP2P~dTUc>mJH z)fEmW8TU+ZKb^N+PgZoxgzw)teok0&@ArfyQLD?YMO~KPC9)^POLEeb;(1jE?rt^8 xPjhE{_g-o9+H>;18Q=4EME#Hk8jKG(Op)9BK-BZ8!~gXlWuC5nF6*2UngFxqNbCRr literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/rainmaker_pedestal.png b/forestry_resources/assets/forestry/textures/blocks/rainmaker_pedestal.png new file mode 100755 index 0000000000000000000000000000000000000000..7ad8ace855f13859c46f36b46ea3addd511ba4e2 GIT binary patch literal 920 zcmV;J184k+P)wh1>PYoMG(p% zCBg+SfMm*u>YQABySEf*Mtk`F-ES_G=*~x zVHj3Q-){vjvP^(XGp#kW)*vEit;N6JLJLCx10f<2EDo5z!!QH@Twh-!&-0lj%-LtrG{(qU zUuPDA06&W?SgZ$p|NQ(M&N*COULw!)8#Bn@qbNdA6q0q{@4^tk0TGc9;P+^nrbv{?*hJ>`(^5Hg8-0a8H_Q=vJBSR2_k|Z5DhWLOn@Kv*ThUPHvxP|0f26|EBibL zTNDMXwaD`v%gf6kBJA()SNb{#0uT{SPfw?wG3v^HRxADUIiTC^Rsz*pi-56;7eyiE z&B602(Fapk>f_+G){V3THQiG@3-~j>FO=ii<2K-Xb+f_W$h`O(3N#fv0hdch5(N-`>NwwXXu6hn{Kg0<5*z+WL<5 z^$YZ$9bo0nV|-cpI8|%>xcL7MYioG2x{B8?F0gX&2xkv}AE?y4FGT)#BiwOo31|su u31|su31|su31|su31|su31|tpllBW)YB;eckSV|b0000))c2u!4hD5KHPr$3c#B7eSg+j*LCX# zhyw7)Y4*&#xVZfF^TEsn1VGZ(6I9(jd7Ng}4a4q)uvFvyUFAzc1!tX^t>r}I*bouh z^I^QdQ-RqN)Iw%zu`|50cDaA{`1r7dUZL(q-901wzVEuOsSLwz9Dn@J7LiD5eYu_5 zU8N+%BWvr^G?}XI_s?Hmy?WB|-(^Q;H~`yhHUPfdd|cUGR!*|+qWXUWt?uY+Kw3|y P00000NkvXXu0mjf)Og77 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/raintank.1.png b/forestry_resources/assets/forestry/textures/blocks/raintank.1.png new file mode 100755 index 0000000000000000000000000000000000000000..2c126d71a45b768913026932403a3f6337dd64ef GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqWPG5d-?Yt z%`>M4-LdUcniS-v+1b(YWX|2##bt%1$!Td}vzuKerDQNxRMiA9wA$=b)^=A zVos?%Uw>cmxmm@1@222n92-$j3O(vhYu)O&9$%3IbQ@3py=Wl?j07cc-BJYD@<);T3K0RY>nq5%K^ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/soil/bog.png b/forestry_resources/assets/forestry/textures/blocks/soil/bog.png new file mode 100755 index 0000000000000000000000000000000000000000..2ffa34aa5ef56c031068f8ba20923683444ae3ed GIT binary patch literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>~Q?gt%%d%BadosmMx- z3i1i@^NI-YDoINyNQo6EJgRcf|F7S6 z;GByg*9#s8vy&$z53x?WW8(ELfKTmDY5jB&!9$-8ugH1lx8jV-)vL>rBQ$p%_#(1m ziKJow+!^~5^>!-rnQnN}^=e{w!_l2{opQYQ#1)s@t@R5G`zYw{`+jc7al0#`Imvy` zU;q92FXEp3M`tD@hUx1r0-d5-;u=wsl30>zm0Xkxq!^4042^UR%yo?nLJSS9Obx6| zjkOJotPBh^o*V^v2%#Z2KP5A*5~RUc*T6{E$TY;r$jaE<%EVOLz!0dR#@~A@P=gT2 khP2F_)V##pRI3sogTWx)(AZyo)?$!(p00i_>zopr0Acuy=Kufz literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/soil/humus.png b/forestry_resources/assets/forestry/textures/blocks/soil/humus.png new file mode 100755 index 0000000000000000000000000000000000000000..144e04c37537c3663c90f36c4301ded2dc0a1e57 GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>~Q?gt!_@uxJP~%kwdb zaxv+Pv8V|#%kePkim`}sGD`9=@v$*#39+aPFe&geEAlhT@-V6kGt2QZ{r~?zSFipQ z&=AHXZ+91=>ODC?HUnpYM`SSr1Gf+eGhVt|_Xj9g>*?YcB5_&OkDZCxkVD90*X`{8 z|8Fu)UmDnE%y84aZ;s-egp;oBCq++9-}!IXK5i~f$DauyCgs*4Rg+d_T`Y|7%u1*b znsQ0p^t0IK^s9&Y_U`e1uuxH$@%rsKE=jwU@5pb=eHwEhExvr5xh@qjCsezTL zv9^Jcm4SiAlcON-AT;FWr(~v8f;1TG8W`ysnT8k{Ss9yKnV4!D7y>oa_G)sE6h%h0v!@R3? z+#{|7EmSRWjVMV;EJ?LWE=mPb3`PcqM!E*(x<&>ehK5$A23DrV+6G2e1_l~Wjsn#q zX~@k_$xN#RX)x9`Fw!+L4KXsZGB&p|G1WFO1Zt@9_udNBAOx}@Ei)%IFEKaOsszYj XFo-uaT~=d14P>6DtDnm{r-UW|^+h zcnw3jVXZT(-oa~(3=1daxV!WGZZnhKf97JRBg2c-EM_aisY}d)_c^?Hf4?arz09p4 zasO>Dq1QYMZ5p}4oW3qPcdRE@Veg7y*+iquUlyHnOA7^THP1xe|A7e`IG^?C7;(iS5(9haZP6n5bS+6Z;@0e%=$;#F_j2dj4K(-M@cz e#r(R!bN?BcFD>frTphv$3UW_ZKbLh*2~7a(JIO)- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/squeezer_base.png b/forestry_resources/assets/forestry/textures/blocks/squeezer_base.png new file mode 100755 index 0000000000000000000000000000000000000000..abae4b8f4f8c8f79767e59cce6143a7cc7653361 GIT binary patch literal 938 zcmV;b16BNqP)JN6lWO6Kl9G)@Geth1KC^>5h9_h?O_Qt7%BAN#a4S)L_uhmMT9~x{Rix! zmx2%^r1oMFdbdkYJs52l#ls$|Rf3BiguTS1q|?04?#$c6blyyNBdpnl&FVatciv~` z`~LXu^L*!dU+ehXgr-kh-)sR8v?AP`V0>S$%a>TXKfW(F5PU!8^gFa>um4)|L6oe2>j3pNKCp8AAa+@>5H-;T8_HjTiJsADT8>3b z#t)rbONL+Ob9QO zW~f#|s+ACcMT)#wI!JZyu}P0u%*2lPUQ-~A-!meZ*e^?~@k0ryH~9LnLX-ucRA%|? zyIJlQj_xRe+d|jFTzgRj&&^9dxbo1Xz#>JyxTW~x%Ol2j^Q+Z2PXyy4#o@<$if{jX zk4rq_Y~7_+ZPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyV! z5;-SzamBR&00P!YL_t(&-tAaDixWW@e&%C$C+>>T5D|ivh1?185F{u7g z-!}v+@Zt5ng>X0kKu+hGd--wUaLDN#o6LXk>=VHjfUmltHn zKY(83$CEMMe|E6HH!Zy$9(b9}o6g@B&~*whU1(bVe?ys4>I7Nm0cCO)7RA39fBf=@ zY`p^VQEq!Sk%1pj_ z{bH%Ck5A8FF@lG8t`>L#8R7n|D@Mmdzqj%ake9JmfQhTWdU62(Vr7&Z2d$##?|BNnRrMbrkWnG^X<3>$yRc|-49fDn43#mDes85F*z309)RZ!-Kt}L`xpBJE zn=j)LHZ|r+2cxnNFdEB@bcMsw>$YGqVw~IkV2(gWr96R*jCp$9R`o|9Ejt~l(O7~} zVjMY(k<8-LJiTtqm}fMW_0$16Vp_t&j#HP>*>yM=B^ZrmDUTjE;ichU&dqV0dQ$dVe5Dpt-d|r`3U)w5W=R$?kya?lzRz}aUIZjKs_G7UBQZ-T&N&ts?f=qctF0e zaRoExsjU<){FPCopuzvgZ{T|pphPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyV! z69N^0))6`Y00P2EL_t(&-tAYtZ__{=efMGeB7+(zK}Zo3L!k^HmI7j8=8s@xLaNvp zSrI#P{|h9RiYa1B2f9$HARz^iRY!`|s}o-s+;jYKDHjRs41Sx>=VzaP@810$!4iCY z`)Dpa4gip6v%DNTZ02siyO87m}e4qveB`o^ZfkKd>81uM*r zWCC9>gwYHRBVd$d&xTRD*!*?Z=h<_NlEOQMOY!Rcms*v<0bpl)vmn>u(HH=5@76|P z^487EMp+M!#&8(H(+AfpJdsTB`0iD!?V;aW`xeN{Sa=*VR)}O`n=oWn@rwP*+S#Sh(rYWwm!b4n_$^fi&{yaT}f{Jb-KI z=FKSY>Nah#KIct5wjR(_drTQ6i;A6BPn)1k<>XXVOfb)5dz#3pYQzM&u8?pRm12}w zdw_6g)&-h)$_l%Phtc}u0WVi5oWu|=wRUge@rB$CJl1_c>jBMp0QUu}Cb?Lpt?5*) z>;dJ*#uv<*r-@dWym`JgFNYOV7+Mx!bY5^6fr&@P3OjeMSn&*x#`UK`UoZ>~PqKaA z?{%_hs?(f~t;-^F*G~h~w_m4~$gFu*iP$Y#v}nPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyV! z69F*b|CYW000PEIL_t(&-tAYtZ__{=efQz`B7+*Jf{-F6hKe$PSSk<`Gk*jlEJzg- zjI4+qiLDEN0}@Nb6fq?Oohp?9DS)gxQcSN-d|`0U@yDfHB(O91Z9bo$eg3_B_j?2@ z@afI{g>X3lK%UKW_lo1f<&bA{tTX@N^Unku0KV#mUQ}@`m_`8d<9hMy%-a_3SDa;D1Fcj(&lH%0+(pYARIKt>9pm3)|t6k@f2Cs=xYeOuuB zuTyw}<>rPmh9?+;a1MtNFiO&AgD_ca_PXQo^f^XJ?wz7V@#5XrN|nI@U~hLjC)eT8 z1ORa7=2mX<&W+1PSr3mUa2Ua(d)G=lp^Wk1_EoFxq2F8i7Rbt2xEwN42xV;L>RRHS zU?m2=%H zZ-K1rbfw0=1f#^dat&SGQ?{^*L|ivGstu+GENnSyt@4dfEhSDko>EWP({9+tWnOR4pdRb%lhp ztQ4cf+5?0`(=O1&Q&iYRJd9Q!4|uUc!8C$sQET@WE?>&sz+>G9G#*fo2XIfYa*~Tw z(wffH+8$7BY&^lNdFp6|$?GROi(*(Yg`rgeM&|{G5tw*nq_B7EiWSfBXi|L|^aR7; z@Fd;$y>2^=raH~(*t#k*cf2G(efxP@ip-j4orv9_L4yVj8Z>CopuzvgA4{+&v99=H Qo&W#<07*qoM6N<$g8Gt)zyJUM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_maximum.png b/forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_maximum.png new file mode 100755 index 0000000000000000000000000000000000000000..08c1652f7f7b4a11af4dab5ed2729eab0dab5077 GIT binary patch literal 834 zcmV-I1HJr-P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyV! z69O^3)%EKD00P2EL_t(&-tAYvZ__{+efPuh7a5d72||jP7z$;eVksadX8s69CKfhE zR>aP~g2YlWMNH{H7b2BPNC9Nkk!tno#1{tl96NT%MFKm6-*!Lz?#|!4ci+db1fSkL zo{=j70P13z8(ZurS3+G(vCjObuRb$u0OYa(bEw6>;4A`=?>C2EXa1&uFB>qMJUH~R z*Ez<)p^v-t4gI6jw7u6kF8nOp`5XTO$d%R`&B}ij%9K(k*xx*$OwQzR{EPnQZ~AQG z6|flPtt&04i7rOp;cL&|7zMn4xjO>@6=_f_*_etnVm*ULB5mK=Cj9t)4v$1`Zm42- zBoKsCID$cNmVO(A$zikYEl;N33C?nBQj6pDhp&|?Lju75?siVDgW(te@Ze4-H+kpw z)lyjxhGRH_;n~BR1)fmFcyj-`)%7szR(=JtGA36-MH-=stz6wm+#^xoG5r8?-+cV? z6OV43B zxiW_@0V%LU4wWuS$7LzYR|v9w3c$vu2ca zb(=KUyz^x|sRz(%o?0?N!Pz`wm(epOXcIX#(FGIC^4Pv6YNBf~L1`jH&fKj9XVxA- z4o|bdGM-dnw3dOPU7@^=S0=2lcdy^~YaxdYr&I1|`sK*1ON1|BCMLJ1MCwgrU zSWIj@64pF*q{8g&i=EkGu~JqHEh}J5z2FFjG9DFa?BBa)#WNU=tFHz<66hbDruV+r zZKtKFspd@Cx~yd0@{$7T`>*pt$!vJmDX|+gXwaZRg9Z&6H2DAc1NgQa@m0T%KL7v# M07*qoM6N<$f~5|8)&Kwi literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_medium.png b/forestry_resources/assets/forestry/textures/blocks/squeezer_tank_product_medium.png new file mode 100755 index 0000000000000000000000000000000000000000..8de98c06893e10bab494577f609b775e870458d5 GIT binary patch literal 836 zcmV-K1H1f*P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyV! z69GB^Du18=00P8GL_t(&-tAYtZ__{=efQz`B7+(zK}Zo3L!k^HmI7j8=8s@xLaNvp zSrI#P{|h9Rh$&)92D(tGARz^iRY!`|s}o-s+;jYKDHjRs41Sx>=VzaP@810$!3unQ z`)DCt4gip6^W44SxNte-*&OT4fAaDZ!3Kb@x}g_U91Erqfc&^#{5tbD1$5O7{gM5V zkNaE4=#PBd7GE(qJi-3K6#bEp{ex-gXW7o*_#Yr#ZvCNI`Tq?jrPK*>kq4OMEF6k| zG5+lJfNZ=1idF7hYC+Cax%v)Wd;Z2K;N6Se1pvrML9~(&laWHK7Vrd1uWxJ%{P=we zPq5tFP{!~CLlDm4FakzN`fLy;i_KnlJf1$sD9OE3v?yM^|5B+kH~{SJZs+7WJemLi z?%mqTP2RbA*(mGb(F6`7c>3Uai6@jX9^bucwLSEEE8hZH84H&~Mhc;ftz2D8+!L(C zqsIZ{p84?kCmvq=p5vA?1sSR8`vASrT%&R>OB-hw4o$a#>7195vgXn6tyBTMZab-Z z#;igaBM9f#$CX~ZiAS`kHBYt}mHmLRFH6$xb=zf-?~Rw$T85G`u$-ooWexf^(_`+&v+>hS>X306*WkxE+A znOfTeij9pYm^DuwtuT4>d}mP%E2c2CD!}Nx;4lIckBk)d?p(3r86HilPlKLd7#yCY z`@Yw0r_ofWIUQS9Mdpr|1gLMnPD_zl^Q;rG8#HLpph1HM4H`7~|M&wMjU*9$F?DMI O0000Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipu8 z5EK{fmqNM#00Q7iL_t(&-tAY}_k5xe4^JM{@rve_`{)x@alhk14Id3{wBuJJAn97;k z6#ruX-jh92`U*&9xpu~ZI1Q(>Z_~NYm!<-qJy@RrfEb0~PINIb3K4`8c$}&Ag*wOK z@cl&oN43zsVhn$Im~Kg`41w^*Y?;RkgXj zyAJ@kc4Y-S2ho4{@OYpuu766{jNoqT+!T*50<<^IV&~ulHY2g;f^ag$Q^;FjtJ6h$ zBQi2~c~w=wO5+k*%`lUo^SKWI@Hm^|k^6ah#3)?62k044jfz86`Ogw=ss`QVby4~= zM&EH3?+tXVu@qfYGb>*N==_lu zT;c(s?~m2xlRQaLSwWD=SZDzB49U_x>IpDPa*3A)s9#>^F^NhGf=osseE@eYl{xN2 zuP)QYO<@c>z(VmOYO*DMp%5rmUJ@ACvt5u)Y_fGl-!8mi1?nV_k3 zlP0M1$AqsPmXarFnqKcS_>{Y2u}5dHEzynkZ8cO6vhx z;{V12X7vRNX@xz`qJ~AA=ENwBH8fe`lflw?Eal|aox11lb1n}gM~elVa&>sw{C9V-ADTyViR>?)F zK#IZ0z|ct7z+BhJAjHtn%GAKh)L7fV$jZP#W1hN%D4gVd>Af83^QX7I;J!Gca%qfiUBxyLEqn zf_|PZjv*Y^O?x_d85B8K*fSZ{95}+)_pjQTI@?`9>OTML1I)Wt@MQx1!Jt~=8c~vxSdwa$ zT$Bo=7>o=IjdTsnb&U){3=OSJ4XjL!wGE7{3=A}$90jUJ(vX{V5Dng z8e(K*Wo&L`VybOm2-HyH@4XeMK?r0+T4qjaUSe*lRSA&6U}zX`xL}seOOSa$=eewN HN@xNAp*eXR literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/10.png b/forestry_resources/assets/forestry/textures/blocks/stained/10.png new file mode 100755 index 0000000000000000000000000000000000000000..f2d613c82fac82170de470af31dd2cf85dfa68ce GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF)6fwLjC-)$intYulzt^7#doc8d#YcYa19@85n3hISN#dq#-vyB{QuOq`_F%z)07~ zG{nfr%Glh>#8lhB5U8QX-+L=igD}X3w9K5;yu{p8s}dlC!O$??&@gJ1emKZLp!;0b IIVCg!07#g6bN~PV literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/12.png b/forestry_resources/assets/forestry/textures/blocks/stained/12.png new file mode 100755 index 0000000000000000000000000000000000000000..61f10121aa12af9918fd5bc5a69f16327623c32e GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFn)WFKrSlhtJ%D_P5$x)zsBn`RwDVb@NAPvU421dF@ zrXfZ~R>tO5CZ^g3hCmH9{@z=G8iYYMq-Ex$<|XE)T9p7942FjBhDL`M*S!T92y~yz II;Vst0QH!CE&u=k literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/13.png b/forestry_resources/assets/forestry/textures/blocks/stained/13.png new file mode 100755 index 0000000000000000000000000000000000000000..8cdfacfbc22c83d8bcc2a0cb89e20274f33a1477 GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFO>_%)r1c1j3A$?$-SQ z3i^4vIEHXsH|^=1=lasr&q|4>0dq!Iug22ZL&fYeY#(Vo9o1 za#1RfVlXl=G}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@NkeXaN@iLmNQ1Gifsw9} zX^4@Lm9e>%iK(`MAy7k&zxP(424Rp5X_+~xd5O8HRwY0NgP~!(q4Aa_e$^lYf$noz I=akR{0Ccr`DF6Tf literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/14.png b/forestry_resources/assets/forestry/textures/blocks/stained/14.png new file mode 100755 index 0000000000000000000000000000000000000000..91f4c65b978d6dc08c1bcf841fd93e7f8006f6de GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFO>_%)r1c1j3A$?$-SQ z3i^4vIEHXsH|^=1=lasr&q|4>0dq!Iug22ZL&fYeY#(Vo9o1 za#1RfVlXl=G}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@NkeXaN@iLmNQ1Gifsw9} zX^4@Lm9e>%iK(`MAy7k&zxP(424Rp5X_+~xd5O8HRwY0NgP~!(p^4Uk+c!W40^R4b I&MBb@0KC0>00000 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/15.png b/forestry_resources/assets/forestry/textures/blocks/stained/15.png new file mode 100755 index 0000000000000000000000000000000000000000..88e7b5377d9d46f0f716d07da69afca5950bf179 GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFl;OkH}&M25un`X1sK_?hjDV z&(p;*gyXttPbV*fA_oh5Cc~NoNBH{wRa>*%{lFq2W^O-Ag2%xyu`nep_i<$F!uFGI zUblw#o?4^YpXur9cXGxxZ@n$D*IG|!y9-F&=YM^GdDjZQOrSp)R7+eVN>UO_QmvAU zQh^kMk%6I+u7SC(kwJ)|p_QqDm8r3|fsvJgfyR@gK=nu(a`RI%(<(t4jCBo+bd5|y zjEt;|&8V~@Y~0~rW(pUXO@ GgeCy3EqqS^ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/2.png b/forestry_resources/assets/forestry/textures/blocks/stained/2.png new file mode 100755 index 0000000000000000000000000000000000000000..ee58b30f8d2822b3ff109d43c83c5111d4e70d95 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFaVG(#7)yfug6kV%wwwlWlDyqrSo$+=1_C*p1s;*b3=G^tAk28_ZrvZC zpr5CUV+hA})1FRV21O1Q_DqH~2afRd{j0WSx%+`dLd@KLmIRN3VPauQSnlJ<)`jgS z-@I-O?>)6fwLjC-)$intYuW1hN%D4gVd>Af83^QX7I;J!Gca%qfiUBxyLEqn zf_|PZjv*Y^O?x_d85B8K*fSZ{95}+)_pjQTI@?`9>OTML1I)Wt@MQx1!Jt~=8c~vxSdwa$ zT$Bo=7>o=IjdTsnb&U){3=OSJ4XjL!wGE7{3=A}$90jUJ(vX{V5Dng z8e(K*Wo&L`VybOm2-HyH@4XeMK?r0+T4qjaUSe*lRSA&6U}zX`>^CJAY#z{gF6*2U FngHiscqsq? literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/4.png b/forestry_resources/assets/forestry/textures/blocks/stained/4.png new file mode 100755 index 0000000000000000000000000000000000000000..424d3fb517b8ccd82d68f19586217b6eac0c1b96 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF2OC7#SEE=^B{p8X1Hb8d{keSeY7Y8yHy`7-&2>3RI7zAvZrIGp!P&!C2S8NY}_T z#K_3X*xbs*RNKH1sG-K+dn-_b5XgqK%$(G`#N1S?5+H-Y&@kTQ!iN)SAoGCEb6Mw< G&;$UyM|+e2 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/5.png b/forestry_resources/assets/forestry/textures/blocks/stained/5.png new file mode 100755 index 0000000000000000000000000000000000000000..ebbad593e0f84fd6596b1aedf6a4e175d639d5d4 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF`?!k)>n=D-oYzJJx$EO$S!NQjx+&ywJAFib2=3Cn#P*}Aa( zW^AdAYtxA9l21CPm)8*fPd;pmTbe_vP Hr-UW|aAQK$!8;-MT+O zK|fCy#}JO|rahg!42m2q?3oN}4jkd@`&Vtva`yv^gqXSgED0V5!^Faru-wOytqa>v zzIojm-g|0|YJaAutKZ2P*Sz(%$X;tbo$W3lb)WzB0p?vR_%cBbQ7v(eC`m~yNwrEY zN(E93Mh1pPx(4RDMg}2kX1`?t~yWFF9YF6*2U FngB8dc$5GD literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/7.png b/forestry_resources/assets/forestry/textures/blocks/stained/7.png new file mode 100755 index 0000000000000000000000000000000000000000..6c25b64624e2c3c5e9c6b6fb524683f798d9a05b GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF`?!k)>n=D-oYzJJx$EO$S!NQjx+&ywJAFib2=3Cn#P*}Aa( zW^AdAYtxA9l21CPmbI+eM?|{q$I?rXD HQ$iB}&2W2M literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/8.png b/forestry_resources/assets/forestry/textures/blocks/stained/8.png new file mode 100755 index 0000000000000000000000000000000000000000..55318316596488f40350dabebc16a1908e4437df GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFW1hN%D4gVd>Af83^QX7I;J!Gca%qfiUBxyLEqn zf_|PZjv*Y^O?x_d85B8K*fSZ{95}+)_pjQTI@?`9>OTML1I)Wt@MQx1!Jt~=8c~vxSdwa$ zT$Bo=7>o=IjdTsnb&U){3=OSJ4XjL!wGE7{3=A}$90jUJ(vX{V5Dng z8e(K*Wo&L`VybOm2-HyH@4XeMK?r0+T4qjaUSe*lRSA&6U}zX`anr2@WIqGYc`oam G5}E+LR(Q|= literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stained/9.png b/forestry_resources/assets/forestry/textures/blocks/stained/9.png new file mode 100755 index 0000000000000000000000000000000000000000..41473057546f663177e9846bf3c576512b45dadf GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF z=l5Oy|Nnpd#BE(bDaMi@zu@|Ym@TJ4oFs2|7nc5vn}I+MXMsm#F#`j)5C}6~x?A@L zDCpn)WFKrSlhtJ%D_P5$x)zsBn`RwDVb@NAPvU421dF@ zrXfZ~R>tO5CZ^g3hCmH9{@z=G8iYVLq-Ex$<|XE)T9p7942FjBmg^k1+y))c2u!4hD5KHPr$3c#B7eSg+j*LCX# zhyw7)Y4*&#xVZfF^TEsn1VGZ(6I9(jd7Ng}4a4q)uvFvyUFAzc1!tX^t>r}I*bouh z^I^QdQ-RqN)Iw%zu`|50cDaA{`1r7dUZL(q-901wzVEuOsSLwz9Dn@J7LiD5eYu_5 zU8N+%BWvr^G?}XI_s?Hmy?WB|-(^Q;H~`yhHUPfdd|cUGR!*|+qWXUWt?uY+Kw3|y P00000NkvXXu0mjf)Og77 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_base.png b/forestry_resources/assets/forestry/textures/blocks/still_base.png new file mode 100755 index 0000000000000000000000000000000000000000..1f8eb958845861b3ec79206ef6e7b22e943b4c29 GIT binary patch literal 921 zcmV;K17`e*P)JN6lWa9Kl9GdI3W<01cYE9C1k66SOr6pi(bWeSBgE^WtBpqm;M9x(2F1h z4KZF6!FyahHx?H??ZKZ3Stt}5EOZmI{C|9b?kOkoJ_owI^93qqHM^O|MMIn>vr*Ckm863b0L=>yvAQ!rB+*)oLX%ie{Hqp@f!JE7eF_3xrHb5Bb17DO2s+= zGi3R9c9_zc_p&@(Kah^z$Zxd-lKcZ>f-#=XE^j~Nfl8HMzI71=!G+=|mu`*nVqjtq zzPInO4wMOA9kP#(9wZVy=8+}`3b zhIiUh_8UY&u<&4c&l>KQ2WXx2fS#LED1JcS;1K@Wsywy*T5aI7ml@O2Q8g8yJ-*kbhaLIru=CN8 zo$hA>$$aBGtstm}dyes?{4bfm25|oT1fJ_*S|%IL2CAwegdhwPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4J=eLkUI z(8s#nblVTezR-R_|02+2(FD9S!VAe7jc~efN9gH}p_RPQ*$9oUjx=-6oO@@02E2Rw z=AK9b0F=^&XXSAs38gf4iGTm$^8kAQ(e%Jfsyr5kt4gey{4VkPg2n|fKY4X^ji1+Z zO#Mmi_5AFlFnQbfeF5910NWqU%l~hvQ%aW@Z1aFRISV21FUCK9`ZCyi1(dTq9zQ^u zrj>Ca#Ln@1qkxNx*Y^OR6Ad}sOhP9b>-8GsPpWzEy(ruZVmu=@_14RJ~(((E9=|4IXLGy zI(lB=QL(~w`pjy3nD4f}0A(2)1=zUytJ9a8NjX%z9gK>;egDzOG4&_#{X^)aeRC8l zR+Z9cWNG8h;j!%ldJpKx0|Yr#$&gMowAPiAoQ(&R8yj-Sny0f?xV-vuxRIj} z0<)Qq*~|x#gzq0_V*s*i-UG@VqE0rxaDH|I060E=fiPTEIPxuc>k7EJ`IYT^&vUb* zsX5J=V{6lqc{CnDCmM@IP&qOio?VXEJ$m%$(W6I?9zA;efBXh)01=}Nw>2vO0000< KMNUMnLSTYlVR^Rz literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_product_high.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_product_high.png new file mode 100755 index 0000000000000000000000000000000000000000..8cd4e662e8d7844392def54f00257f8a04289f29 GIT binary patch literal 830 zcmV-E1Ht@>P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4Jsq_LxG6^00O>AL_t(&-tAbsj?+LCJ()+YNeX0HqF5wYp(RxNC3Hwo?N$_2d;yOd z8ajkTL9;#5?icJQY(;~6Cs%UFJ8nMh!#@aa6hIrjLTIrrZ5umP`M zy<8JX0Dw}uaId^hB%zeXHt}!Xe&}HbAU55wn<}qG(N!hZZho8iT>;y4!@lHrJi+sy zpD`X!a5Vpj$>e)>eR_6Y`B<*;JO2TQr1OjB<^MO-DWy&HZt{RSISV21FV^3^|J2)g z1(dTq9NvO4rm`-C*gAe^6mWd}WDNj1)sX$`P3Tl(wOWBZ%C3F?HWrHz1+-FxPR|%A$V`^ zPOYq`vpG2DI6Qn*;ZcdgX!OA8c-ZGQegyI|CX&#phDwx^t6PbaM-?8s4gjZT=NZ?< z#W%e8^`*dVjDb#@H%DPNnlF7;mM+dNgvgFTU7gpdcIL6qZBzk4;DbmO%t|E+aTGh3 zE4%qR9@%#CG!mi<4a%OP__5{xl~;j)&;uDkHG;Q_)*H*ZFHS9fWH zZJn>D7w0qt)qJrNl01k8!V4&AJBO~OCBJ|qe_N!s-d;6OmZ$BP;P9< zBWIpATH)Tar;pd=VWn;u+BCq}d4Y3|Iv$;B931RB@l0p)=BGjO2$z>XvU48I{bh928LoO2EGVQlK=n!07*qo IM6N<$f>zyiqyPW_ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_product_low.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_product_low.png new file mode 100755 index 0000000000000000000000000000000000000000..6698a0881a9d9885c2b31a377893530b2df8002e GIT binary patch literal 827 zcmV-B1H}A^P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4JtHukOWQu00O&7L_t(&-tAYrj?+LCJ)TFdNeX0HP;4Yv&?Z#-2Nck<5=cnU?I+OD z@u)#Uw0yw!Nbm#j7b~$_kVvUeWTmjz^#l2A%xm-shtKRVb0h)oyFrpjw!cvXoto8KjVU$F55n3p_1zrcqZ z-|+I+L;SdyVLTcZexE#kP}sa}{Jwx~Q-JM@=H>r4)G4J+INLm+PR>FI{EPK>?>{+v zuYhuv2ZL)!)3mZKgxEQLZxnEP`g8>VI?<55^(J(pv0N@eE@l5c?>gr50OV33R>cbB z5~45y=Nyc&?A|DhAf+t)?+^OfeT=cfGi6WW?Ci7CxCxF&hXuJ#rZWJ*?OVe_@WH{& zT3Jt~GjPsve0;CMqhf{e_^#FQFwbrL1C(WK6ky}(Cy(y0H|0|8aWE?S^7VV=-tlOd zagRoKpp)j!QK(o|N}rLXjk60OvSUzJ=XIj3dCYSgH9_C^KqL!hrDBCBjI7I**?b+3 z?Ae#Sd@>sQ070-QNS8>$_dRgVt!sM}Mo_V;6`6G~*oyk-XEWjAE&K&2w z@bY;c-}kI}f?&~3A7CN|#0Eh$I+e2!cf|k6E|jX~P4Ak#63M@~&>v2Aeux z$7AaOZMDaYF_vY_WY3tOP3F=xt(ah*$F`cJY1)bj3X>rrM3x1{n6(E8A+j#8j;E}! zZ9I&zb{e64hQjb_En7?XCX$e{+BX;;+diQ4fR;Q!kV};e=|n?oU76%;JfPgzkW1D) zZM4G9^Jgck@~~1j3~d@<%)G!kM;(t&G>(oAt#~HWS@Y8%xrEEhpV_(heJ>kL%`|7m z)=eXGf6#|cH0JZ5GBO*UT}JE<9XfRA(4j+z4jukKeghq#6bNVH0{8#`002ovPDHLk FV1h*wf93!H literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_product_maximum.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_product_maximum.png new file mode 100755 index 0000000000000000000000000000000000000000..4987d5372bea83db8df70bf4fc55a8422f1d2088 GIT binary patch literal 823 zcmV-71IYY|P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4J!xHTT~eU00Os3L_t(&-tAaDkJCU9ec6wUNeX0HqBtZtp(9lHOX!fG;;JjC_yv5_ z(9j{ID`>9gw_HVvoCJxK?jn=IKCjnGD2}o0*f};5*eU!vuh(zAp0{si+`|^Uee-%v zqyYfN*wVetaUu<4EOwdy?)|48_5fi+6UY%h) zp5W#DGbWQC`St15S>u(we%jaen@-QDrCq7(G5L$#puL0{|XAxL=xlaB#0y z*3;P>Qc4^jKdJDT#9%af7G`o;Ex{v2=@ORCINhGMMvx9gnLA zv{fDpAw(WAjvkw!OXRXFtC(Ps$2FT|S=NdPDvpp+DvyE?!r23qQh60v$Fr%h+jxW! z?fefYMktD|Z)EG}-b5N&SL+7majgS74`|5)6nRvMkWDSDwUtiJ#RE1A8}i7Rr;Sp$ z_u~1}^=7kD*9>iIV7On9QlgH>rWQv>hfX}x*}VB~kUYZW<wq(4j+z4jnpl=+NQ+<2OL+C?2^rr3?T7002ovPDHLkV1iTG Bdkz2q literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_product_medium.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_product_medium.png new file mode 100755 index 0000000000000000000000000000000000000000..ae7556d34a9cf2915ae1ed72f3d8b6d855bea669 GIT binary patch literal 832 zcmV-G1Hb%Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4J#JA>vZb?00O{CL_t(&-tAbsj?+LCJ()+YNeX0HqF5wYp(RxNC3Hwo?N$_2d;yOd z8ajkTL9;#5?icJQY(;~6Cs%UFJ8nMh!#@aZzXKKA&YIrrZ5umP`M zy<8JX0Dw}uaIL&fB%zeXHt}!Xe&}HbAU0jFn<}qG(N!hZZho8iT>;y4!M@~pJi+sy zpD`X!a5Vpj$>cju&(1L(PjGs6UinzA@jL$kh@|t2=H>r4)G4J+^ltKiIynm=@GsWi zz5mqPc?FcSJRIJFF{ZLEgxETMXB2RJ{A3LPI@OT<>rLoXW3^g=Jj#Ci{%tH4A;_ab ztV$HfBg9b*&N&!k*}ZWTLrPirJs1wM`xs+|XUe|B$;sD7l_3CN^l-l**Xe8y0Jwke zZXtMY?@q0(r?WXY=QuokRN+yH!f5os>3G=ZHhu*1GA5GHsfJ3FldD^alSdUEyAGgm z&&9q3oIBU{IEtYXRm-Ci<;)WVe)C5lFFTv5FkFH$ z=A1dsdEw>rJVD?)^Mv8D9TT(}vl5p5Kc&kdb3_u1F@)i=mdCEU@U-Cp!b&%9MtN6v zX@hN@uj6s`fVSFW#u&>oX0vBa&?R%mn2HJJd0eZBF{Tw06gERbh%5_?F=r1DLS$WF z9Zy+dH}NpW+W9{qpP?wax|Xe@dlN}WS?wDvk82;$c|c1ZAjqRihIFc-wXRHZE*?;B zY{(;Lo;F(H-m|BV*X3cQZW!7$z}R_#bB;P5ooXB$>^t#HXY=N#LGlQfmp`&|9|V3j zn%Zg3j;)(U=D~0PooXx=VP#~tJll-e9XfRA(4j+z4jnrDfBXi|dMWM^4u7lw0000< KMNUMnLSTY|Qg|l- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_empty.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_empty.png new file mode 100755 index 0000000000000000000000000000000000000000..b13949885bc1173ea6c88b2fce463b00ce1d7501 GIT binary patch literal 832 zcmV-G1Hb%Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4J#!CI~Dx^00O{CL_t(&-tAY*YTG~*J)VcJYA=cqbP+?_6y)MUARo|0)+r>=eLkUI z(8s#nblVTezR-R_|02+2(FD9S!VAe7jc~efN9gH}p_RPQ*$9oUjx=-6oO@@02E2Rw z=AK9b0F=^&XXSAs38gf4iGTm$^8kAQ(e%Jfsyr5kt4gey{4VkPg2n|fKY4X^ji1+Z zO#Mmi_5AFlFnQbfeF5910NWqU%l~hvQ%aW@Z1aFRISV21FUCK9`ZCyi1(dTq9zQ^u zrj>Ca#Ln@1qkxNx*Y^OR6Ad}sOhP9b>-8GsPpWzEy(ruZVmu=@_14RJ~(((E9=|4IXLGy zI(lB=QL(~w`pjy3nD4f}0A(2)1=zUytJ9a8NjX%z9gK>;egDzOG4&_#{X^)aeRC8l zR+Z9cWNG8h;j!%ldJpKx0|Yr#$&gMowAPiAoQ(&R8yj-Sny0f?xV-vuxRIj} z0<)Qq*~|x#gzq0_V*s*i-UG@VqE0rxaDH|I060E=fiPTEIPxuc>k7EJ`IYT^&vUb* zsX5J=V{6lqc{CnDCmM@IP&qOio?VXEJ$m%$(W6I?9zA;efBXh)01=}Nw>2vO0000< KMNUMnLSTZjba-w6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_high.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_high.png new file mode 100755 index 0000000000000000000000000000000000000000..481b313d8456c255d82bb6909af831650bd7bc2b GIT binary patch literal 862 zcmV-k1EKthP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4K4!QMpV-P00Q1gL_t(&-tAbsZWBQiJ)XVeYwQB8R-ylW7F&FfcJ%n|^gl+MiM$C)LR(%5AE+jk#Z*aFbH3A3sESP;w$Yt802S-&k1>n6-c zj>i+6KKqXGc!Hl#zF{)?oje~N9TyJEcKy~L0JF6I(6s#jhBBqpiPlXXP$p+0!oL`Q z|KU?>>lKiXa<6v_aU2)MiD={XTcd#e{g+n&pd$_0UTs208q4Jp+~MTeb#G%j^}!v^ ztW^sI?l8h2gyT36LL|QpgAh{6%yYNbO@1eY$h=dwB@PZgSE>vGfIB^<}W?(U-kk6I`U1`n;Shk0-1S0F88W(gf>sD-j}bt7@^aDm5+ z1Hj?Yal&=5}W9tERmB&H|kwnZy&zPW1giH2E$`p2Q(f~lLruYxDX*7X=tqr zot%va__ur*I@rEvcAWqTz@BEoRk2SxxtmI%JgK|=yY0ESr2T^B;e1M(H3j#j?# z;`!6n*jI_5KL?Hazz_*nx&*IW0jH;D$-VbHH)%~xH)q<`buDwZ*M*KWrc=MrG8>*v oTI>c58Z>Coph1HM4gNp=0E6`^VW0${XaE2J07*qoM6N<$f@x-aF#rGn literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_low.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_low.png new file mode 100755 index 0000000000000000000000000000000000000000..69adfc1ae39b0aab9e56bad1abb6b5354068947c GIT binary patch literal 847 zcmV-V1F-ywP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4K5bOoPe$X00PfRL_t(&-tAXCkJB(1e(H}pv;zu}7_Jgd%(khG4Y9z(H-leD-JBpvcBQ5^em?Dz5WzV2WR zUcY*ABLoKkNU5xE#daY$q*U0Z|C_fTI@kfQbszMiifwT`FZI=n-=_brVC@FzpFBUm z0Dt)t>f;@JznEYc4y@<#(V?|?*Z#W#vPl81Kbn{S-%zELCehjC0abEljNxCjzkC0w zv-1ilM!Da=g)GZT?ToRl`|pebPEMZR0Dwvrcz3l3l`1TkO9)Sxci+E_=`@1ygw7&C~%pVp_ty`#W_xL{10}LI|R0R>`B=U3i-C0H&pzH>13(yOhB? z&sXuddO%a`F+rvy#27PCAcQ!30AtKlfmJ+3 zg>B*?gfvqK|#xNR%z!@OM9AUWsrwuUAyayC3M3t_5;rQqf05BduMjX%0SeyYE z!79OPSHR`v4|DE=z&BS@eVfzQ)^%6rUcU#GDom$Q>B_8mwz*=rXwjlYixw?fv}p1F Z@e4Z!5_^}6&|v@o002ovPDHLkV1fs|g6{wT literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_maximum.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_maximum.png new file mode 100755 index 0000000000000000000000000000000000000000..02fdfbb40716e4a1560f42dcd1d6a347103aa32b GIT binary patch literal 853 zcmV-b1FHOqP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4KE2&kGvWH00PxXL_t(&-tAaDkJCU9eOb?DLQ){h62&0_LL?}~NpzHSS5VU5Pv95u zQA0z^54fI^A{`RV6-d`WibUe>q$?vUg&nWg%29+h{>rhDz)s=UL|%`dy*qE;%%+1a zc>U_-HM0Z&D5Z1visQ@@N@?s8|K{z74)y@F?S`3DaV!W{rC2lhUE=ozV%rV#k<;l6 z^P^Ktr!#zi_7$_)&-8kJbXr<0+xWd-0A^|Zp;`I=4OL2M5}lhopi0g}gnu#q?)}Hk z-YcM(<-y<2pGe+&g7g;^gF0t;!$(7!4ofIF;5ZHr4<7-Df6H+vNdg_$Z;oUpnk{`smNw2#MCmrDs`EP5);#9DwJN~#TrkU=S*b`N3_|O2 zWhP(6BfIuxFPn_o7QpwHCFy#e3&(M+YkL@kP?4(SQIWFd@jSQwEs&L+$&~LeA%w8b zoZ~pTkI(XWo@>qH`^#ob&}7U=SayGxE{n`DO9&z0`^!omGj7Avga?q3Zq|&lu5Qx? zn>t^`W9tD;wZ}pTk!H+f&zPW1=8_~SnP8U3wwfeK(ufI?$q*5xSr9^4djJuoU0@YY zQDHan2qBvJKOmc-AXsf=Yw6z15>l4?2E$|92ecm0kOvU=xRfCsYiO-YCpjArC^k0S zV{4wqTH)gA%kD;wM1=8p2uuKeA`yIEfyM+(0F1HuCFDGy*dgk8;|q@_Pk}MOUnGLz z3N#u1;TR*=g4eEq`TRWH_nzmbM^kf}Gso6#N9O*Z4;^bP7Jli-YsA00000NkvXXu0mjfN(YKB literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_medium.png b/forestry_resources/assets/forestry/textures/blocks/still_tank_resource_medium.png new file mode 100755 index 0000000000000000000000000000000000000000..fd6d420cb9d54d2354bb6ecde87bacb023cb0353 GIT binary patch literal 829 zcmV-D1H$}?P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq` z4KE}YP~dL>00O;9L_t(&-tAYrj?+LCJ)TFdNeW~vQEVhw&?Z#-2Ncw-1QHT-`w55- z;88<^M8yYej|5-9U#zs*f~=G>Yo)N)^#l2A%xm-zP|K0DY0h)oyFrpjw!cvFcro8KjVU$F55n3p_1pFqC3 zhW>IV`@NXVFdhwYF`41{vnPek+s5w;*fs^&zGzq3Z~8Gg0H6~M*;{WyCmPG;668|$-}7!`J`X@H6=GGa zKrSH)BXG{a7|ZUB!U$5z!vFrDpWVk8D?C&7B+kyhIgOj(cyw5h>-1^{0Jwi|SO`8i zxLYgh>D3IJa~vN(s_>{-VLX0lbv(>-8~*@h85;%IxcbS{$LmeGRC^qZioXB&ncXuU z4J(|Z(F5qDd2GoOA2i9)%H9tZI2wtgLx_-)sH|#u$QNQOjf2ZFt)70AZw?H>13(+qA)^ z&e!qSdO%z4F=LEn88g{4CTNqnG)*fenCG#rCTW_sVuHeCNC=T-fiY(70YZqZ3#{WQ zD{LDNW2~JD8?HX^>pP<>jyJ-21+ljizRr zGh^$fk-0zULnj*Zc~BXd4bLtkc83lfI&|pJp+kob{~x~r3P2PHeszoo00000NkvXX Hu0mjfsq=7M literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/stump.png b/forestry_resources/assets/forestry/textures/blocks/stump.png new file mode 100755 index 0000000000000000000000000000000000000000..7755f321a74de9a80edb72c7b7beac8192c743c5 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFckG8l~F UEw)CztpOS5>FVdQ&MBb@0Qnqc6aWAK literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/tradestation.0.png b/forestry_resources/assets/forestry/textures/blocks/tradestation.0.png new file mode 100755 index 0000000000000000000000000000000000000000..053849719b269c2f04a9c0c41f936906d986dbac GIT binary patch literal 716 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>p2b|_FYcXE%P7gc{t$Du&W+BLHFW=!L)xW-!v z&9|cKZ-&=g|NsAgoWnISpl2DAyxm>AoCTw5@TLx8%#UVjCuW5A>?e@H@tT zBHJjC@4@5C#b<8Ki;JnKeY`8?)FK#IZ0z|ct7z+BhJAjHtn%GAKh)L7fV$jZP# z14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>4wh?TyH~8`1SQqZ)2$SUOt;PO%D_ zViPjWA#$cu^el%6AetFmc|*YwsD~ zd`r*4+c9#MYwTQ?n7K|-vz?=7IRV|1FwZ%5w!V|EzLSrUYk-lfzk#!_fs?O+v!A73 zot1yRg>S97PmP&(_5c6>9Ydy01O^{tlD9k1nfDDCfgH{PkH}&M25un`X1sK_?hjD# zfv1aOh{R>xb1%aV83?pJTqx=h?c(9tnXvGh0*4mMl(Vg_jz@VXoPG2+zWwr{&+n_x z&z!@sV8WtRuN*CeRA9UzgXS|H-)-+5yIM;S#apm(XrMwKL z$@2^qJrrHfepZ?{Meofffr+P7OV?X`zrW*Lc=o1y8CRB0soSyh>86`m+pRP>E<7#& z&VQDH?T^Rzjn^kv+sLuK;D4jY&rn?@*JxH&)|fd>IgXr^QiEBhjN@7W>RdP`( zkYX@0Ff`INFxNFQ2r)FYGBvO=HP$vTvNABxcybh|9!W!PeoAIqB}jv@u7Q!Rk!gsL zk(IHzm5Hggfgw;sjlcI+pawyZ4QZJ14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>1`P}**a)SMBOc2doPE`nR?E}x{ie!R+(y6nd(+q>eksIl{XBWeVw9b zshUJ6=mkd9-Z1v4(6RG$i<@T=ILRh>s$!r&FF2Cpscu{$@r9iL-k&%XjEL5-GPeEc$=o zO38r@9v^=!QDB@X%RJ}#ne!n{iob=JE9O3U`&YTkZtG&}5C=oYOFvfCmWv!)cjm$K z?N8^#ZQgeNKj+~+I`tL?az$_Xv|NCmRV{IiC`m~yNwrEYN(E93Mh1pPx(4RDMg}2< zhE}EqR;I?<21Zr}1{zO}0@WjF$jwj5OsfQGFxE9N(ls&-F*33;Hn%b{)iy8$YN+w| p-U`$p2(lq9Gbc4KF*nt!1jt}8i?=))QfdY=&ePS;Wt~$(69BEF7$^V$ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/tradestation.3.png b/forestry_resources/assets/forestry/textures/blocks/tradestation.3.png new file mode 100755 index 0000000000000000000000000000000000000000..a18c0460eb4dd0cbe6ef5ca5ddeff95fd2f3fbef GIT binary patch literal 802 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>_NXxRsxojb zHF7W4cPY_xF4lK0HgqeCZ@v}VbSt9vMpXUH(5f4ebvK-%XE{X7bc>(o95dS?a;8K0 zOl@0tyYT7KYWDKlZcb6NdinV~I62!nI6|tf*#u9ORIwG6(c|J1lTmk?!ND<;lXJa- zg0@3JP{lRtpefR7j-t{!j#0C;?D7K3ui1spkXCcx;uGcM6>*B5EwDwJZ-Y2%373wY zM{vb;IZbD2bw}BiYBDQSrOvA8Ie2T^=ex$vbBvtj7&+6x*;mJ*Kt|nBUdu&B!`V4{ zj;w~0u%wo#jINM`mXL%dCy%h4rV|&hh?#e_tcJ6NZ>@9e9G956hAw{A0S!8~?gmai zI(D8W?t!|Fg_eGGCZ3i5|Nr-p;64WoKE@<(cbC|?_YD|<9L@rd$YKTtZXpn6ymYtj z4^Z%#r;B5V#AVeBna0eH0u2x6ojr0aVfWD^D(mJ7=p@E=x(XyWPw4pl?SFmyyiavC zt9Gs4#n{5pvR)yzP>08H%CXRs<_oVp2@x=G@wihWnSN@8sz^xcwSucrxq0`T3lj@9 z`*LNchfDGDug-pb(k(~$PLDuf`-MBV{L0_t?b=>{AuBQ3;j_TyGcs3S{#bJPU@&7k z*GHRILa`rQu5<1PnelznnV6+_Oq)Y0F26s%y}bFL!SebY@{!h3MYcu!a&o;V|2X8G zur&;s*STtsV0=g1eTP%!&+TqSz4m{8NBpq)d^xXk{~tX6&OiTx`~?^9^(814Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>>``n8usV(X*Xn=D5Vpaf_el7&+4+Vy0c#bcgU+ z+P3b|4L6;lW*NGb8M&A1Iu&U<6zDq_+lEdz^RA9>x#bu+%PD%cL-EuHPdW?BVJu@9Z8ZsDZkSm+ov%O+&1hJ}-sU7kba zOsD8swjtBCZQQkNbDd*m>pB*?#Labznr$7>VBqX)Y zbzS}y%0Lchfk$L90|U1Z2s2)~TlWVjxWm)MF+}3B>G|t?hYWZe0v~T#>T^9ngY{I~ zhVS=2{FiSHeqiTvYND|R4+#9{t-SA{j+ifn2J`a!kCHKHUXu_Vlzt^7#doc z8d#YcYa19@85n3hISN#dq#-vyB{QuOq`_F%z)07~G{nfr%Glh>#8lhB5U8QX-+L=i ngCNL;w9K5;yu{p8s}dlC!8G1tgXr&{Amcn;{an^LB{Ts5eADQp literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/tradestation.7.png b/forestry_resources/assets/forestry/textures/blocks/tradestation.7.png new file mode 100755 index 0000000000000000000000000000000000000000..e00bad9703a23731197b27df35982a987fb5b172 GIT binary patch literal 802 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>B2F`w3c6rV*v#o=tiYr+eEZz3H#)(`d?aqUt-NuhuZ3gkaXA&2AOGebmid1A ze(AkG{0tTiJ0<%Q9{lod>`$G3*kFr8jnvwJoT-M>lqbYLzGx+CruTp0hK)OyZaeB1 z=n&&{A|-jHGRv!X({w|=Rcu}Mn!{#)y@LX0#p0S9E(;8;t=d%9N)}zpQT%W@=5~`+ za_cWkroAt=9Q3@Zn!KpARlL_vd|mKbi`|;{zWw@p@NTWR!i8TCKYH4H?=d_)ku^R$ zb=8zU^`KMJSKj?;HGA*g`ZLex$9ErnAwAvtB>$gB>^A*A{~4|(%DMD1)b0X$Shd78 zq9i4;B-JXpC>2OC7#SEE=^B{p8X1Hb8d{keSeY7Y8yHy`7-&2>3RI7zAvZrIGp!P& z!C2S8NY}_T#K_3X*xbs*RNKH1sG-K+dn-_b5XgqK%$(G`#N1S?5+H-YG~UqQ;R$PP Oka?c2elF{r5}E)D039p< literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.acacia.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.acacia.png new file mode 100755 index 0000000000000000000000000000000000000000..7afccacb9ce04d0ae859aa733ada55225062d761 GIT binary patch literal 673 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a> zJu53T)Ul#6eA?91h;Wyp;=q!U;Np^?mgcxQv$Mm)oQjG9s;VLb18iqZPoFs>W7f>f zganVEAp5-BfWkumuu#X45Qms(_ksfdh;Zk~2-mW*(8{Wa^77D$6B1@jOUuvqn=~;o zE7Lc?-=?}cYU-4fDU*|f0_~Tx4`iP?HdJ^$_UH z44!Rw>Hq&-yY|j5W|YWp$(d^AG3f?pPWijF!Bqms`c1YOv_{TUT;%QHF5wWjZl;FR z^d8~mtqU~zTx6~GiK( z{Z87gJGHuOLCOR6y{ELhHqBR?QE+zm0Xkxq!^4042^UR4Rno6LJWY5YH00)| zWTsVuG#Kj|80i|Bh8O`gm|K~cY8w~=HPrZfZv|>l2HB97nUk8An44-<0%R~0B&Mh8 eRq7j>#m0k~6(DBzjidsgat2RVKbLh*2~7Y3fb_8d literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.balsa.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.balsa.png new file mode 100755 index 0000000000000000000000000000000000000000..126b67df96dcaf4d8671cf10e09ebdf95ea3b32b GIT binary patch literal 1317 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.chestnut.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.chestnut.png new file mode 100755 index 0000000000000000000000000000000000000000..bf03579445fb52a8ab82bd8775c4531c60123f74 GIT binary patch literal 1062 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG?e4FMGaVsV=Fpl6YEDnrA?_wrRi{F82NYROsclUOik zO1p@(2bbT0i4g_d52W5iq?x_o*3hfiN- zY!bP$XunmGH~JLqs`fp1 zeqWNwzQqq&L}t2NpJg=d#oD7<)eip0g2P^$-kR`*UD0)!$7R!Psw;R7ekeMUVR7ia z_>q3W#MS;6F64CagnBHQ!sh=y_|zFCZJ}%3rt8uln)o~lJ@(?T==!*N-$^+iWPK+d z(YUR2^O=X@gi_s`)41092yiY-{B-+$e#dpgZr5W+Pd_iI^1ZiDa^c4VMK`9fzD;0H z>CM@CJEXKV`?kclw&sI!^7rmbMWskKmJwbVjWqnx)!{Yg31&9}Fl zIIa7eot?$8!61vrXPJ5MpRoS+pSH^)jivQh7Jay@R`kDsU%1uCH|OQYZ~fnwczSKQ zm*6>j^=nPX(+@9y5z{ouyX=;y6(EqxY1F6m?BtxH-A@xP9KFDn=d760`#w@9-O}+v zapm8M3uGs`OYW@|KX0gUnkmzI)-I;wpEI_Jyft|6=Fyxe?Xp8+k=s(IPP?LYh`%=M zbjM+F=0{sxynCkvHEP^=Z?1W2%H6mQ@eIjMPxxv5qqKn6oWVtT4x erM{tAY&@7*0b*v~NGbp-XYh3Ob6Mw<&;$St9Lrh& literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.citrus.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.citrus.png new file mode 100755 index 0000000000000000000000000000000000000000..f465f4ce95ef69219d12b04931b4016b392c1c4f GIT binary patch literal 1338 zcmY*YXOt6V6#bT>6cI!a1eGRRNKYnhlF3XaQ zYs^UfZ8uF!=rF1tj0OSNyng&qZM3duml-h%!17iAR;>Zxh~8SYAArSH01gxZfHwdz zt+{b)+z-HrgE3Abt70e>@mA!JLOK&6M^R$5G$)1ws?5k7T1!&{DwCwGGHor(WIaXp zri0}~up$uxW>ZBx&7<{vJWBc`9#I8vHi`|V=mc))FHlQsVo4$@qE`-CMaor zaht>ud6_F^>CTK$&xWfBq@o0y1vba~nkrEj+{FamNQE^qpwLb=ibpWF%mibsPfMVc z1m2ltOJbm@aV6eWkr0LRWWynqgpy$|Pk1vTEipt&AQ;$~lkiH0QCM#yNi9_AzErT1 z2&kl86i|tFC&MsL!-{}M35Y?_tPm`vDVcUDl&dDA{W-EHNB5>fQOr$y+cOb=GK_IJ zB-1|9X_N?u5VYnwq>*MbJW>)7m9^!g{k5*Oz$r?PbEQMZ zM%-7R9V+9DB4#D*6X}4@(H3W10%p>pJ_)zP(Y9jPQI31kv_)eb-C0y3&1D&jVMZ=! zOL`1R%Du8ec1y5=nq#;*&pC3GSrgnc(IJLR#h6bap&aYxU_*v+4m6bhT(H1+YCNV! z>?IC5cI?=ZecR^h_s~*`(8S-qa=oUDu}vnu2!QdEhpT1B-gA!X12b77C{5qlGO6Y8 zKe`+-a@6SKjvq62-1rkFoH!9oI%)FBQ>LCWZThJ*W}bHX8MDCbIdkWoIe$uPTYJX> zgVAIL7OTzffSfM3$J+w?{0Io3SP%~pBt3E?jrf#Xz{^(#zIg ze#MnnU46~9*KN4|25{rXn{K}4*4u8sdE&{Z zo(5Z=dG@*IUwHAQmtT4Hwb!@3@g{id?d|Wp``-H>?AW<$_lF1TUC|KiK9 zzW(Oh@AiGa{|9j3;E#vq{B(Ht&%gZo+wXt;`4`kbw6A^ppWHsQt9{{m0O BsnP%d literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.ebony.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.ebony.png new file mode 100755 index 0000000000000000000000000000000000000000..80d311894100d723a1cb6776464a19667b21f8cb GIT binary patch literal 673 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>=Xz*Xy6tJ+-e{)aR*}36$+5Ynz{Fb$cR;GEKniX<-cIcTo zVV%VR)#=_dYJ%q1`_^Xp)nxiKvL>4nJa0`JjaqnX57_sf((c+cUu{Og>8Zzlq~BSs+$g|vbmq)67IqU#zwo#17tGq{ z9OMr4qH2k2L`h0wNvc(HQ7VvPFfuSS(ls>DH8Ke?G_o=_u`)5yHZZa>FlZBH%tg_V zo1c=IRteHztZQJTYh)T?1k_+|Wn!vrUc6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.giganteum.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.giganteum.png new file mode 100755 index 0000000000000000000000000000000000000000..16ee0154f8474761dd815e0eeb0d5108d966bec2 GIT binary patch literal 732 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 abt%jL*Y*sz#Y0lnkb{svj_mRZgZ~0}rpt{0 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.mahogany.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.mahogany.png new file mode 100755 index 0000000000000000000000000000000000000000..40d700c965c629bed0ddaa9321491e0401ad2366 GIT binary patch literal 1320 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.papaya.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.papaya.png new file mode 100755 index 0000000000000000000000000000000000000000..587abaa391afca2bd18c6c18a705e9d5275f0355 GIT binary patch literal 1359 zcmY+Dd05hS9LK+|TBm^*D57!*q6PwCCUYK%6BHCLypj7-5D`I85J6E<#52viX|SP>-al^MJY0FL>#u822486#yE@&K?B0dRBx@Bq4U+yS783cy_v z0L*a!kou{!1t|cm1AK0A)})0tq{4V5=#e`7oF%SX7NumvDl`4XSwZSOftvJfTK0BZ zS=fM@c%(CJ`G9c2!5r7d^h+`04GH6o6jMIDjuW8F3Dj^A#ypfUH>8ml*djpqRD?x$ z`sG8SNh@QtKDJYWaY+ca@+dPexS1bpwJ}3=_{rvk{kEi8 z3&X1-cxAXjF}6<>)hR{0L@2K;YOJ2P*qM5Igg0$XoifrU4Lf|A7)vQi#|vx{gnE^v zi8}IB!;UF4rB4w#Adi~T$DQ(UF3c6$CDEge2~%czdo|iz5?ap<)NtS?0eVDBUUa1_ zb*JyBB-2#*Ad2 zEMh=`p3sp`dsuxc!h|_-P)~Ksi5?}XqY`Z^2sG!1)U#m@F>&6*n{j3K%5m-*#7qFn*-dT-nDMXm^k$P^Zm=#dP4pJ3_nM#l&y4X|R>>G=!u||eZ zPnG8cRI%V9R)8!MR-Y4W;2{lpC__QGFms!l7tk#u>^C#c4|A^{(d=tU>rj$(1;|<+ zQq2xhvf#R0q=6S|=7+YIN4kWO?Nz8=DQ3n%Io_4FJTG)9HQXWlB1L+xiGFe%VWwSXsxm;deKHwJ=78REWO3TVCDyyo6 zH9#bmNM&+`Ql-|^)@gP1K;K|!G&Y&c%@%7*tIgg99PLh5N2j~1yT{Yp=k51_fx)5S zk19S!QB4G=NAqfJoLnqhmR~CU3v;UeeC#&XHK3vedgJ-&z(E}{0rd4 zmoB_~@zN`=F2DBro9}<{;YYV_e+)kP^s~>u`0}f3U*GxW z?zi84{{y)9<4^a0{^i%-e*fdo2Y;>n{ZCL*Tgi&M-~_Zgf-$SiC=(myOsPQ*37|s{ zC)228I-{6IXYOP$8H{);ok^v-L;SS=1GM!rwZgIn>?Bj^WO`yT9RiY=jKp{<4FX#8 zb5BA5erQJCe3Zu&A2zCH))dQCcR11rYY$z zbVFMasiI7kAu0}VD=Kb55eM#pI8a=OXub76|9Ic$dA{@h&Ue1|oNt5CP`zN@vUvc2 z1!|SNhSEjTHD?CZi)ahYl+45>dII;CPgSD_prrtSTo(YBsH5Cj0Frb7 z&Y=MCw*Zh&Y&&8S05Ag>b+956^bBN(h)LZWcJ;-5BqR(Om7QUaOTxw>c~o42aElv+ zG(;^)p%xrc^!toXnP6kRb0gtvGD`e*IOEWD;5ILRZIieJ<*k*|R%T3Mt%%oPgUljs zFKTd#xTC0M0Jn_Ts&alCp%*%36@;X06k>Q(!d6u8Wv|hcu8z5_R=FS>^mtABUUOBy zOPeu^Nkl(j6JgcDsFK$c#ZawueJntT3+=4J8VR>n!pq?93=wXDr9DsKstz(he zwh)49WIb*uq!kYLw8ypFCM~@W)B80-!eJi5txh3lN3$<$5~cmfgiG1&P$L@I_LSRI z#q3Ii;u=nix{OfqQbut*?%YpUj3WM)G(Kdnj@yl?8u?aKq2aM6Vs2ExOuL{Ur1VS5 z>)rN@-!VYe?1u2d^}Oz(JcSuH)9(pcb!X_olw? z5Q3SsgQy`H#Nu{Se_Ipjv1obBq?~Ez6vq%#!VbYztd@ueg;ayh#L;b?F|)cij$7rT zrT{Xb=k%gRNFnZ!mH9;UfP&j(QJOhLgKeZE<;VzJ zS>9Gz)F5Lv8l`c&!LQ^Q1gxR9o?a5rEG>-z)s^Xw2Ds3SaBt*+h;*_ zvZ%Hq2}=>BU_6ay(tcL<+}~a(e)Zd42vs9UctTha=I37$D+_MlzXdN;kJ;TC;8IL9V@{ zv#YzOw{OG7{(-@vVK6efY4h0l#BEz{-+ITk$vf`?+wZ<-$Ie~5_w2p*zWev>A3p#N zK5*#4haNus$fJ)ve&pyAPd){ne&*Tdo`2!ki!Z%={FPT7JHef`bZZ_j=A{SQBa^FRH3;g?^3`~8oLe_s0Q^56de%liEC zeZF1P?$(eB8|lZ$0N!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG?e4)*croWf%5e#vBl6L-m7 zwplDmv$u7ZUH{Gc+wgV#t)qJCZ<8*WWG+n-%~-;EWl~A2jOUvlIqxf{#Mk{>*&*(2 zz*Cji$bP$<26EntSO?GSicV z{fW11Ht~pTKV;Ftxk+{Tf6q+^8y<@vUlAx^Afx}`QPbD5>3dFWxEAxKYNmy^;LNr- ziy0da#HZD^!CIi&))%_wB_^&8M4Azp+!Bvv!3=ZkNTe31UpVroI}h z1<&udcaf6(m({t7d;ZZJznx2r{f|%i!nAUkgr`%=vyc==!F!X$EthCt$Q4lbM;)%{4D z{`sUxys_o$`35suO?bPT&+ki#4ZcxXc4Ag=+H1$z*TVY$irZhx%5TtF{Pydc>Cs{q z3!OIKO|GU!hwi?eV{*<@x&PpYS(QqG?voqh&-8lT%k*A&Q%u39@0x3)*jHa%^!=*hYpd`!)CEc@(S!_Gg z*_Dfa*!lDItvog3X*LRpYcdvmwL<(+d5?OJ@5L%IG6El{+E3v#Z$!P55E#`q=S`*@LFJ=Q7v(eC`m~yNwrEYN(E93Mh1pPx`qb2 zMkXPKMpniqRwgFe21Zr}25q8@xhNWP^HVa@DnS~Ibq$PkjZ8y~fEvuLOiZ;641pSI z{JpmVH7J8@NXyJg%}dNpwJHHJ7zz^8Q}rtK4b5WX!ORK}Gy6tT0Z=)Er>mdKI;Vst E0CM@&4gdfE literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.poplar.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.poplar.png new file mode 100755 index 0000000000000000000000000000000000000000..6fff2d17f1af52b1198b63a35a0bd7537c7f9ebc GIT binary patch literal 1356 zcmY+DcT|&C7{)J-)=}%I7Am%&2xSG55LOV8RX~Oj0-}Jj0s^8G5yT=zhN4sv6-Z0ZmqR;*gdSHAN{X?y!UzDd!FBU&%NioX9)>Wt5$4W0RUJP z6CII==$eIEwir2GQLB>>S&|W@_b0l??B8~Y)zqWxpz7LsHC^qJbKNS6 zDbYbN38)ib@aB%*nqna75W^RzCrBUT=$|)6FafK#rk<18TOJBR- zJZy#-%5IMU2XvqlKG}nGEJb7%i_H?1S!{f0Fg>yqmF@Ela8%xaDR5IO)WjR*RS6D?)+gM>Ki;R|YI(PUESnolt01_AY>CUp zM`!zzp)1m94LrmNCU`k`+IjDA2}!|5WNuF{PasP!!qx%Jl!hX1%cv!`a+`-AkIAfJ zfeF^mXe!%}kWOZ%=7lHa1iSlfcEUL1)$QS1VfnZc8iAElTE(P-Yl3BCQrUz|Xcb(B z&-)VGZBc8Tz3l=M-TZdB6gK4W#)YC$iP)+Tjfw{hT)Mi4rtG3=Iy+RYExe|jnzZbS z}H!> zrAn_7&Tk0U~GKi=H#uZ>6zKN+w*ts-UIg^Jbd){$=6T6dG_t| z@4o-xNATjOpMUxFx8Dc<`17y7U;gvz^#-BrBifRq2iK%Q*0#J-%RzX0uC>IEaZ%h=9T}YySl> Ca*CJ$ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.sequoia.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.sequoia.png new file mode 100755 index 0000000000000000000000000000000000000000..c52bb59b8ffdb8b0eff51699867f6726d0e16b82 GIT binary patch literal 1335 zcmY+Dd0f(G9LFD5ZIyGiwpOcE&d!x6AgIG5F;o-}ZcRWy4nYz@AyObg^R`S;F%L34 z$P5*dJR^_N4!d-<&b3x+cC34=?bU1T=lfoIO3VAs*4l3AtcUPu1?eSe4bE&1_`&w~M06qdi-bvG#Og1;y8{pbls_ zPA#iPMyQDLsAmP-JW@GXopZsUY37BRxgkBu_-Zn|TS~B|#T^n5x@8n+PI8wt&cY9= zp}>rEv@>7we6-`1x$q!6sFlC1O%T?`3o#|4tx}?0P8u(jkLlSahF>ie-Yme~Y%O_x z&VH}0*pw7#VqzNEp(fVWVw^|6I;n{lVG)MkFct4Mn;gC8)^|oOjRl-_sZ-t z(%r-5C-g#_l+cjqYlPk+PxR`_@UxSab`jp17IQe2FkT=!Q%pd~^-pCB_qOA9_FE_{km0vy0^qu2wp^y}?0ye5tc=8AsmrHb7P~zE z2Z|rfnLF>}Pv$RJ==!PKXN$n%&zF4h<GLJ71rijF;k{xM4nl6)PWGa+9RlBmX)fz3>oukv|=IzNZC@d;2DJ|Oz_Lc9i zkW|tQRn;}d+5>g0r|#b8|~;o8@r(5zuke+S%2;-ey16<2c^i*AE5;hfX+8 z4v&nEojN@}apo*IcYgB1#Y>m3OillA_1cdk*TIdOw{GA0>F&?>e!2hP*N4B&fJcv? zJpKLI^A|7uUol?4`Qy**;H+q=&xtG0-K|%IB`Ek@g#g3L5I_Qu(7|B{I1GuRB9Is# z6b6Ob0!L!t@Pef-Y5xP#()nUx)-2!ygCk)`G!+Q}ei#&b3mgFfnmB?30@lt>5Q=vQ pq}((CMgbWh})%C?$jh5dsl{6cHm$ z!GdB##exOJf}nzky^9sWf&~jUM1}tzjyUn3KfZVGedoL9JNG-^rq-6ih+&~&0Duvt zVs4U;qxx&eK>uao$jLqon&&lp0PNi|{A~MRU*jFcNzDMPq5JP)IKWa^#?^~ihl*hgMc8qu%aj61 zmX5GAmPsdEOB1*#&ytEraum)Gk$PJ#cqUKdp)J3qMmo^p18Y)XhYYbI{bW|6aQZA`N zMn}A+(27L!EY8r8Xf&j&Y`vq)0tp#Bo3~wxww@ z;UwggjY?Uwx#&glS~6Bg6Lp@WrX3Z-Yjl-%Z87KRw!xVi<2kaIgz2OvFn(krX$Y>x zQB=g#nT*5a)4Zl~nnda{?zx(m6msdfDw5GiSca^`Mbk-vz-mlH=UgtE7V7GPD#YzL zmrY6at|AFELt?T(8;JB=)R56lgN-f%4m$7+JX(WQK%wVX6HE}zkw3WMV!6?EEa=!!79)*?l!hQj*QPDjKy=hSJjc@ zYtH%&;Zn}41dmpYsyg$JF9!@9H2A#phYTGy{DKh|js&Adj~P2|e03mL6AIV*Ck60m zj36nRVL4t9p(F!EMVfBJ&4gtq9XFK*^hbUlLf_yX=bP16HhDunJtc`l>Zo_g%Ag z-TDnfH(q<)Cb0SX8*aR5%gwiJy>+>?;kMiF0C)CnyX)?Iw%>c-{SWNe@!&%bgGY8g z`q-|=pLp`A-B0gH?S1B1@Z7%r&+j_$!oe3`dij-CUwi!x@a9{6Z@=^Idxzft;KPqT z4t%l|9RBpk(a%2r;>%-Sef`b1$G`g?{P3f8;-{Z~`SrJxzn}W!&%aJ%UA_A&r%}n@ z9o3tk);qVox6|%e(&+<0esHKN5a|^a*_v+ax}YFiQ8tdR>i(ahd-2@)T`T(y8dMNO zMg{o>)7A|^QGLVe3FUphf#{#mHGg5}qW11iyVob6r+r?hv{F{%GiLoqSM<{b$L93- O?Vyxz$?eX}Ui&Yj1XDZ! literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.walnut.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.walnut.png new file mode 100755 index 0000000000000000000000000000000000000000..2731313ceacb81e207ffdde0bc8542be3d3622f9 GIT binary patch literal 1359 zcmY+DcT`hn7{))U)?G(ywc258wOWgY2x_BkMWJlOh>Adf07(Rr5Hd+__TnbFH{&KD zi;xgDTBe|25X9nY)w=3#wbjN-zDdf4uMWJl}bL=R4nf&S%I-PnbDv;WPli z%%sFPGOn}7Ysv(?FOQtH9hZrW*tA#xx-8S5P$%JeaZw^U4FJh90F+t)9^*&KdjJRs z0NgJCfaC^XKBs12+eQE;fQ;14c#A`Zc~l0g*yY#TT{53v9jwFw+xM zbhRRNKBdJbbUS63-(W!CNN^c;o(M)M_De+afMW8Mq0df5sL8# z`f7Plsn1u1IpkKm9FkBEheH;$f+we*Jke2IEoHFDN(1Z8<>B@wL}Oso)hgU|w)1BX zxm>C$n2*`S{XJeI%v2hgJ>4EpjfyMDMVwG~qphPEQRt`vzeIv?Y-a9(a8RnE!6?h? zla>oIE2LSY{ef%O2Q5yn8ZN;cywPDFW+|%)$V((eO%0}|CR1{1lw8HY?BZPoTR4^3 zC&Qs?pQNZPl_Sh8DNDb5Ye=J_8WC>7?l=)YKj4+qi<7C;lzdux5_zLq%c>IQ(b;K< zMXdtG|Yr`C}u2w@v z29aL2Bh-Sqd|HKudF*IQcc;T_gANWgkDThPZ?lAtwE8>!CtQsg#-}8 zfQk&3%E7^4AgIl_}F)2-S+(16+%s9WFGj9tDs6bu+)L@;o4 zzfi_d=sAIaE*Q{Rtzxad0!Bmzl<%)M>CGZf2yJe4^z_uaJ?h#z*kXsq#>PtK%$$mU zl8C~Tgt)QB$qz^IFqM<(wO%kA;{ zYW%ez5UdN;H#9aix3sqH-S<&D=;-X~?%Chlci>?Ez@hNqVK6j&WaQ|_qsNY)IC<)m zPfwo#XFof4{=&sepI^Rm_1g6tH@^U1-n#wO*LUuI^XJ?I%8N_r;&EV2B!L)7jL9V8z&cWN%t}HO4oJ7A^y0vh@f+wROd6ZY nqLKKx0URoWwo1G@YAq%IKU+C&%dQl1@Ntk7pB~q~xj_9d++=Rk literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/bark.wenge.png b/forestry_resources/assets/forestry/textures/blocks/wood/bark.wenge.png new file mode 100755 index 0000000000000000000000000000000000000000..5116eb5c91cde406e99063190dd16a74f27c5e3d GIT binary patch literal 1356 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 F69COW``Q2i literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.balsa.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.balsa.png new file mode 100755 index 0000000000000000000000000000000000000000..c0b5e53bc94f9ac2716f1a12e8eaae89fc497777 GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>WZBt`a$=3C&S1g&oZsn5QTQ~0AvH9r!-K&=` z+PHeztp1M8>sKvXGq>Eak7aanf4?Wn^BJk806FHE~| zE@w-jcU8l|1eyE)-v%s`e!f}xub-2E=+3}U&MNKMyA^IM$~rD2{I1#T?LE0S1tzaH z3g3INIhJzDnjD7Sc z_iy39hs(aE{@lV`_qub6{oNC;%>iG9|1kyx@V#5z@B0tv7u6Eih?11Vl2ohYqEsNo zU}Ruuq-$uPYh)5)Xk=w14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>$w|4ohmCCoN0uU!2^tAYuBdtQo7b=agGbS)N`qF|2k{c-`cPvYx=I{?OK0 z2@TVtCofBDoE|fEMaImvxzko=&RUn(mSsP2X-f5ku%;QYGuPzI*-)@-XGQ(gsGj-p ztC~H!=BHHlh0I=`Kd;heVU_LN3hRpA;JPW16PBcO&5d1F@AUuw|9i$SJ_4P`nB?v5 zVzBOx?h_z~v%n*=n1O*?2!t6g-L3lr6g=SR;us=vS$4whsKW+4&B=!^OuKL{XG@`X zRl~sqnfw3W1}u|)zFGONpOb*-&cIO4D(%_36>cobIxZyquG#GEJ-IgpCa*RM-+Qq+ zoLA1hxo!C+DDYr~Z-nUR)qt6Z(C+blQinRBB$^@X%9=Lg#w zDUXwrryFa&Z`+u9?D#dKH>ZoY(tLMB|14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>4+%}>sAIyK+9P(bk5Z2Q$c`fGX(*7g}LZPQ%YrMq>S z<%WqSM`zh>oMd`@j>DOSt|#U?o?YY?Dkyk(hRv#Oy-kzNPA_mdzr^F_x}fzFjQ375 zYfw?nOevB_g7QfvdxA-|w9Nni|L1M}x&i1s#w2fd z7lU2BR0px^;d7sn8Z%d!)0M;$icX-+<7 zs~Qd_$lU+`Hei|b^UcbC{hS0ucLs)XR%y@Pt#D&e)^Q=>cg<#R@5#L>FnP66_}+`n z;k14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>lizor8J`aIuhv%Kam4BWIadiAQ1j%;u$;jIlu5Pp3uxHMV>eLs~x||apY3jNYv3+RLK*Y^kH7#jl?8UXjQ5T-aQ-sZXRPGWOA*+`onY z9xnTu`g03&-RsUN_IFRXHV1qa{>K;)!1r!-zwbYwUsOw6BT7;dOH!?pi&B9UgOP!u zk*=YEu8~QIp^=rbiIs_owt{vX42FWl^i;h{eM7U@crdd9#LT{tQ~*@Y;OXk; Jvd$@?2>=$b|Ih#c literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.citrus.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.citrus.png new file mode 100755 index 0000000000000000000000000000000000000000..93dc75d4e5ab0415765e1ed21014bb16f026cc0b GIT binary patch literal 591 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>pCPF zIwhvem+`aH?Vc(%W3kM_wQ|k95|s&VW%Xjy7RsarT4#mWrUqEGO_2Qm|9|`1>OP>Q zj7i?^E=sYfF>8Pv&H|6fVg?3oArNM~bhqvgP;ir{i(`nyW!VXD%a|NFoEx)#dX&Gs zF>}||t*?IXU()ka(l3ueN$eTFVB#cZdHc?*HZfPv$bQflioN#dT-m8h{YD$V&*E`d zs2uykTr7h1%-M-?D!Cip>}6W^Hg`=`oXBmBWVcg4Hn&KAYU@x_Tk)bjq8n zMc&f7Gydt`{j_#fueGO$LXOwPzkwI-v?cT8T)1*`)AN|5^KX{dt@FKV`{ifPj*7bx zy6l#pVmrJ)bLv+d<@&tlH;XaQ^{OSV5hW>!C8<`)MX5lF!N|bSNY~In*T^Kq(8$Wz z#LC1(+rY@mz@SZ(F&9NcZhlH;S|vz>v95uUu90bo5m1A14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>jp#%H5u^aEZQL;t!cuf zwdmgeNop^?EuNYC&Cs`V#)|`Iru^_Yt0@@8Vzu9;z^`Y{*G08~#~D8LZj5sHqhS#{ zk@wN8E`>XsdmWFTWSvl_9x@>{?oXuCqa(ao2W&*1zsvizA)+ZYLVsS+-Q->g-o8tl zuX5cL)Qql>s1um|fh%dF)$Wvy^`}+^CWXqL{?fPX;-(UZ&Xd7*cP?)FK#IZ0z|ct7&_LJ7B*f6j%Gkup#6;V`$jZQ=O_VVg zMMG|WN@iLmNQ1Gifsw9}X^0U}gSnN7skVV3P(zKs_g0_=WsnVNnK`L>iMgp(B|rv4 jL1KEUUZuXFS!_I*Spi~Z-$*I|DrfL?^>bP0l+XkKAY#0s literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.giganteum.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.giganteum.png new file mode 100755 index 0000000000000000000000000000000000000000..ce257788b64d47fd89af4e88a1072498812a2319 GIT binary patch literal 622 zcmV-!0+IcRP)b zY$ip&V>KU7tNBH;oz9(dV6DZiXo{X;4j~%DCzn4&WVTrIx67@d*5n5g83ftJQTzV{GLq zMIpparvMN`G}f%PL1lBx59s}u>lcr!BoK)oPMZ9&0RX*xum8{LA96VNwYMC&d;kCd07*qo IM6N<$f*ElQg#Z8m literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.greenheart.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.greenheart.png new file mode 100755 index 0000000000000000000000000000000000000000..2a18661ff284347d3dabef9b7f5199cd37d633c3 GIT binary patch literal 643 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>m&+uza3-8N|=*!QJat!Uxaj#79s7my#N^&ZRb}NtbZ_Mzn zO$q7B_Nhw^>&cCpP#D&m7d5dc($_kuGs~?a-nT9-vcDi^QgOI`xILuH**h94QaY$yc>C-*;_H zJ$BrW`-|G~yrz(?w-yM^$vL(>_}WIDFKec4Rc4KU$ei~s-t literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.kapok.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.kapok.png new file mode 100755 index 0000000000000000000000000000000000000000..d8bb12a22d635b4f3b617808744120d76de98c49 GIT binary patch literal 632 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>*sr{-yvRO+VY zYnE2&Rn{4mRqI#Q8~X&?7FTK~W~rtXXjRl2RyUY5wOgg+Y2=q^#AkTrl zrMq>1fP#BHT^vIsF3V2n3_5JUQXF50cqKWT&eivzmpHl1c~FV1^gV)kmO_nwR5{Jitrn@?ru%FdkEbdcBQ(31^y z%NT!_2l|Air{?$#Zpbe2c8~;Ys&#Sl0+_NTz|3G}mk~bljdb_*)f3Q#H z;f<`la}5{^45}rr5hW>!C8<`)MX5lF!N|bSNY~In*T^Kq(8$Wz#LC1(+rY@mz@SZ( zF&9NcZhlH;S|vz>v95uUu90bo5m1A14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>?`)m*ltv1Dsq;r@>5{hc)lt_FKrE0$MeuBgmfS(Ux0IAv*B#)ihC z)wOxMTgune=I?E*JlIvcuf6I}cb%7+`p)LEW#t)b>+%nD)gI|>I6JL#bxrP;+Jb@* zhb^sTOUu#^_tYo38>M)fB)Sfv$C%{p?qaa+ zj_wm6hqJ&VvY3H^TL^?1FWs&C0~9>q>Eak7aanf4?Wn^BJk806FHE~|E@w-jcU8l| z1eyE)-v%s`e!f}xub-2E=+3}U&MNKMyA^IM$~rD2{I1#T?LE0S1tzaH3g3INIhJzDnjD7Sc_iy39hs(aE z{@lV`_qub6{oNC;%>iG9|1kyx@V#5z@B0tv7u6Eih?11Vl2ohYqEsNoU}Ruuq-$uP zYh)5)Xk=w14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>^ zP5rrrx$br66#Kg;T$=;F3jbpa2;h6Sy5IL7&@ZYbt`Q|Ei6yC4$wjF^iowXh&`8(N zK-b75#L&pf*u=`jMBBi~%D|valra}YLvDUbW?CgkgR!oGk*<+xh!IeOxs{2jwt*o~ zLyf=pR-guDkPT^>IjMPxxv5qqKn6oWVtT4xrM{tAY&@7*0b*v~NGbp-XYh3Ob6Mw< G&;$V8Tlh2p literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.mahoe.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.mahoe.png new file mode 100755 index 0000000000000000000000000000000000000000..5b166394c36cd083058ce956894af36efb5a96b2 GIT binary patch literal 599 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>&?NcPG?LNNbrHoLy5@7UG>)5MR}ondX_B>79}4;gygdl3O2|*YN-U z|2SUP+d$hHlf2zsR1Y(rQK$!8;-MT+O!Hu3Sjv*44WhcCiIvl{! z%xKQpp__MY+qsv2cKpvaNq-oB?z5VV%asuMGd@T8s%k_^UD|#NE3JAId1m>}_+KS? zudargi0unF_tK#9^vVYeOpea%K`&BO8SL-&-YouAtgC%KK zOrqS5P1T+6s~o!TLgT*ft(C&wY$|PguKh^McrPkFbMKzoEq}g5Ji4`a&h;nDsM!8Ru;C@_Ze}EvE_L%0v)ef;u=wsl30>zm0Xkxq!^4042^UR4Rno6 zLJWY5YH00)|WTsVuG#Kj|80i|Bh8O`gm|K~cY8w~=HPrZf zZv|>l2HB97nUk8An44-<0%R~0B&Mh8Rq7j>#m0k~6(DBzjidsgat2RVKbLh*2~7ZP CozkxW literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.mahogany.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.mahogany.png new file mode 100755 index 0000000000000000000000000000000000000000..36416f988cf6cf984dff6b09e868bc3beaea1e81 GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Ih^WgCtIrRg9UnR)CU{y@!2IN>1u4!#hGeIzl}=!@QdOo!f%lCd3Bz zMEcH22X0x~Vu37!bhsZgs!!KcHV!OI#yLQW8s2t&)pUffR$0fuWJEp@FWE zNr<75m9dGHiHWv>k(Gf#ngTe~DWM4f Dxy11A literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.maple.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.maple.png new file mode 100755 index 0000000000000000000000000000000000000000..4f0e296587bcd8030a228baf28d7cfb4ec891882 GIT binary patch literal 588 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>{dCBT6!HONBigo_-%|QwiqgA@Yl@_OIR905@ zL?|yv(O8zDxiMd-GfZhhl=6fL6B+{*mZWR8wY7D0bhNg%PL5Ie|NsBXu#PuC8ySbgTOWt=s2|KfV;OwPOF-yj7)Je4aL_ z%lr5G|6thF%sF#`+@%7b>s3o!BT7;dOH!?pi&B9UgOP!uk*=YEu8~QIp^=rbiIs_o zwt{vX42FWl^i;h{eM7U@crdd9#LT{t1ac6Ar>mdKI;Vst0G>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>m57oM_z@$%ZNZdP@@xx&t+OgEabrHJg3aI{ekA zN9s%n(VQ5ntw}LV3pB_GHcAc9Z}V55 z8L2ZnN+&V^H32ij6@8pY}y^8#=E zVmZ1zY{k0v;wkYRv4)H)ZoSEeCMEc6s1fB#|8>o1t^0zn+MUb~Ze32=DDRNX9li0U zlJ@SW+kXiLU)>Y$x5MPDO@8_J&5^IC+28ya+A;AT=YIhv9=EQ{=qW%isFt`!l%yn< zq*^5xr2;7iBLhPtT|)z1Ba;wABP(MQD-#oK10yQ~gEmpdToett`6-!cl^_kqx&}tN zMy4S~Kn>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>l{+gt#uLGF((?SP-nZ zu-sr(o$=CYqZPHrXEvK2TWffFqtVF?Mn~2dp51CSyIAk+7PECTv^UPy**r&Q$pp>S zQ?>Rj)88^rciVj3b6c%jlGN8s*WR&E_r!X`vs*0AZ+E!7*MHAa{Y@>V=eOI>E7hM< zqQ7#A)`1lU2Ui;W|Np;#=51S`8yJ(k-Cfjm`Bx|dIh+L^k;M!Q+(IDCcE`>#AJweH-!o#yF`69nQrI2!pXYFJYO zgP)lPmR>JkAaU%^iI-ER8Y?e2_w~}9n~RqU)!cd@q_k+!yeO5pn4-9B1w-3zLp|r5 zYVU`3D<64Za^3d%>gBu!HB-%w{zu+ZRJ#nPKDAz|+x9_u<)rgdwsCD@n(<}B`YQd5 zcfQ-N)qFqkVw(Fm)6>XP!(c#fB^&jVd%Vj(<|Gp)h1$siY z#5JNMC9x#cD!C{XNHG{07#iss8t59CgcurG8Jk#{m}naqSs56#i8AJ*Xvob^$xN#R zX)x9`Fw!+L4KV_0Ft;)>)iy8$YN+w|-U`&946-3DGbc4KF*nt!1jt}0NK8-FtJF6% ai;V{}D?rTb8%YH~14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>OT&x5{K|XjkBFJ+s_sW2g20sSbx{`^>L4UDjwmJt1IPiQ&E}_HCi=Euro!n=Mwi zTKxb2-}CsddZ6u$N#5=*s)rd*@&h@X1s;*b3=G^tAk28_ZrvZC;5JVe#}J9jvJ-9> z9Wvl?Q59V!?Zt9MZOKx`TmS#NrF<*2t?oO<;L#!P(&Au!r=Drk3eC+Ot9HvZB+dFf zV|j7dJ_*LHSG~*A`{#KTY&@yDL~PN#D3!RFO{~(34MuhkS?{%QFE^BwZU_26wZt`|BqgyV)hf9t6-Y4{ z85kPr8XD*tnS>Y`Ss9yHnV4uB7+Dz@w23n2qG-s?PsvQH1ZgnVH89dOG7T{TYB0Al zG1WFO1Zt@9_udNBpbWAhEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1K;;ac Lu6{1-oD!M<4D!|p literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.plum.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.plum.png new file mode 100755 index 0000000000000000000000000000000000000000..63a2f53cdaf31ab0c34be84e65a0786f8e3ed4ee GIT binary patch literal 597 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>uDopX4zThv6qly0wt z9`D3O;RUk`gIe69X9i_0i!5H9Qq$=bKfyP7V^>a-Th!8sqLp=Vll)Vs_^18<|9^|l zTMwYUj7i?^F3MU-IaWXpXMsm#F#`j)5C}6~x?A@LD7e+r#W6(Uvh0M5Va$dcE{bb; z6n5X3wIg6O+zzcWUe@X1CPVqTCvA9!tbNuhMX1t-@ z_w6_DUgdLoXW(4_n3?lG@aINwT|Sd}bU)AoswJ)wB`Jv|saDBFsX&Us$iUD@*U&)M z$Rxzj$jaEn%EUz5z{twLpiPu97ezyEeoAIqB}jv@u7Q!Rk!gq#P=mRZiK(`MAy7k& zzxP(424#>9X_+~xd5O8HRwY0NLqTGCs$QkOp;>G^m{|d0X5UCE04itjboFyt=akR{ E0GJHg4FCWD literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.poplar.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.poplar.png new file mode 100755 index 0000000000000000000000000000000000000000..354b13c1c64efea22dc1a8f85532cd3258a3c8bf GIT binary patch literal 611 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>U9`w{>Qsx_ zv#r*waa_FEZs}6H-Mjs=n&Riov0k>!e(P43UAw&Z?hQJ0D1P;7ho(8@d-n#GPs*M- z(`wy1$Mx%-{{R2)Q4*C8bO2+Lx4Vm46vvFMKn`btM`SSr1Gf+eGhVt|_XjAr%hSa% zMB=jSgojm!3^-gBUlk?xObea8bz5=q=fClRkN$e@tLAIz;QqXD%At_HnkwaW0#l>z zD<-MQhtx|9WgS2F#1#jN2mY^LanB`dyUc0L^Xlim_*XDl?&FEEua<}f`a-qDHKHUX zu_V8cXd4(=85p#QGUlRa$jwj5OsfQGFxE9N z(ls&-F#>8Zw=yx+HZTNgsPXp(1)egT;nx5F literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.sequoia.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.sequoia.png new file mode 100755 index 0000000000000000000000000000000000000000..fd24491bf65f564c22a835e0941b4ba203dae1b2 GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>bdw=$?P*QqekY;`beb2KlrW@xfC%Fvb1&{N3NS4dQoNY$1pw$REm zR&B60%rjAIwlnT@v21ZL?Q*q>)Mu!((ofTt%{NtRce3blx1Ap3kz=G>VXV>O!BS~w zkgO@yDYs8nmATWX-z;KK0#|9_W7a^67aF(!GtyBMsyqx%HN z;VkfoEM{Qf76M_$OLy!300j?tx;TbNT$Y`1JL<3jPjm9&3)3!~%h^)sUDa?fLFWGd zw*kwfpKn(F>*pjOx-&48vr2pRZiO3*vW^Q0ziT#odr$67fyt|l!uMWm4(F9~Z*E(D z$x6vqvRQgY%gMyQKFp6E-r8_wOJ<~{+$vY=>Nd*_d*Oe~bYEeD7BG`~Cy^MYY5=q9i4;B-JXpC>2OC7#SEE=^7g78kvL` z8d({eSeck;8yHy`7_^Bp=AvlG%}>cps|0B<)-^EFH8Kq`0%|a~GBMRQFa&C-@%P>e z)SwKqAuTf}H7_wY)v5%@U?@mTPt~i`H#Ccl2Qw=`%zopr0C(8i A82|tP literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.teak.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.teak.png new file mode 100755 index 0000000000000000000000000000000000000000..93ab57e5af517426286f8f59e85fb5b00549c7fd GIT binary patch literal 631 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>?Mil1973ReU`?}=k#HJ($rzC|W#Q7y91ZJd0q^5-C=fv#0)n=Z z^>W!WdF%Z(bB~MpTFWUWy-xjzofA;vF)1J4}o^E3PcdK_w{mp{f=PSQ)`Zqo0 zm2og?m<#lWYKdz^NlIc#s#S7PDv)9@GB7mKH8jvQG6^v>vNATYGBMFMFtRc*XcJ}3 zMbVI(pOTqY3DRJ!Yha{nWEx@w)L?F9VybOm2-HyH@4XeMK^bI2T4qjaUSe*lRSA&6 kP>`6Os#mFRXcij}W>$ch**B63fXW#>UHx3vIVCg!02f-|{{R30 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.walnut.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.walnut.png new file mode 100755 index 0000000000000000000000000000000000000000..368720fbd7679563b3cf0eb13247fc3ac1972f77 GIT binary patch literal 642 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>rMq>1fP(uxT^vIsF3V219d%eipylS;(kO$Mw`OgaD6=K1`oo8R z{m(D#Y|Kx17SG`rlCpG_&=<#R{f-+PuTJy!so=V`#kzXi--9cr`&BGHA7@%o(%g3a zl9iINBr~sBVo8L(VZ)C7($i*{o#pOtm%4cFUIO2l_wH5lI)77C822^zGiz3UDN=fR z`hl+XIqB0Ic58hT+A?E0TkC@t!t17Ps+c!3(k9ZKD=)0wqBgpIMx8}wZKPdZ!C8<`)MX5lF!N|bSNY~In*T^Kq(8$Wz z#LC1(+rY@mz@SZ(F&9NcZhlH;S|vz>v95uUu90bo5m1A`d6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/heart.wenge.png b/forestry_resources/assets/forestry/textures/blocks/wood/heart.wenge.png new file mode 100755 index 0000000000000000000000000000000000000000..7a566ee5c7b4a512a06edb940c6692103340c521 GIT binary patch literal 618 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>;3=* zw|crbhDcnN4Y*x)$bhHYc7{S`HdpSQAc>p}xBvfFDEd0dWt*P5W@p!)m8(?lp7>_V zS;q0E@=23g=IxoXYwV>8rCOwuzaDr}X_jHNxHu(COU?WO=ibA|TA7~Isjk@)tI2yj z*rQ|v_nF3`U6XzBG~%N2Yl7TL;_m7Q6SapBs9ktE0AM<>J`WY4IO;7R}6F zxa?yRbMS}Uz(@a*9~b`YU3T%)F7|(qj!mh*d&+sTz(-E~CK+CVri#z|fgVsTag8WR zNi0dVN-jzTQVd20hDN%E2D(NjA%;d)#wJ!KCfWu@Rt5%bqKvsH8glbfGSezS8jN)f zjC74mLyUkL%&kmJwG9k`8fyH#w*oaNgKS94%t_5l%uTf_0Wug064O)lD)kM`V&lQg W3J^214Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>-S4p_Q8 zxV@or-m<9PDV|%mr_`6{*Oun?O!k;G%YW6Hh{a0-|NsBL_UR;lpu-rGyxm>&LM{um z138=p9+AZi4BSE>%y{W;-5;Rfeoq(25Q)pO6K+QxHsEO%&UcP>vfh00nC?qPw&XeY z{(qgYT>AND<-dMT9YT-YT#_c_-mz`zu#I7#HszzllFa^JOO|gAIv@L_ci)Wc4JKMD zd#+rY@Iq6<=b(xY+uL-h34Y((o-I3j`qak)15O*?Yxa#P;oFU75AjQPtvRkN)yC$&oK2b+g^M_FbL6<6lPoy!xFh_pgcJ zJ1~E~$IVlE_f%X?**}!G{lPc=0+-K1pjT8&Tq8hkfv%BB zh@p{{v5A$5iMD}}m4QK)hTQy=%(P0724h_VBV8lY5F?-lb1M^5Z39D~h8lnG ztw0URARE#$b5ipXb5pHKfDDF$#Pn3XN_|7K*my9r0>sR|kyHRw&fw|l=d#Wzp$Pz6 CHu^&V literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.acacia.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.acacia.png new file mode 100755 index 0000000000000000000000000000000000000000..92b4edbe8e8543c1d091710a1d5583a7c366b68a GIT binary patch literal 448 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF=>{ zV7obs&B*O)>bf&?j1`Z0_4C%Wwi-BCvNJq=eV&1T{X+dq&3kPY`Yy95c$z!Q+h^lB z-W%*|-sQY1a^7wG{^!ZpyX#_~3r;)`@q0JWX4Mkch?11Vl2ohYqEsNoU}Ruuq-$uP zYh)5)Xk=wP0aO3u4Sw;t7*ptywhjQ8u)Jd%pd?0)V-=h;_e zFbY&Gxw4yGbN<=sJ6C0$YmzKFEnB62S>i#AI>YnV=NYzVywukWl4i{}dwL*ndZwQ7 zlUQp5zYV;l<*XO=&u7=Y`ms*_T_^vAj5iA#fmW-QxJHzuB$lLFB^RXvDF!10LnB>7 z16?DN5JMv?V-qVA6Kw+{D+7ZzQN~;p4Y~O#nQ4_E4aT|#M!H6(Ax1zA=2j-A+6IO| z4K@DWTY(ysK{lji=A`B&=B8Se02vGgiRr0&mHLKevGHJL1&En_BdGwWoWax8&t;uc GLK6Tu8IyJZ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.baobab.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.baobab.png new file mode 100755 index 0000000000000000000000000000000000000000..fd67cf55dcbf53970e245a262b1a8f37afb6caea GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFEal|ab33eqUd1*4(8U)3`JrcCzx;DmaPZZ>6w4I z{`rdf`}e;X{cCwX1}2n<0j*Unag8WRNi0dVN-jzTQVd20hDN%E2D(NjA%;d)#wJ!K zCfWu@Rt5%bqKvsH8glbfGSezS8jN)fjC74mLyUkL%&kmJwG9k`8fyH#w*oaNgKS94 u%t_5l%uTf_0Wug064O)lD)kM`V&lQg3J^2o0F@#x@Q5sCVBi)4Va7{$>;3=*D?MEtLpZL>_BaYM849picQ*PYJ-A_9(Asu{@%Q6q zW-eZd1B_|~4J<4h%lEIGIZtinGcMM!$x+=3H>WL@ynOd~L6hdn+fC=fbPPITr3HT5 z%m}!W^KsY8SyiuWa?Ed@x?FyF#vRY4*^SrTPO6*UOI&vJXR&Pj{y)#;H9Lh4ZP==n z26TjKiEBhjN@7W>RdP`(kYX@0Ff`ING|)9N2{AOXGB&X?G0`?KvNAAe6J^Xr(U6;; zl9^Ts(qOD>V5Dng8e#<0U~Xk%s%>Bh)KKH^y%nfI8Dv9RW=?8eVs5Hc36Q~1keHsT fSE+Ak78?&{R)Cn-jd|Ns9x6KsWnY8aEe-Cfwl5<6Z4Ih+L^k;M!Q+(IDCci=u}OIG9^EGZcw+oMfs~oOz(?=hhsUr zuADlvszqY6E#C(&?!<;7KZaA+=QEn+FVw%(yj$>AN>`(Ge6X(Jr4J0pTDBfsr)U1< z`sXX^@8ADo^snXl7?@BZ2DDbS#5JNMC9x#cD!C{XNHG{07#iss8t59CgcurG8Jk#{ zm}naqSs56#i8AJ*Xvob^$xN#RX)x9`Fw!+L4KV_0Ft;)>)iy8$YN+w|-U`&946-3D uGbc4KF*nt!1jt}0NK8-FtJF6%i;V{}D?rTb8%YH~gZM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.citrus.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.citrus.png new file mode 100755 index 0000000000000000000000000000000000000000..7e1628004c6afcc1ddd27ea3a5173b9e0fa6cdc4 GIT binary patch literal 507 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a> z0%MZ5yNlqXt+u;>9L@rd$YKTtZXpn6ymYtj4^VKTr;B5V#AV%nPCge!4rgvF4!zIM z|1F=}w7+xKhCN{p8V;2~yf1zQo?W$K#l{4qwjJii=E;iBV#15h?d3DDIMCN=QqDfp zrC|E>xPQB?TSSZ>tl67h*rDNeOinr>9TmMU%8eef7u2}W(%~p=c`?H^TxP z{Blvu+qnnxc+T$kP~9qXLgu-Rp#O*7_#;1==kl}mC+(G!1UgQJNMC9x#cD!C{X zNHG{07#iss8t59CgcurG8Jk#{m}naqSs56#i8AJ*Xvob^$xN#RX)x9`Fw!+L4KV_0 zFt;)>)iy8$YN+w|-U`&946-3DGbc4KF*nt!1jt}0NK8-FtJF6%i;V{}D?rTb8%YH~ O10y{RD-%6E zO%+8sX&}~ARa8?}kd_qx|NsBwc>XA$O2#B_cNfl&HRdP`(kYX@0Ff`ING|)9N z2{AOXGB&X?G0`?KvNAAe6J^Xr(U6;;l9^Ts(qOD>V5Dng8e#<0U~Xk%s%>Bh)KKH^ zy%nfI8Dv9RW=?8eVs5Hc36Q~1keHsTSE+Ak78?&{R)CnsL-|Ihvthz{5>46606W2^8 z7_QRGPJ0%`X&6?O^FUjth4GXngU0-Nwu%bg+KF;+o^s|I9c|RkzdS3ct2FO`T|#Mk z@O0^0Z!6dP$KC(Q{NgNs9$WGYCZNr#C9V-ADTyViR>?)FK#IZ0z|ct7&_LJ7B*f6j z%Gkup#6;V`$jZQ=O_VVgMMG|WN@iLmNQ1Gifsw9}X^0U}gSnN7skVV3P(zKs_g0_= zWsnVNnK`L>iMgp(B|rv4L1KEUUZuXFS!_I*Spi~Z-$*I|DrfL?^>bP0l+XkK10jfB literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.kapok.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.kapok.png new file mode 100755 index 0000000000000000000000000000000000000000..efce0c953bc8cbe63bec02d72bed24e19cd83791 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFZ-5-m0*}aI1_o{+5N5n| zx9$&6FyGU~F@)o~Z0|lzs88kvR|0X3LgnV4!D7y>oa z_&i3xQse&r|F5v3`yx;!W0JSK3+Kn1OWy!FoCO|{#S9GGLLkg| z>2BR0pkSV-i(?4Kb=lrP(ZdEj%u_2E*61)qZFl%|OffNl|DZz8_bY#IUi;bNw4P6* zfbHfiHY2yIsq4{vX42FWl^i;h{eM7U@crdd9#LT{tQ~*@Y;OXk;vd$@? F2>{_tmxllV literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.lime.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.lime.png new file mode 100755 index 0000000000000000000000000000000000000000..8e6bd70f10572544d66a866b2142a785a3403490 GIT binary patch literal 448 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFg-3+LbG0EHAh4bUhrEh>7&H|6fVg?3oArNM~ zbhqvgP%zKa#W95Ax@>Qt=wSmM=BX77YjhZ*wmW<}rkEJOe^8<4`<1^pul;OsTF)m@ zz;<&Mn~~eq)OBa(7%Lw0>gTO#Z8dPPWM_E#`aA>w`i1(Jn)li)^j&6A@HBUpx6j6N zyf@g_yvuo2!C8<`)MX5lF!N|bSNY~In z*T^Kq(8$Wz#LC1(+rY@mz@SZ(F&9NcZhlH;S|vz>v95uUu90bo5m1A14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>INadxv4NriJ>^xu<5u#V5W0H<6RA z!%TQqVquk2k0s|$yW1z{E1HVl`&jC_bJpg&(#l*{SWRaMtS|l9Q4v)wRs4IKnEe-7 zwz%%KH*JBgR4s9hC`m~yNwrEYN(E93Mh1pPx`qb2MkXPKMpniqRwgFe21Zr}25q8@ zxhNWP^HVa@DnS~Ibq$PkjZ8y~fEvuLOiZ;641pSI{JpmVH7J8@NXyJg%}dNpwJHHJ k7zz^8Q}rtK4b5WX!ORK}Gy6tT0Z=)Er>mdKI;Vst0DFnH8UO$Q literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.mahogany.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.mahogany.png new file mode 100755 index 0000000000000000000000000000000000000000..fd0fb42692d09eabab35eee8f87277d614804cb4 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF2OC7#SEE=^7g7 z8kvL`8d({eSeck;8yHy`7_^Bp=AvlG%}>cps|0B<)-^EFH8Kq`0%|a~GBMRQFa&C- z@%P>e)SwKqAuTf}H7_wY)v5%@U?@mTPt~i`H#Ccl2Qw=`%zopr E0GrW^Y5)KL literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.maple.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.maple.png new file mode 100755 index 0000000000000000000000000000000000000000..7f619ca3f8be20b5a1bb705fc6e368ad91e625d3 GIT binary patch literal 506 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>h3nI@+!UY1l&huZCVXJb_gS*b`ox>4 z7omGqjMkNNXr>*oyZ7_B$KFYg>Vo~4t^eKQVCyh*>p9q5b#&hGy>`<-C36JNcsw&G zBe(ZxUhky(iI=Z@a{PAVcV|UY^&Y|B+)pFeBy#^QmvNATYGBMFMFtRc*XcJ}3MbVI(pOTqY3DRJ!Yha{nWEx@w)L?F9 zVybOm2-HyH@4XeMK^bI2T4qjaUSe*lRSA&6P>`6Os#mFRXcij}W>$ch**B63fXW#> MUHx3vIVCg!0N;?QRsaA1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.palm.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.palm.png new file mode 100755 index 0000000000000000000000000000000000000000..32fe041a44ccbed29fcb1170f1771de96bffe3bc GIT binary patch literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>4t{c*gPdE7;EwMUT>vpEue_Dk0gb>ZyQM&VDbZ18D%!$@rlAzxipz;6z z|AfrXIY4t5lf2zsgn4$yOapQ_3p^r=85p>QK$!8;-MT+O!Kt1ujv*44b^99mjwot311c2ZYt8;>!T z?dou2Ik9JrL3Wu(%A6eG)WU>yAKUno&)Oce(-fTZ=GQ&df6vx?88~d&{XwEmN2GX- z?@s&nPw5`lkJ)bAF5;G5YAd1Xa6dpw@8a)$$>-ERdtUpKc21t>1zY9IsgF&84pc31 zjVMV;EJ?LWE=mPb3`PcqM!JRux<)1;hDKJ#CRQdU+6G2e1_o`SjJYTpa`RI%(<(t4 zjCBo+bd5|yjDQ-ckG8hUH(^K^-^$pEp Z14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>0U3%?M^sN)w z7k7EwJyUk;MDB&1u6NH=Tt6Il`()m|vz2?7>TR8;b7-ahv9*Q=R_GsHV{mq}$=c~! z|NsBrXK-mT&>Y4jZ+91Ap4~CifE>;OkH}&M25un`X1sK_?hjCKs;7%%h{R>xzDB+y z3LMVeCj<(scK`o>WA*1*56b>*<``K}#%nr(aWX+CAI4SLU&u)D_#t zV~l0HI^0-J>{(-wUFMN8Cr3E7Fk#)tHvZ(Zwg>Gr1?Rl^bx-x*v-MsE4qJAAkf_rU zDPH5d)4u&vy2tfnwi~yLxMi2xN@zOV50KKk_UO_QmvAUQh^kMk%6I+uAzahkx7W5k(IHDm5GVAfsvJgL7OOJE{cZS{FKbJ zN{|L)T>~RsBhwHgpayd*6H{#iL!gElfA6h84ay)J(lT>W^AdAYtxA9lhJwWORJ}@l cL$la;FtY;0%)XIS094N4>FVdQ&MBb@0HdM1X#fBK literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.pine.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.pine.png new file mode 100755 index 0000000000000000000000000000000000000000..ba82f48fb597a7c684b4b83afa8b30dcb6733c7b GIT binary patch literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>)I`k&JQ{~+k17Z#jyn;`=>e_p6zpNLFmLngYF!?X(fg;%Z;WK8%{4ZnqO_&ny&Nz z|9|7diqb%H7?Zr+U4(gd$4moqI14-?iy0WWg+Q3`(%rg0K*6b=E{-7*mv#FZ`Hm=X zICq~AD6HE3|No8EpJz$z*BjX`#qN6MTW;nc!}bsyXKlh4{7w9^!v^XAt*)ql^{dl@)v+5JJHPDiA8 zjqgtT_D|^^*N@q5+%DplU1}?#>2N14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Y_)@L;?i!5H9QnNm%sm?jP!ZEnXEvm&my1_NF*)6KmE56t+;Q#;s z6U}Ru0?lDe@^*I-=Gh%H4angv@Q5sCVBi)4Va7{$>;3=*r+T_LhDco2?Q7&aqQK$Y zeL|qHYWM&DH&%b1CE>G>pJ8Fcq3uf@ww}(}9kj%PcltFIr`@xydu1NmNnNpRJjPhI ztHX`u#GW+<*<~Inb8>`J3lr9TY~xQpYkSa6Q*h3kU-wl1JzMW(;IL))2Z=fzk>WMJ zJMG&)rF&dIX1j5_h+B54t%Rn-{QxPwi@*0JpHu(rdF@ZyIeDHJY?UvkJ~jn9P_@K0 zq9i4;B-JXpC>2OC7#SEE=^7g78kvL`8d({eSeck;8yHy`7_^Bp=AvlG%}>cps|0B< z)-^EFH8Kq`0%|a~GBMRQFa&C-@%P>e)SwKqAuTf}H7_wY)v5%@U?@mTPt~i`H#Ccl Y2Qw=`%zopr0Bn`9UH||9 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.poplar.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.poplar.png new file mode 100755 index 0000000000000000000000000000000000000000..eef180166c35ea9cc08ada7067c410f98afa733d GIT binary patch literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>3T=FKka);Vt4MB=h;UnAcU z1rF!#69R=*yZ`^cvHJ5Y37>`h3=10$ZC~oJ^>ohepd}W()32#G?VfGjEA!Y+>WXdS zF~+i89d0Zq_N+0;F7rs4lOvp3n6U0+8-May+k9X_+~xd5O8HRwY0NLqTGCs$QkO cp;>G^m{|d0X5UCE04itjboFyt=akR{03Y|e0{{R3 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.sequoia.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.sequoia.png new file mode 100755 index 0000000000000000000000000000000000000000..3363e6e0b75e714eac833f4db77f3b564b48b138 GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFUI zR^|c5MhUhyR;nuh|Nrk<`XC9YhB3+8-GyB&vEwz6!&%@FSoqvKBHOwLj6n4y9IBhbTwMX2kRPM`oM6kW$VFpdgfoQ zf4-vr{{1gT|5~1pfe9sIKxhkfv%BBh@p{{v5A$5 ziMD}}m4QK)hTQy=%(P0724h_VBV8lY5F?-lb1M^5Z39D~h8lnGtw0URARE#$ ub5ipXb5pHKfDDF$#Pn3XN_|7K*my9r0>sR|kyHRw&fw|l=d#Wzp$P!#*NfZ$ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.teak.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.teak.png new file mode 100755 index 0000000000000000000000000000000000000000..3f0719f02794899a44e79e9486ed51f76fd96299 GIT binary patch literal 448 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFf-qH ztde^PCO9tdpFQ#)e_f;l9a@fRIB8oR3OD*WMF8dYiOWr zWD;U%WMyn(Wn!XjU}R-r&?d^5i=rVnKP5A*5~RUc*T6{E$TY+VsKMOI#8lhB5U8QX z-+L=igEGj5w9K5;yu{p8s}dlCp&&6mRj*Rt&@46{%&Y)0vu`970F^U%y85}Sb4q9e E08T}cfB*mh literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.walnut.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.walnut.png new file mode 100755 index 0000000000000000000000000000000000000000..3c774194284e2c77acdd55fd1404e3f017552594 GIT binary patch literal 445 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF(=eyM)s8 z;OWx0-d3*nkGubq`NdiOJhtQ)OhB7eOI#yLQW8s2t&)pUffR$0fuWJEp@FWENr<75 zm9dGHiHWv>k(Gf#ngTe~DWM4fhS7&M literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.wenge.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.wenge.png new file mode 100755 index 0000000000000000000000000000000000000000..b2a2eb71b21f27b7adcb7660be7854b2eeab5ec8 GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFoqvKBHOwLj6n4y9IBhbTwMX2kRPM`oM6kW$VFpdgfoQ zf4-vr{{1gT|5~1pfe9sIKxhkfv%BBh@p{{v5A$5 ziMD}}m4QK)hTQy=%(P0724h_VBV8lY5F?-lb1M^5Z39D~h8lnGtw0URARE#$ ub5ipXb5pHKfDDF$#Pn3XN_|7K*my9r0>sR|kyHRw&fw|l=d#Wzp$PyID~fOc literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/planks.willow.png b/forestry_resources/assets/forestry/textures/blocks/wood/planks.willow.png new file mode 100755 index 0000000000000000000000000000000000000000..109ce46f2bcdc298d591810f536658e1571fc4b5 GIT binary patch literal 445 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF$1HUMGqTrFsEK-obZ}aXp-ZfUmofk++T3q-S73EK~`O)s`NmE@ri3D z6AV}BWv4xh;xr7a%6Xuz)53Vll0jpBJzGTuZ|y|6H%~cpjgB^I=U<+c)K!{yz%HRQ zJ$SnGt+$oy{p0TcWPWj$KaVZ>1ryL_)e_f;l9a@fRIB8oR3OD*WMF8dYiOWrWD;U% zWMyn(Wn!XjU}R-r&?d^5i=rVnKP5A*5~RUc*T6{E$TY+VsKMOI#8lhB5U8QX-+L=i zgEGj5w9K5;yu{p8s}dlCp&&6mRj*Rt&@46{%&Y)0vu`970F^U%y85}Sb4q9e040`- AfB*mh literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/tile]-120.png b/forestry_resources/assets/forestry/textures/blocks/wood/tile]-120.png new file mode 100755 index 0000000000000000000000000000000000000000..a19cf7bce613bc282352f4f4a653b73125e4028a GIT binary patch literal 507 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>V{kYOPU&AaU8B#_3+JBj>!A7pQLiczIgm{ zQOw)92lIH&?)OmLDsw{Sxs9Ozhu-)jKbhz9v-T(Lm6HTIPPN1}q9i4;B-JXpC>2OC z7#SEE=^7g78kvL`8d({eSeck;8yHy`7_^Bp=AvlG%}>cps|0B<)-^EFH8Kq`0%|a~ zGBMRQFa&C-@%P>e)SwKqAuTf}H7_wY)v5%@U?@mTPt~i`H#Ccl2Qw=`%zopr0I8^?YXATM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/tile]-127.png b/forestry_resources/assets/forestry/textures/blocks/wood/tile]-127.png new file mode 100755 index 0000000000000000000000000000000000000000..03f875dc411be53da2c2b9a4c6ec001ec97b2d69 GIT binary patch literal 560 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>oFk!-^Nt2c?T{?5-%*MvX|NsB@>YM{PlrhQM-9?%y;mQ&qhqJ&V zvY3H^TL^?1FWs&C0~B20>Eak7aap&ITj;O?2kS?1mx~!DnU{adZ#lm#|JcF6h-oJj zT*T6k3jW;Cdf=Er^fp2MNkx9EmY&j6>Wg}ReDb~D7HWZR%yn5_uA!Yg`3G-Ru(ixQ zI4#|5d6SaMXQ{>iEgX8X*YQnc>e8}W&CJ|sKl$wDM)nIzoJKp|yvpc%&Ge+gR;|8m zrJneYb-L5;-}_y`w7Fm!N7oI;&Lvy*`YqpId)Ic$ZtYq9g9%*9M^x-r1Kq4z;u=ws zl30>zm0Xkxq!^4042^UR4Rno6LJWY5YH00)|WTsVuG#Kj| z80i|Bh8O`gm|K~cY8w~=HPrZfZv|>l2HB97nUk8An44-<0%R~0B&Mh8Rq7j>#m0k~ W6(DBzjidsgat2RVKbLh*2~7a_3Dk`M literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/tile]-142.png b/forestry_resources/assets/forestry/textures/blocks/wood/tile]-142.png new file mode 100755 index 0000000000000000000000000000000000000000..0ecd35838676de6f3ce725bb963e45d58be082ea GIT binary patch literal 1121 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG?e46!}hR5&tuw{6x`_%!m`vvHFu7H`qtR{Z-3a$lRW>S z_LRQ;e*wPdT=SMENi+orPjCGli(wQxXn`@@LO%iuu z`8e;K^xrv`9+hud*!*a=3%8|S)oGn&irY5{?)x8%AK8>lY`pNzR${dt;i&5excL&c<`|vA?}pa)qOY3SGH>XDw+F;!!2vR z{CS$=;W0aLqGaHty=` zE34Evt^4hBjpbODOcwfhZr-HxuQ|>?KA6|I`Zecz_Tp3jrX)z7`O)JS{P^j9tMh#_ zQl-;FUKFU?ANnkk(#e;5^lA3bj<0_ve3^A@{dxZxrNt8RewDML7iDlpoo3Wtwq(Z4 z0`=_&dfyes{NrCa^|FRFcbu$g#O>3C5t7C$^%H%AWnA6~RVCjEku|;Gk)q3_X(6j_ zxt3KTQ#8}koae6eIbp8Z$Jne3D+)_H^=s$7NefVx{rAJ#(Pr8a1Gg#bRkuEy^Q!ms zJ$J(+KR344ebK#nRi(I**BP;;NWwx^eNlT&9-KnB|mo^^k$gKX$c^ zIhW_9=-dTnD%BF#h?11Vl2ohYqEsNoU}Ruuq-$uPYh)5)Xk=wi-k literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/tile]-143.png b/forestry_resources/assets/forestry/textures/blocks/wood/tile]-143.png new file mode 100755 index 0000000000000000000000000000000000000000..6ec69a47f2b3d6a5eb3b68de9c8ee080c460b6f8 GIT binary patch literal 1320 zcmY+Cc{tR09LK*ZTUe2ngiR8QX_y=17^68HV-7Q8#x{c)GbY2BaUUUxBBjz+Iw2-6nGqLpZOF4GIqfAjcVif+7IE!bb&@0HmV;n2G^_ zSP8%i&Cy1VF8~Yr*$f_)L|iKfL2sbDsYT@aW2J4kj#ux>J9}VjhJv4|h}d76^}P9f z>xIM58c**jP-aVMB(GHxo>v;rNB8vZi2l*ZL)%$&qMG9$%cHPpWQIRV#0f+>Si9Pq zpV*nZC6OONbxW5EnE}YA8)q*ZFQZ`W)Do7MhOQ}BGs$>$te~_oHBZS);QRTxEKiXz zGNnNX2O}p75YO}9lOOMow}T+4wxXc>-qmnAp6=zCD&@opNEF|7d^&1z zaO3X>wJ*E+bnSywIxG>;2c3YXruNL8OB1=>Uooxt~7jUws(W zj&=-W`EZYkcsI+z29*O_p=%A_i6-Nyph)iG^fE zL?8+8v`N8Gr1C4SS0+YLlcH&XEW8iFk{gOSdafcPE0To8#>&_l5hWzdrzAtHWO)~5 z#O%zKiCNx4CaSPlSyYlH48zBZXz2+XlyUsRJmrafIms&ismjfr_fHS@-R20&`ezkTQKZ%xfDt-s&9 z|KK5DJu3gB?eUZLr_VY%pLf0J22nj#y?y-ygW4gTet2Yb3?#iAe>E}r=hXD;H*ep) z|1e`elNs6v#%$r;Ii*pBX);NgoEV!ThXr8Zha=G_BnHPrV~AKB5r;#dFhmq;o27y3 ze}GCYi;v5m2e3#K28qG*Ffiar#NiPrGz{djLT|u;Um>{h!U6w+Vex4LlBlsZ7eHz?i~+0l&2>EdT%j literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/tile]-158.png b/forestry_resources/assets/forestry/textures/blocks/wood/tile]-158.png new file mode 100755 index 0000000000000000000000000000000000000000..4e95d48941795aecfc502b485b6471a7bb65aaa9 GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>ujE*vt)wi z>Zw}$mg#Sqr@L*w?zyejooxwgrfct5sC#0);n^(~=eIjt-s`_-ss8dsIp??A&z+Gp zZ&u2j8A&UrXdPH#aB!u;;(3|>|Nl3hv{?w~62>HNcNfi5+gnwD9L@rd$YKTtZlDCW z5aXr0b$@_@yF6VSLnJQCPPiF%IDo^IaV?J$=d!b=nMtclfBn~=a{DvK>o;ea7&t#R zb_l!>ITRrGy(EiK$-_wuh z#H$ji&p=iwG j1&QgYdX@TyX0h>LW(A0ueIuy=sGPym)z4*}Q$iB})n)59 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/wood/tile]-159.png b/forestry_resources/assets/forestry/textures/blocks/wood/tile]-159.png new file mode 100755 index 0000000000000000000000000000000000000000..f8c824339445a2d765a8b08b17dc80aec0a79d8b GIT binary patch literal 652 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>dgj*g6sjEahyIdkTeDN|<5m@$3&^huK@&7C_pFfee|tXa*?%`Gi0t*xy!H8l+l z4Sjum9UUE=ot^XM&6_`ezP-JDV`F1iSJ&*>v!_j)HfPS9g$oz1S+l0Sy}h@$H!(4B z^5n_&_4NxDENE(K3Jwkq4Gj$n3aYECYinzpFk!;Pi4$XDV*daCe=E-Q8_;=-N#5=* z2J7zVJ^^w#3p^r=85p>QK$!8;-MT+O!K0oojv*44WhcB2J8Zzy{PsXcj!)F)iw?8b z8dxR7-2eZ!VEOz{6YXS$3zPPFX&NrgzIR6;y~FF=b^*i5)?Q0r|Gl@}n%_1>ZJMIq zRh{U{63;J7<}PFq=-BBJEXQl-Bj|85u4mud-DNXYE3cnuFz+FoOkCfyUtVjxU8E9h zb8;Lt7waxxu*dS%Zll@*taX7a*QI;C+NLp$A$|4}W3SqEMJukRWygh`n!aAy@4nre zWwkoGO1J9jLi?3=vOLw#{V}J*`L*yr#tWPHoHpA{mvNATYGBMFMFtRc*XcJ}3MbVI(pOTqY3DRJ!Yha{nWEx@w)L?F9 zVybOm2-HyH@4XeMK^bI2T4qjaUSe*lRSA&6P>`6Os#mFRXcij}W>$ch**B63fXW#> MUHx3vIVCg!0PiIA-T(jq literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/worktable.0.png b/forestry_resources/assets/forestry/textures/blocks/worktable.0.png new file mode 100755 index 0000000000000000000000000000000000000000..d0f1b373e1bbb72e84caa9b2239c943b3e1237dc GIT binary patch literal 502 zcmV(0U0MLm6`wm0fR|I zK~yNub&@@96hRP$Usd(Yu-NPM0XP8(AwohN0C5x!#4QLA83_p@bI1h{5f(zbVm#ed zuLycQ8X;3rsrA)gzbD_ny~llIc)j}tpp1|Eiwzg&q&&)GG72_9E_f(JER&3y;brap zKRUw`e$K(N_I~#2EdX~nGZArj5gCR-RRP?5eg`0<6#$G1fTWqJYD54ShM^abjEJOr zJ!SR@nE*1gwf5r8HGutoN2aPAkIR=2w5cfoOAEj{SzRz2W)mD|eJ4TQ$7>0U&Bc)I<%KrfC9j^J(tiwT=~$ z%p9jf_*}-zve946tc$Rss#;2^wF1~(JrNPvnr~}|wT;?HUmzlC0Lp{@Dbr;)oQMLT sFUU-WsQp`@HmVMynxu$|Dxh27FQQKcB`zAaTL1t607*qoM6N<$f|HQZasU7T literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/worktable.1.png b/forestry_resources/assets/forestry/textures/blocks/worktable.1.png new file mode 100755 index 0000000000000000000000000000000000000000..fdbcb2d5d7c2d4eeeac75628f3509f00debb6230 GIT binary patch literal 767 zcmV(00YBNU7-K~0*pyS zK~yNuHPB6HR96_r@#lTdxp(f&9g~@0n}XmMuKXxPa8XR{)QCl+X5miVii*;O3&BMx zS-7=Ig+lG3wTrf^ZnB6GW3g0JM5T-R2}TJviJD9&GxsLvp7XvgM*r()@$jR``_Z*=f-~Cvh#E{P{3=k($9LU z+v;9IG+2!rRp*>|3?_BqlcxkuW+K~`~_goFF3u?&%7GM?;QcG4!rIMf^Vrwm80Lb&)W)*EgW3{G-v7}MGoTh2#?>Qxi zNNZxw+K8E&W3!eGGm{~zfP2Yu4+BDFL{SuPPucPOm6>HbmTS=YD>L<>4@o(jXmV_+ z1^~S7a!L_F1OSl@M5@ptXb8+q%0wnjt0px7)<5huH?Lm2bMY^1SYal0@o{_M!F&i| z@mc1cFD6NXDM?&IUcVN*7X1Y0+2~W zK~yNuJ&xUrRaF?qpLeZyt-bfzd(PP((`e0<84-0+h?;k$R7#W(NJ2qI7kylHB?w*i zAJk|#PfO@DCu#8rk)oA*|k-&m3c=ZJz0RV7-^YoaxWmrG@PCPxg2pSBKL*VCJf-uKe=Z`syD_ zDWlbW!oI_$_kQmyrE_lok!my=y>{ZUwryX3cUO#2#QAQlNO58{0A~JkdCM5{*Uwwl z+U>sl&00|u7r$M9U_`@fmx7zz{`aRCLlh6tY%;WI)wLU%v#h_!wjk0(O2pNR2WWWh zQj9@q8zo3+-R!P}PH8Kli{iA&ZB_%&IsqW!?*V5D7(2AY=8^ya002ovPDHLkV1m(| BZ-M{- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/blocks/worktable.3.png b/forestry_resources/assets/forestry/textures/blocks/worktable.3.png new file mode 100755 index 0000000000000000000000000000000000000000..d56c74565281e214cacfa4c7b0039789626f1763 GIT binary patch literal 748 zcmV&I52A6>U#hH0(nV9 zK~yNuJ(0_cjd2{tpYQkmz3=bLoN?xy+%h7!F&oslgp|uhBK!eLYBrQ&p)6RCvb3;J zvY3>`EF^YTqA1r08)RW-!kKfMW8UlUYVpeY`8<88GQUQ|6*O+{&r(C!#g)OlFY`bnQdkd zr*0Cn0MP8@hxe}N_EnOZC3Sgl_wx9b>Gsw6i498|6=qsU^z^Uv$H#jkW5ekUUjkTY8iva++vUe}Msscx^@8BRJA_gD?rMcM@MRo6q2*7xyvH}2* zW_FZ0^gb_a5Ds|ngf)4bn(n+Fxx9J345|YH;9a-(>;h(gEo6n+a%DWrEi*WXoYf2f zK)n`DJa~Je`8G}s;P%~pa^Ux~MO8686i(cKceeRHFPu@aH5mt@Qg(t1l5@%m)9NJh z+@REwh@vnEFGq&{`iqv<-kD3YY+3!*)4TivXmt_MS#o4H8jn zF0NFBv-JMSyisv9xL7cYdMyI*?M)s88i4oSdq4BZd+)W@-uu$*o#h}BEM%h=5z&8x zGjMSA#sD)Z<$B$e2wz_o#DRBOcxQ=F8kkji902A*2;sd~N;&671~c<(rf25Kvdq~&a3bqXL)+9Ml}Q0vEYW}%BedC~+RqM_0t!m5a>&Kd9i e4Mil1wEY)iJXHMf^z6|90000&H!omK`#}Hz0wPI7 zK~yNuO_IH9R8bJc&)hrrzPFo~-N<5LKqI73F(6{6g(*akV511eK1B-u1hr653wsL@ zTN||yLqL#Nsg)!k*l55QlZBA|-t60ZXDr^DINc0$_|422s;{pQS(VUlZ>Z|^`P*yL zO#r4u$)vxzIeGu_bJak^0Akpq`ufVldkX+ozc)ls$#`R{w>I5`!HszI#PRX^&Y-&& z06co~Ohp(#>dn8s=uFmOrc->m=qx_CNrDefDzcSL$u27jO`Ad3NUC6c&In zhDSM>#rab&-ux8N{{$xQ?*bs0kavvrrT`V;lFF^QsbbwxyKw;W{;o?aAcMjV09O{4 z0mK+ZB!s}ss!Bx8xjfH_h=@MDJqdsfCx!^X#cQ<~qcQwvb0^EnWF$$P_pa6I5z*&& zO{f51BFjtwR$lD@AR<)-y38CxA3#AE-A#rJpqjaYP*lt1wAt*|YL!;23!u~Ki|Ci7 z7J$)fSbIPKV67bt2F#5ZqpAWBk$ng?wpIab|9D>*2|!}564__$vwr(`p(%VgeCz@> vw%4E<^0r9WA9Q4;%S3`|R2iy>u^zx*Fc$+3DA?fI00000NkvXXu0mjf-nSs; literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/beekeeper.png b/forestry_resources/assets/forestry/textures/entity/beekeeper.png new file mode 100755 index 0000000000000000000000000000000000000000..71d72af98f11f0b9402b1a52d4ca2e624c01d17e GIT binary patch literal 3951 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 JPDHLkV1naIdprOD literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/bees/endBee.png b/forestry_resources/assets/forestry/textures/entity/bees/endBee.png new file mode 100755 index 0000000000000000000000000000000000000000..56a840c8973cc73fb0c5853dec695c30301be7e2 GIT binary patch literal 974 zcmV;<12O!GP)VGd000McNliru-31;8H!!KgjF12T16xT% zK~!ko?U_q!8&?>HpYLcaTaJ{Z;M6v8A(+zAMGB%?ghF=t6Wxj~O!rx2*IgI=172y{ z|ItM*RK;lnA*96^+D0a6>-eghHE$RBrWqNJ>?BHTDgI!XIhQ%-yzlvLXU52quc5wF zS7o_kETrncWvnD*HPn~tnxCJizEl@uEP?l2&ImXoV1P6l4JykO8)pLS`;3O0ylfFS z4}Tf;l}3_)voLrT28SnWw>nz8)lpV?tO*zd{4|pg4Qrq)-{o!Yya`}^OE&T*P+6{6 zqtQ6_KneKt^Hd&9z!SXZ$|xz*`O==k;BG?f_E*#`z?Jm^a+*;J_z+ z`bjTaO1auVOHv!?npymUfUV2HqZphU)?>`NsXil2V4R!O1cDmAnBZIgUoCL_}9#y0neR? zJu~Y@jJ`y^`$b8!u9%-nx@>0K?iYGy_LHRGKA`K?+Kv9%*d1BquKtmmKneIr(sfA- zl8|&AcnGv5T@4{5zPFiJZ*=3E2c!PQC%Drq0w1~?DodISAx!mpy;2C_S2LRhJ_epR zVPWXU;S(kyavwk($LnTRkdzA{Bz|E|Qpx+}-pcoY6O`EFeA}JdHn1b9C28Btc7T?d zeGc^e8t!rUgu%Cg9pHCh)?@rL;4dKd@?+pZD*uW{o&YmTvb>H1TMr@pCaEW>U}l$q zEi>COvnRkG-Y?0<8Tn7%8F|1(U{O-h%r=2PJr8&~j(I?0`@xf*u7g|$lDOYVWrBO& we>^ncRnG!`|Nks7R)2l6PJ_uw@UYY1e+U+t!Xn|88UO$Q07*qoM6N<$g5ws+)c^nh literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/bees/honeyBee.png b/forestry_resources/assets/forestry/textures/entity/bees/honeyBee.png new file mode 100755 index 0000000000000000000000000000000000000000..56b22c1197221727aac34df9f43a9c05ff00a7f6 GIT binary patch literal 1043 zcmV+u1nm2XP)VGd000McNliru-31;8F*Nw}?+*X~1E5Jn zK~!ko?U_w)8&wpBpL0Eq?f9c)<2zARJ$R9v# zk&r6HnjJ<$R0;@?P(+DClO}BvY>z!NFALu(b`&Qm7!sSD&Gnr*bMHCtJ)hUcFnS;A z%XQUOYQ{p}^N*M)a>HKKm+P9JpQpZD7ZXg5|2drla1Ou`)MzxQt<-Fi0kDsUytvI@ zZ^Z4xKSl$yu>{~e4W6gL(b1iyCEZzC(y;kN18|h$XBmWGR11B$x@y-K0|9)$7TMUl zKy9UFjYi|d3#H2U|ISaL{1j)}1xA(zuPOvy+yT0kS^31>VIaDFPxOGPCIK zrNMPScA>os+t0)0ZD7lrb{DESpaPlJ@MQ`&MsLcJoL4*tdX zbOXkp0)P4?Nprvg@RFn}X13?!LTqMVOL9I2bbHZiOE}wVfEnPLq>`CE2JZVh-~sT+gU~dyiKqio z-*8k{ro_{hd;AwjSKR)RNChA|GVclTb2_DuB{s|4NnM&w@{XYNz N002ovPDHLkV1gXE;Mo8G literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/bees/icyBee.png b/forestry_resources/assets/forestry/textures/entity/bees/icyBee.png new file mode 100755 index 0000000000000000000000000000000000000000..dc5c5a4b29fd9dddf2b23412d18e97bc9926c384 GIT binary patch literal 981 zcmV;`11kK9P)VGd000McNliru-31;97Za6yo_zoS17b-; zK~!ko?U~JP8&wp?f9HDQ4`S0e5FA8GB~+{Gq9DY!-SGf^29y!`p!Lb?)m;08(FXp&5fq&n{{I? z_54fb3PRRFbEB!{1O)NuXW$>&FP7iL}ly2OVvi5VWfa3%|%}R)-Md*vq%r0Mu1n|@Sq0M{<)HmzaYPBXN zln9^xUCg6mo>LtHQ!9g)FD#4+`pX}~G2Cwdbk<2rER|;R?Q`Q+d;Daa`CG9B4}kNj zr*~iN4JpaKkNg#1MJPgMbjU9?;}8ZphpVFq6YXR9sXHt-Sf4RF;@ z`oII$s~2B*|5TIUVb?5|UL3RgLI6Ai-T)o}H5y?O9{&cexbs~FdO!=P0V`7zOws`} zW|k>aBz@zkrv*EuigVjU(3hY16M+g~qCbWvittT=CkcTcjJD*%hYlB5-&DrpfYN|KqiftHyiVG#o(U=T6;5V`fs zl4`&ja7og8X4dh%Ffz06Bn8g_11~#+=&$y(nU&n#Kk^W$0OuuLle8uYN!NfMfu5u* zA%vla!5**+5Pkajomv0l6FdaUz&pS>;A2UJ5JGV@8dX9FKbTn!xClISg@vh)!zZkS z$a4U39B-RhNm4F^kmQ9`NfpP-{U_f8P7q?R$30-z%sRl1q^_inne6~wGyBk!-)QRN z@Cggw19pI)ftuI&KY`zY*!OpVJDvmjNgbbQ1(;dV<@H^#?GQp!(nwOt%vOM>X0~Hy z580pKI^Guy52nFc21yIv_*7DTz!LC*q_UYk0eU;6iQ# zN!{BAXpAQds*;&BXgIQp%{`JY429rtfsA=#YCe)3Vp*R0G00000NkvXXu0mjf D)y%(` literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/bees/sinisterBee.png b/forestry_resources/assets/forestry/textures/entity/bees/sinisterBee.png new file mode 100755 index 0000000000000000000000000000000000000000..2ed19dab10a3cb35995bac54413c6e3bbc265683 GIT binary patch literal 991 zcmV<510ei~P)VGd000McNliru-31;8FgWO0l4Sq@18hk| zK~!ko?U_4oV^tJ|zjb^Q=iy|6MMxq-gOI2|Lbx5ODG&|S2vI{3A<;2CJyWAJ^fVMm zh=RX>kq{$M01X1hfnk!#V;np7^`c;3#*X471BS#VTe9x!oOAbH`?2=97Q^IisBhF= z+pLN8zWeVpQIdu|sBhH0wzfunqi!Zx6903#0^kaOQ>4*oP}{6&k^#^MLmu4X(Gzp) z=tVp4iftBW$g)}A%?DNx(2snKYh zd!fSk{_~k>JTuLuPJxlp;Ob%;F!Vud(C*gJ<>W~fp6XZf$!mjN`+av%`7f$+8)yQD zKqY>!ZV!h3uysDG%DXXt1!w?^z?(7utoM%;fa4)rnLT-6zY@n4e4H^KmBb>j9iTOV zGSCBNfj4rW`Tmg>!Q-J>nLRsaKQ4)7;6Bg-O28g)^Bn1Z5Z+z^cEj*IiqYOEDcO&r zQPNPwGW+FIwU)jTz^7IDt=w#u#6c*%0~mNWHy@V7CslbVjC_6jWG0xd;wCU1bLV26 zHn8*$J#D)LOa;4Tk>a-91-d|2QulAsU@wkKvFg1rq8#_@+>If5{>sJCeHQ+i2bOFv15enV2WD(r(hjgK zsYr{W^mH=DU$XFi#r6uY4m@xBX-WH07jj8o+D=geI=~Uo$?oqw99zpH{If`b1>hOm z*KM!c#`bmKTcB){nC!+ocgFpTPl^<%08atefR}8SQ%W;=o-d@7zLB&7 zJO|tjz|zRK!xs!f7BzrgueT*>)^;hSRMdr4+Y2$S^sjsmxIpOz1Gj;uqBT61`N+4!7i@ex`mY~=mEib$z%M{AuD=8BL=8A9TAQ&3KvL1=9fe_ADW&gi z=eB1hEdzU!4kX`hX?iS=$v!yTH%U2mA&+2oRc*CZZ20 zaz6o<)CnWEfP(jr`Z~d8jGv4Mc-*}}9RJ!2Ow_+V!*+wkPVl7N;2#Q8oVstVL6-mk N002ovPDHLkV1k;0(gy$l literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/bees/tropicalBee.png b/forestry_resources/assets/forestry/textures/entity/bees/tropicalBee.png new file mode 100755 index 0000000000000000000000000000000000000000..a27300cc3966e4db44ba764a1468fa2f08cf4fe1 GIT binary patch literal 1043 zcmV+u1nm2XP)VGd000McNliru-31;97c?+-D;59%1E5Jn zK~!ko?U_w)TSXLxpZEGEwi8=U6P%P1R8%6NR^m&nD>f|r1G4Xi75i=x>Xu)@K5LYJ zzycu^DvAV@ZP5#^ZI4saq5IPNrNG=$&swNbLZSSbKdhcGZusBeOO&yb!nv} z7W>|R#8^=@Xkc}D)e8#?tS+ybF{X(BIb8y93BWN_E|)2-lr+u&=;HwccX>8q?jHRy zKF}LU04~emWf>eE-MM$mckbQtp#E3`aGc^78H9LP6MgdGL*2X{8{nIt+Zy>0D6N!K zE|*U|QBV2)=gcI|Omd+^U}$CV=JkmKivGCPKEPXVUd%eFo~8O1`9k5K)i!qyF22*k zYKeBn#Jhq?sABR{2l)ogQ?BE=v`B40b=FKbKxv`ar;OBc5H^^yiJO!hm+N|nA4z_#V38MD6Kowpgrvk4UEy6;m7 zu+??ze0;RUeyHPX3Dl=VVW&G$EoHI=kt8NgpWV{7Q@}*1ZgB{41MS{VQu|D0uu$u^ zsRSAo^H~kveNnL0egD&jd8H^)ImqqH{X5;r^b|Zi?tfzKC@7u=GNGO51E2*ofV%Al z(2~^Y0m6*Kx22kYl-F93_cYqnpKR0(+@k@UIkDCB@vNMo(|&nHhuR`cNgaR`At z@UrdOwij(<`!?_pXxM%|ilTN1gBq|05Wn}qgHgZni9!hEfO((*ylp!jMNuY6l6(|J zUrAa3mVn0ruxOm_1f$>yGq&k;I_r|Mwo_3Q_42}1+xftk`d97)&XGEy&NqNPNfn@K zyKcK8sS4C3y%CaMGW6r{IV;})s=)WaLa6Z@!0$jO^uGljgdETe-;Fi^l5D#j6siF0 zQ51b=JF%UWR0MVNn~YUU}gyL32_CAOG-;g$w*7f%E-vc%F4^hDagw!DyXqDX>hV=a+o{u@^R|%a~TNo7z*(k3G*o^DJm)}si>){X{hI@vgfLC+nUz#m6Khre4YouNjH{L?yRRh*v@#epZDRq>&bA>i{ZXE<3nHOM}91i{aK#`ussXn zcpl98B82N@DEF%{o@+O6+_-(~=AGNO?%uh5@9v%Z_wGKpfA8Ug`;Q(zc>L($lgE#q zK6(7?>HGKZKYaM``Sa&5U%q_(`t{qlZ{NRv|MBC;&!0bk{rdI$_wWDz{{#Iv3PwW! zYY2R4Fr%o3R|8Oxy~NYkmHjTO zkPwS*-qh$QppaCFYeY$Kep*R+Vo@qXKw@TIiJqTph(ejMo~fRpfx(xeg}{)t@^oA560j z@Fp@U-rtiZe4681i^G@Sam&mv9C(v?YZKf49gdYX@9%Eaj&QrsurH^2?6hJqwE)AK!PC{xWt~$(695gYDH#9& literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiBatesia.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiBatesia.png new file mode 100755 index 0000000000000000000000000000000000000000..e887ef66c978a8700067a2b5d9120f0aaa365a14 GIT binary patch literal 1546 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA^9hRZ3yBJfhzp5I2#ZOINyQ;f6J2ol_&qNNcmrx`oAjee{JT|ds6@JOFuoK`0|YEyNe1RuPA@MruyZ& z+SeQEKW{1ge<=I^iNgPVs?= zOj_Gs-0#=hck)c_xTQ8i-XZqazYL`{>!Dcq5e+30H=UUkQY+kiJF_ERawZQQ}^z~gk z8;>@zJ*(-}o%lmgj9Y3&?z;Q;EIAW4E@0fNIq63HrZ2rt4)?7;`)@lK*}-`F4|~a9 Y?u%Nb$1WJNfXa9VPgg&ebxsLQ0J_#&Y5)KL literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiBlackSwallow.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiBlackSwallow.png new file mode 100755 index 0000000000000000000000000000000000000000..65497b5bea63dcabf99013a5306811652b58f912 GIT binary patch literal 1534 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiBrimstone.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiBrimstone.png new file mode 100755 index 0000000000000000000000000000000000000000..6ce67f58019e052f1dd882cf7f94cacb653bcb18 GIT binary patch literal 1540 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAYjCm{3h|a!rL|b-ZnUQ$MF1JqbqlGuHMzXdt3Ly zb;FA{j4s_YzI@B%!ad__cg=6#G`@Y$`0j1f`*+Rn+&8)O!1VG%vn!9xuRgZ8@xb8b zL&MvTjqf}$x%<@g-ZQiN&&_WT;NgA4M-PmiJTiIu*!0;Gvj>kYo;o1>dzJIm<{nL5F z&RN^`FW7!y;f{lgb{<;1>+q7@N0#nAw*26!)xZ!N1;Zu;{JH1o0rLq%NswRg|B($C zg1@t?0wb2Qz$3Dlfr0N32s4Umcr^e8*-JcqUD@xl3JEE*Ha>Mc3KWtmag8Vm&QB{T zPb^Ah2uRG#E79|F4N)jF)-%;JG%)y5v=A7w9-c0aAs*guC%6Y63J`Hy+tIK$$y}_1 z)zwu~h;jEmg%%+P*NuPv&liZTnLM*vz58^J_xV>f`GwEUy)N9fXg_b^!^RM)N51L| zg^7(P{1kb<9{J7*WS(}q8PQbz@mceZ4GwNsbxr#pHvVURbcpHXoK4Z;5^{U^onwBe zyY&|T=JflppRb0uw2J+9qu+zw{Qdhc9N0Hc|JK=Tol{3RTAY{-V?$?OmDX|65c#5W z;lRb0t|#^GCI_miim#dH^HjH(vD?7TOsYjFBf+)W<4FmRq{#!F>}cr#MV$+__3|C+ zicS>?X0!X9Qa2p%S-VcDK+;5DU8JaSpJFrHyEW6D%$gOOS*3PoN$a(+<()peXyUCS zLI?FK@+(vnT6Y8rgN^WRx|sq dXZ8;)?AI5TaBdeg69tAmgQu&X%Q~loCIHSPYb*c& literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiCSpeckledWood.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiCSpeckledWood.png new file mode 100755 index 0000000000000000000000000000000000000000..906afd2bb62de4ff1ca60cce880b0de3565dd2a4 GIT binary patch literal 1544 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA^K&qY@Ulq@a>)pB%L?--i*hT7@vDmSs!8yvOY-Z;Fzd>) z=*h9_NO0;)^XSR&>dW$JNC{|43u?&->B@^5$nYA-@f*qu=&Q;YD6ktVbD5}co2v4d zsqq>q2pTI2nJ5XHDvOw@h?=X48EME{sEJ!BOIoT+*r>}|Y6{qC%DZZcxND1f=!kpj zN_go>dh1L17)bjX%J><{2AIgl*vdKTC^_jWJL{>q=&QOKsQDPF`WmbGnWzVvDg>D+ z2AeAdm}v%@YXwxJ3q$Jr|+I4UJMt0cRqrnsu5x~ZqRYovQg_F-IZ!75bgt^FMOv>HYrk2d^LDB3r&UJ4Fc}3SBm{Ui>%0f%6NZu?zu^BP z8!!ZaXIBMAJ721s-(?jN5f$q=_4W=>NUFp&q9iy! zt)x7$D3u`~F*C13&(AePq0Cs%RL{`B;7id$V95G-x;Tb-c)y);JE$o@!p*w9Y|-K= z(>P?;1~6~Z(cHd_bw(=trF;J^S9Isk_*woWCv8_w?Arcr(=+#&lM|Kpq!&*W71{I_%y}1@vO~gTfvLpqK*J*o8dql@mr~p9F12FgrMG%90#X*c zUWf4LwyLu5%G}|PUN-NTP!rp#wPk4L+I%suN_q$QjR8Uv!| m_WhOp!zJ%=re1+(Kf|G!`8p+)Ytn$B&*16m=d#Wzp$P!#qxon6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiCabbageWhite.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiCabbageWhite.png new file mode 100755 index 0000000000000000000000000000000000000000..734ac52af63f047432903c2e9685384ef7bc31f1 GIT binary patch literal 1527 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAYjUv~3h}zfCwnBMcqOHIC#Uo zN$e#2ZF|P3?TJLo1{y8vz*Woe!EY*GKPD4P(1I4epm-ie}x)L5H9l*p}ld^Bw ztMrH|$E;eMn19DTik^NuqGjvZG+D0&jbXq0j!L%4m>h^^zqh13q(MOA{C)Nau8A%@ zOa3jmqsr0v#Fz7wY$Mx^3#H4f4z67Mwf!<{9 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiCitrusSwallow.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiCitrusSwallow.png new file mode 100755 index 0000000000000000000000000000000000000000..1bf904c60267e55210fd0febf29928f2a2f9b2ce GIT binary patch literal 1540 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAvvYEAaB*_+aC7tW@bK~S^7HWt@C)*?iE*(D^K*!Eb4c-V zOY`#x32+Gua*GObi3xFw3h{`G@=J(tNs97Gi}Oi|@yiJC$_nzy3GvH_^T2?z-a z3JVE|2n&mfNQntZiVMn03du!{1O#^}KuD`~F4WhnM}p5Eum`HUt(|7fuD{6NZu?zu^BP8!!ZaXIBL#1kM7F$YKTt zzC$3)D5~Mr02E{|@$_|Nzso8jtSq}t;Y|flNUFp&q9iy!t)x7$D3u`~F*C13&(AeP zq0Cs%RL{`B;7id$V90uSx;Tb-c)y(z9o!Tk;ug%gJMvcOS|6v4Oj|WLPHg$@>l*O; zzkO@XkG7e$Nmc$ zVGFWfN3fjVS+s!VA>Xa&T%V1%_*VopWT9e&NDh1pZ_{5aLSn@NAlS^ zuIG--(uwbn$|QVP(0J#`Uj0;W$atg=2n4@TaTLsr?gAVnEl^Dq?R%4T2AF^ StDB&ZXYh3Ob6Mw<&;$VA!2at1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiComma.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiComma.png new file mode 100755 index 0000000000000000000000000000000000000000..bf9ffb271480a26d4f6e7c821d3e98ebfcbe08f7 GIT binary patch literal 1535 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAGcYkSGBYu=vaoTmvvYFD$O>z4vM9@osVImmDoH4-NU14F zs;Ek*!VVrEsG|ho^h7<8E!W*+-YXK+ro6OmHB=f%Y$~-haGH> zI@uq0aXjhfeA>hHte5+FAJ2;}rdK^IANv@-O=kW+h2_Uo)}PbZeobfpJ%i)VOwPZv zxc<%N26=fDjD`R>1oosUyaDDDhLRw^;Qu2VFa&>RR|N(NXMsm#F#`kNArNL1)$nQn z3bL1Y`ns~;WfkU-wA!uy*$F5lRpJ^^5}cn_Ql40p$`Fv4nOCCc=Nh6=W~^tbXJ}yX zrD!2AWSu=-978<3-%hz5)D$4$=BRD05mjclLRP@Uh#iL?Ds|&bj-sZ^URKXUW-tCpzRS5h6PZ>$&A#BncTPdmXMujiV>_GfZe0(q z-)!HCGpBqOJv;xL!{yj~iz6o?CkdjA`?q&z(SBw4#R;h`l`Zon+Bq*IpzPS64QclkMD+^ep zEatAO)yv_r%XpBHbewUHu+$IMdifXk94r!Nn~YUU}gyL32_CAv#~I;vodjUuyS*<@o=&8a&z$UaPsqV3Gi_X^79A_@`(uX zONekwitU9Pbx%eptfwX&KLt zWeh);GyYn^^m`@qpH(b>SF`?G!}fnI`~UTv|2J^`-^dMg>L?fu0qTapQvMlVfcb=> zB*-uL|HuXm!Qa_cfuYM;;1OBOz`%D1gc(IOyc&Rl>?NMQuIzVN#rZikItm3lfkILx zt`Q}{`DrEPiAAXl0g0J;C3=3YAqr*2dZv1Y1_ob>76L<7)6>N<#KZgTq?>++4Fp^{ z6}4NJO}Mf0@}?=Os=PM}4}JP?pVng1HDe`f-znwiFJtUwZcgeyqoO3A(!w??UBKFr z#mI?iwxd^ob{!XxW&N~Uc1N!XqoiWvF7K{Ka&4^!EI_tf=}*b##Dl-zaxR>M?pP;A}7;^P3Y2 z9QJmxdVj0CEq=8t@_qwzw57qu?>FmM*w3t;X1GFG#bEA!ew%9weHR+SL;cHqD6FbZNwfC literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiEmeraldPeacock.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiEmeraldPeacock.png new file mode 100755 index 0000000000000000000000000000000000000000..574cc22d1f685fd8a4275d58680b49b9b252c2d3 GIT binary patch literal 1544 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAGxIaB2{W+EGH{48aEUSSNHFk9G4M$<^2##^$T0CKFz~4` z@T)TNt1}2FF$k$Jh$ym)sxygevWV(3i0Ls%YO_fiGDsOQ$e1w6nlj6ovB;aVN?9<- zS~JMmFsO4dYjLwF*fA*DGb&keC^;}GJ2I;{v8cJQsk^ePcrvJZF{t}6Xt;4`_%dqx zF=_cTYX`9C1hVP|vFQb~>xXdEsj1bgtCxPSEdNyh zYBp(UHEV0P>gu-X>2(?!EcHY)I`P=Rm?6_aF=W$uX|CYx8t-#P21tTg146NSn1?Cfmk|4j}|05eP z1b=5&1x7w+fk$L90|Vb75M~tB@M-`GvX^-Jy0YJ86%iIO6`u42RJcf$xJHx&=ckpF zCl;kL1SDqWmFW4ohA5O7>zV2q8W?;jS_lkTA5Ry@5D)LSlWzw#1xUDci%iwgUOZV< zmc>_K^CcZ8U+auAy|wrLJC?=P96qz(@mA0FwbIv)AC*cou5Jr_RN<#^zrEr^V+#-G zv&iO(0>+&M8+dq+R5Vl+G%m^OpY%bY&FV-qx5w80?bjz18{{d<#VFXx%s#H!!|?A9 zlUVrLFfl)ad0XmIH!Qy|`hM#{y|{l)%#+s4GrL=<4_Jm#BZg^w?quKTqs{$N%IF$Tp zJRm%yM}L8eLemGvl_4DaFWAH=e5(|xn_qjup~$9ceS2)Wy~%`4Z>GDmI`c@K*mCMs zNPXhkt7g}idMx)~)=v9<`pzt+3AQG;#lw~aFKIloFLCENooNCl2a2qhu9|&Jpox1! m@6|g@Av|^hGygLr+dtZoeq@1CCnqrU89ZJ6T-G@yGywqjMHRjP literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiGlasswing.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiGlasswing.png new file mode 100755 index 0000000000000000000000000000000000000000..97038c5992e2c1fc4bff4b9ad540c950fdf942da GIT binary patch literal 1506 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAgP4pg49si{EbNS|9L(%oEF9ddoILE@e4M-jQj(%F(&8GN zEV@$S`ZAKnBK!ujQi=*P#tO2gO7a$}NGB_rfUk!&=Q=fEi_97wq^^ zVl)KE4}teR2N{9+grOwJFZln+1`NU9*;Rod$ywkLSKPgsd?{K83|Tc# z7sn6}@3&Jj{hJ*G+BR-knq}L~zBMk?YjsCg`rd#4_e+UaI2#?#N}pW!X7Zb7vUWC- zZLu~*i-Z-fcpS`VNl<^GbcN&KlotXQySA@rKC))AR#c|$D}~O!&T|0~FV-ppC0jIj zCg%PqO6ygerFbKgRrdb(ZP#|yRWIJ#-Oi>r!&dxv*-X`&%1rItd0n~ddnSE(^p0`j zL00|G|K`vCXy^Q(;NXw!|8ri5iYlMoBm$K9cwGIWDVJ=F!{n5#eM`8V9-RBcdiejk zCRR-g-TuwYP69JaLtRy468H|LmUKI{zfh0~`Ojk8s~Gm(kzf3cNc1}s*NX=oH`-1O z?5t^3%-z>NF|^>I^u@sc>1|%EFAm%}^0U0hskNrn;{05x430UGoE>$Hd12F=bSCc) Q0fsAsr>mdKI;Vst0J=Nwxc~qF literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiGlassyTiger.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiGlassyTiger.png new file mode 100755 index 0000000000000000000000000000000000000000..724ae86c9ac0cb66103834bb8c701698fa4427fb GIT binary patch literal 1516 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@agsfPd>I(3R2di=ni&{={s+=8 z85l|p7#Ln9FfdrnU|pA>)8je&ugA;2fZ6{ts^jX{ZnMVX65g^NvyKPgsd?{K83`P@A7sn6}@3&KK`W*@oaSe5O$-s2=(TN2sL|6k| z=4^;?`1@b}*0q%7CoRMFcJ!}XzSVQrr8yJy67|-|s5-K??RE6{VCpNYj ze#_)Vi$fGQDJRZpj;N1#L|2l12~AA8pSN z+1V3dt`UEo@8enZx5mFZrdl-_-Q|#Nh>v-~w*P@W!ye}7XZ5!d#kO*T5~`=GpUXO@ GgeCyf2;Y$a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiGozoraAzure.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiGozoraAzure.png new file mode 100755 index 0000000000000000000000000000000000000000..208cfad44e820f1c91a37d54134110c9b55efe48 GIT binary patch literal 1545 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA^YH2O@*D6A8cB$$OG|1A2pJ0sn+S=Riinwuid%?DSZedI z>+*3b${Q%DE30U#s%ojJX{)R2XlUtcD=8Q%D;lXN8LO$7YN(lOYg*|V>FJvoSQ=e-v=%PFNQsH7{ZW+o#iYH)|QRXdAW~Tdy&( zS?l4q+$&(Eci<|&khK9}>jT3#1VwBNj@%R&u`4)gPgv~!@VEmJ@dqOl4n-$jicPr^ zmwGiZ<3@hT@q*G5g=Hs;%1;$noGz(6Q(ASltomGe&H3c)M=3dv)AF9C=ReCRc%E7K zBCF_ScJZtF*2i7VQ+isb^|jCF@0dBMd(NWS>lV*hzhv%)rSmo}U$A-QqOEI|?r3Ox z(%AmAspDC5=ku1X7p>hd+j?HL_rC7zf7>HKXYKm*@HXJ z9olvN@a_vI4qOF>?I;-JA&}bn{XE)7O>#E~_xR0w<$>#ATq6REcXuNpOBzNqJ&XDnmeGW?qS&pKFLhnX#U! zo}q!km!gHhkoEO+aSZYBemlWE_)vg|TWH7;K8>XOj;`1ZDoLHO&72*)+KNr0CO`hG z@A{!;{N2|r-fjB4t3Tg8(#dOm$q~S3) zz}hNGQOrjn=}zk8`yzYn|0Z0~5d9*{Bi&>x!2PYWIZJ6fyZV-p>e;o8$F@n;U$}j> z<*~Slfoaj|C-1j!)ZpDJz{Q&*anw8Z_Hm^v*LP|!WRVhB`nV}>)Bncf%nL6Zxbtb& zr;S$4t_8bS#RM?%esOP|WYB$(op(kp_amDr!fFrZ?B{P$Q=GG*v3rV8n{4>`WkpJxOzlLrZE}~c=f4*c6E`Uc zIAgc`+T)0r3kSA*Q1VU^>E@O)NY-|5%;Dr_+Q$k8|r`J4lW{~0g;Vc~jRzL<;U Sx;8NQ89ZJ6T-G@yGywoQmQ?Nl literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiLLacewing.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiLLacewing.png new file mode 100755 index 0000000000000000000000000000000000000000..79c37d0d383d9d8aee6ac408e53d06425a9a7aa3 GIT binary patch literal 1545 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAvoSDnFtBhjvhgr;@Un37v2yXVaf`As2(a@Aa_|aq@(FYC zOK~$u^DxNpGKg>si1G-E@d}Ca2}|&c$n%Ja3kt}IN+}33Dhe?v2{WsRvg%4R>B%rF z3rH!5%cuxSs|v}ei^yq+${WhFX^JUmODO3`D(gzA=*y@XDX^O;ahj=cTd48cXbIZu ziWnwP|A6^g6BpV)6H_`J5_A= zYdH_(X}ry0cv8snsgU7EIm6EihCkJee`}cj)iVFDWBFgt`lN~PQzOIYCWbG~4BuKA zzqc{{XlMT4#`Cj-KZ|DV9~eq7L1p<4sDs37#UZE*t;; zzj)Yu=Fhip5{)aq%)K}L@a((2XEz+F;z&BgCiP08X4@eFVYLA5pV13r7VQQyFW5~w zvE@Lei%18ja6wPH+~uzlGKU0#oDJ+jx9*yRDI43w(4 zx4CupVpg3)GiNn~YUU}gyL32_CAgP2UL49si{EbNS|987GS%I*F zGNK}~Vxn^5V)Bv_iqcZb+C1#~0^AG=Weh4+464e zxzC*Dzi?jg(q-W**F~@07Qb;{^44SNJI`hBy_SFQS^3Ft^%ws&Ujx^DPr3X)m!if%$}?B*-uL|HuXm!Qa_cf$_^(;1OBOz`%D1gc(IO zyc&Rl>?NMQuIzVNg*kNj6nB0BB?GAv*NBqf{Irtt#G+J&fW*wa5hJyShH z1A{L`3xOf)>gnPb;^F;v()FN20V1xs8eBKH#Wo~1OJsK~2r_Zq7(PYp)BpbhwKpcu zEbcKjZ|+~WeCzwev#O0>esnUN)AZxRfsIU@X_ibM6B}!GT5;f_Wb_IJLYWDbF zVPqY!{_eS_JZ=nsR}09CY1}aHy`}EPz|AZmU#EK3WRAOq;v^|Ack$(Hm-l+tuFRCF zb7sC2xbnr8c^fr41vy$-zihf(^ZS6(5%=We04ClOt&48|d&(wU$kEDH6!h^8xHJw86g$JBjph_ zH!a+}V&(R=xAXEoJc*M?FL2CwupwF9 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiMSpeckledWood.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiMSpeckledWood.png new file mode 100755 index 0000000000000000000000000000000000000000..fbad6dc8ab6f25c40929609b1e794662094f6eea GIT binary patch literal 1526 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA3vsgubFm8Zu!{1q%L*|_3UEsa@<gQns7VQ_OAD(=imOUVs7Xtz%SdU-iD}D=YsgA# z$;%qb@|h?InkfmJD~p&ai<_xPn5#-!tBBaD2-vF$*{X@zsf$~vNm;5(TWQExYs%Vd zNZ4q}*=oz%=_ojBi8*LWI%-KdX-hln$hhiAxai8d>C1Be`EuO;P33Jz_h?w;1OBOz`%D1gc(IO zyc&Rl>?NMQuIzVNg+#=dcG_ko0fnSWTq81HGa4k&WFm zsvRq8^L|S0^IIWGj*(Q|n zpulYAPG=s=j0V}cds_lLcQ{o2vlF=Mr1Fq?XSw-Z_XkYbYyT>EE6AJd3Y&I+$Hl@m z=LOqjOagME*K+7_^5%S#YBaAnI;n}RZ1#O${W(dVj?7E_wm&~E$>iPm*nP6Mj%G$f x@7@0P9}Lc1dI#Rk)9+hY^r7*}A9jh~jI}GW)#TY4`G8@~;OXk;vd$@?2>?nV=DGj? literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiMalachite.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiMalachite.png new file mode 100755 index 0000000000000000000000000000000000000000..396d95959d7c7d80a4aa8a9171b9fbcc440a45f6 GIT binary patch literal 1558 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_A}Vq|1uVq#`yW?^ArV`Jms;1J?x5))<<666pT;uIC(mJsET z6yuZ<=aQD-mXYL?mEw|<1~PbLrFi9}`Q&AI2dI?5Cb|o_^MG?sbQ`*PQ2G^qzmi zb-^v?1vlLm-|<}XzaR3Q3i?MwA5Sr0@bvK0lOQUf0Zw5|REA$Rhmjh!^wf`;KZpN7%k> zE3AJVq9Ha*^XTFD6%Q7#K79Jy_X`@QKXZs^bxdi!8I{J|yJ1SldIg~s4~{Osx6F(= zW6D()rdBStt9MFQ&H1lauOcosxr4>(&X+$0H^W<%*hEiU?Mm8RUnkQSy^+f%f^{Q@ zjb6XP-4bi#g3F)&uD;*3NvY4lI(3R2di=ni&{={s+=8 z85l|p7#Ln9FfdrnU|pA>)8je&ugA;2fZ6{v@ak&&5+iG`V&jg^&$o10fam`_lI zUr1DtjZui5NtlC4l#5l2n@yaDO@fzQf|o;*k3))|Q(AyaMvz-hm{&+tLPT6jR6<%@ zN>)l%K}KFlUP)D1fKye7TTPfpU4&OdluuKPUrSs-TS8DrQb<=ySWj9+Uq;kakiklf z)lQ1jUYg55R?JXN+(=%+SV7W6QOaCN+DcWn#~JS}|<4W!PfJ zu-uDdts~oNXU;V)Tx=w=wh?FfcDkqq~u7#_wlJcwm{6vy~D zp6O9M^Wy}TXGyHjli8jnv%g5?e3{1ea}vX!sf>T8G5w#x@_#1l|5YvSqf43O@+iHC6+SMC3uHU|W>&~6q_wL>O^7`hlkN1Cndhqwlqkmr?|Nr&`7=WW- z=!QV$I>t2&42%pVL4LviM>b#x{>~08HyAhzJR*x382Ao>Fr%o3R|8N`s>C&-Bsf2< zq&%@Gl_4N8Gp|I?&oxA$%vjG<&(Of&OVL7LFuHlVIEHw5znu~ue8@q`XFVKu}*RAL9c!KbrasSpGaIU zz^`bqYpXre)I(W{a!v}{tR71gNQ%ZUG_AL(pLTG<2Z@FXj>Z>XPP)Eebar~`{A5{a z9lQDl@niE=M~3<~Y+RndUx?|OOPOk6w`1pVMG+|v*Gs#1mU4GrkX^&?#A&iX+_|~h z`*y^Xd3+qLY-^4=9iFf(S#XzC_3H&JQXYG5U+g#JF>P@+*`ZilSJ~1~|IhA#rHi29 z0dxLI0j4buY0B2p&8r=mZ@s+Zw~y7CS84}eyk+-UiL46;{w`hj)0#=KAX#sH@Bb3z zsZPv?xpy8usV42sDOIqnkL{4FFpzcOZON0(u~qU@n%VALiI&#?qxRri~6@vd$@?2>`?{9+m(A literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiPBlueMorpho.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiPBlueMorpho.png new file mode 100755 index 0000000000000000000000000000000000000000..3ac7ab9ff7c4715e025146071811c01d9e7dc610 GIT binary patch literal 1532 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA3u|gh=;=x7>q{9JNE;f;7#YbL8_SuP$eWsKaI)y|awwRY zDVm!rTUx5y+G;r^YC9+Cx~3R-q#Jr>7<*@#_+*>;-C9D9^?;z{<&r#Yvd<(__?cjiU@*_VaK9~PW@ zRe1h&(S`sfT~;As2Cj96j!ZxysS?+SlHmNb zlJdl&REB`W%)AmkKi3e2GGjecJwpS7FGUN1A?x7j;uzxL{dUUjpr!x`H*KM6P1ZS;C+M`W@!EmwdcKJX#ntW+3mTtI zm^t;9so2sjj0-O`e6@V>y77ai$o1`B0ZhC*Ca+g~op8dDd7^Qt(ETI#3mU)tseN#< z)#DKRyBpr(TI}`0)oB-+PCGKEKU{lIhsQGG!G=Zb#&Z+)zgup@Aa1d0T66g7Mpahc zIazJ@>bGxPvY@ef^()u>DSwimEodzEPhMQOYJDf0((kv)Hgi=4Y|YjE11x_yWc_0f b{K9)dGViq5%U~s7h%Nn~YUU}gyL32_CA^9pbZ2=fSv@Cu3Y35)TIhzp2H2#QMyOGt}I%7{wIib>0f z%g9UU$x7#3>etE-x+Dw?Y)8EI)4YipY5XqoD2Td65p zt1H>5D_U!**=Q)+X{p+4t63Q6Ss58PX{$QxsJZB>JL_vTsByRJ3Z34baB*+iuZy9- zFNOWR67m0f^#9xO|L-Kcc^vTWY0&#;!5^N7e0&l5>1EjGSK(h?M|^z~`R#4g_jl1h zKg9m}829T}= z&;R9r|F8J>e z8eR=RLG}_)Usv|KtU_WMtf>+Pmw-Z2C9V-A!TD(=<%vb93;~Imc_n&&t|1C##(JiD zh6V;-iWUMx*2UAsF~r0B?SyD^ra*}{&q+dEPXbQ-^vRkvOKPEvlZ#65?uY;Xcbq-C zJ8fagdpEAZq1$ z^M`pod|Yql)qguT&me~5mm=RQPPcu^a)vP+yua8#?TUG0`hX?=hPm9g_w7u|3r~EI zv-{`3d@<^0SO>e#sYh%rPRzlfhpRS6N3{I7lqTb~pz-JFNq@gStZJI`c#lHhc?l=` z14=q))FuZo@xD=6r5+{L%+7ma>Wx~qQ!bnp&)+k@G->IS%9#06WJYRV}PGP*!H0Q#Ek)Q3cHlzXCFy& zWNx=yC>yW3A>u-Vjn@2Y%eEUvXfV#)+nMKBxq|WhAND1G*o?#rvkv?{{T~?W44$rj JF6*2UngE`QQf>eM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiPostillion.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiPostillion.png new file mode 100755 index 0000000000000000000000000000000000000000..93321698b3010a5dc8a622e04c28c2fd8d640adb GIT binary patch literal 1536 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA%Sj2!%86)jvgiwNE64~d%8Dq}EiiGKjhU<$( z7>Gw2N<=Xz|YtW0)Vo(2%XQAd+EW z6vN^eh9$9#OXHZ9#WOEYU|EsKx-yAvRWkeP6pl5ioa-}qc4si`&0^S}!+0Q<>0lo7 zp?sFZ1*}I3*^U)+oG)WIQOb3)jQdO_--U99ixmu)s~E0SGhVG>x>n14y^iHZJ?qna z#^;61%h%SfTwi~)f$df!`|T!RD9T7Y3S3Wiw-Xmz{+<_$)Mk|4j}|05eP1b=5&1x7Dtfk$L90|Vb75M~tB z@M-`GvX^-Jy0YJ86%sSFwy$hS1PV!&xJHx&=ckpFCl;kL1SDqWmFW4ohA5O7>zV2q z8W?;jS_lkT7f%<*5D)LS6C#6~5=7c=iyH^u7H8Jh(Pn1kzJ1~p*Wrwfi;iCV|6h7V zcliv<^cl~RUu}B+s&eMTnar||I+t8MIQXBac$ggZ^Wfk<@$0yX$)rM7p+ii@&w8y` z`;!VKfb2E9$ zuFjeHr{(fhw{}NN31M?u*m!8|YYFv<;wrm>I5isCQkGxbbAf-OhO?6RmfGvq+r1)M z&SYc>cr9q0-oE?V%tl2vUY7T{`uBd@2+ZHl?_uO3Aa|nfRpkl^9fO3p_5al-Y`uEg zi_w`!%3{U(+$>8T!-xf88z0p&a=*EKb(6XLYZkc;ca~WNn~YUU}gyL32_CA^YZia2?+8F2@7*Eh;TEA@iIsXFi8nA%ZjiG3X2Gd0FkJW zsF;Wt5Q&S5ONdDTk))WUl(>|%gp{()Sx57WuGUvQ?Qi-z-wkws80!5r(*I>_@Y}@jkEzjL zGvjMLVo#D|>YAFhAOQ1nA#U zFd72z5GV>@O#tQ-hLRw^;Qu2VFa&>RR|N(PXMsm#F#`kNArNL1)$nQn3bL1Y`ns~; zWt9__5l@_U-VP`vRpJ^^5}cn_Ql40p$`Fv4nOCCc=Nh6=2F&Jqh6V;-iWUMx*2&Yw zF~r0B?Ua*#%>fc_Tcfr{t#J}`xnlJopykmCo~u@ltM~oCyr5fO<-h1j)m>lKoIC!A zCGW&sZK;bdoxE;1Omke7xq5<-+JwrF!drwgxq}X|%ws;ix|%(c8OV$~=6w6Qp;m^j zlh=#`yHl-}^#(TXV9`wE|9H0llHi;Tm*U=X+AiL_W<^t7OMCo<13tUYs_`p{J^jJp zw6IY&v@^E4!&O2;oo$K(Gxx+rOCPd|J^dg8l!`SMId;)XEU~^I>?g0u1))7IQw@JC zXiW0u`LUq&s*4b^-s2Wc|E?H$Hbs$QpBZwv2#idZEn+ zjv;9GLq`Da4I`aF)H%ZI8pT{8+&xBhv*mKRb@uFv`1s0%1RKLt&7E7FnD{-bU+afT zzpf zD6=}-oVBIUTw*FNfK1c+zs-zRt&iO?k6FMZB_{fc?Od`M8da)3J>%bFX-1b~(o!+D zshW;XR<)!=P}zN5N;ElLVWmH?tnJbLlH!Na7qo|%j%%Y2-qxQ|m%f~6kMN{U7?`=_ zCEu@zsZ`W_a%UPJubd(be}1K))JP4B!<7Al=T{fSO=WxpCt`D%*Jp&BV9iKxwDF1H zT%$jz+z@*m3-y$Xy5EuWBYHnR4Npl*Smwi(cFRS>=H#et39iq%O+sm(Lef-wV`SFk z55EiSea<{dSx$WTUy*HfO-XVKF{^M*uqVgK~yoBOxE*&?bQ OuX@m^wW?-izV#bdE-!ol literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiReseda.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiReseda.png new file mode 100755 index 0000000000000000000000000000000000000000..d0b0725c477ee4487de8d245ad2ff993841a7db1 GIT binary patch literal 1538 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAt8*~h_-NSqY1#X0I|gex1n4*g>A8g&xknm!N1J=a7< z_{5p|#+&&imW)`|+6}je=I^>l*0aK@IjOO0a#Qz|=ANl7z0+FzrnmLaXrC~%bJFat$#Z(9&bxZ^#`Rk_Z`{6h`~JQA zj~+gF{OIxXXHS6W#q*~xUp#yD^7-pmFW$U<`S#755AWZ8{P6D6$M>HH2?+KOFVsD+3&InbMP~YZCSq&C?r+l z8c`CQpH@d z#C(mCmPp&icU*d+EC+cPMs#kVdLJos&(hCcTX-;o6C_LnCqnU z#KEv(#mcFQfC$0^>?Ju_+2uPUktn|eH#Jb(a zlO?#K%v7B0jwtNDwX;q5P1V|qI_j^sW-Y$u_28j|RE5xc{d;e0#GYK@E zT@fvpA5ZqxaO9f7`mVw}Vv6!ybB!WHkMm16aQvRioZ85iH#cbB|AKC=3Nn~YUU}gyL32_CA3vw|_@-fH?F{rRIsIoDtu`{W2Fl%zL>hN;t@pCDNGAfEO zDTy@foPe+Nla! zt4o+_D>j-=4hPNyeB<#ac+mS<1v)$wu2KC)&to+DPWu%Ou+=rr0ZmIjM&`Yec$g z#d+!HI>_cZ%H=!Br#dJXI4cyoC>FUY6}u^yxT}bq_nb*c!)FoKfCt9_om^UWdG^N-!r`mO-S$1dI^k&=j<=D4nIQHi{OvrPbnC~>H zz@B82X zKK$|T(Xanc{``OT|Nk3cIFEus7y_xc^0|TegrOwJFZln+1`NU9*;Rp2#981GS{c>6E3+Ir^;u+@-pQVY zf=rt`^=`JWb>Ebn(c+*n_jLZc2Nxc0N&s^Hxb8bI`}o4cf`p7C{Sqfrx*~H9-OMPv zJx6W&&Ah_fJ{5mlnGZkq+Er86(Y+YL3kR-iPc9u{z)y z8Ev2;_2NsLaqA5sy+t>J-yT%SSn&Mn|B17X9du^Sx}0!dMs2cy!Mpd&6E)Z-OK{la z9yP3NaZtFp+q&_rGxO=&NALV$vj;-*+g##yZi*gxfce45Q%Y~P-{VLpe z;lRJI*Ijiinz~!rHkr3>J~DgZ{6;phr=NbEi7?j_lL}Cudg?{BHlLW{f?s=b-_Ec} gIWG_3QJ2j{$He~4~zx|Pgg&ebxsLQ04RSwDgXcg literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiSpicebush.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiSpicebush.png new file mode 100755 index 0000000000000000000000000000000000000000..b0f335fef36f136a2f48fbd8dfb4e699c2238deb GIT binary patch literal 1549 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAGcz-@Ffg++u&^<(axk%TGIMY-b8@n9aItc7vvP5>aq+Nm z^Rn^qv+?qB@bGc)@^kR2?%is3i1dD@dyg@2nq8EiEs;v z@(7FY35)THi1LYu@rjD_i%IZ{i3x~G2#8AviAxDeNC`sFPjw%=FzM{|Dd%ray>M&#r8_e&-<^8>(VXiKXWxA>_x`Iz zPu?$h`fbE~ufB3WR!|%19{%!pBfBT>RKfmAn^XtyL_pcs){PgVG z_vhb#y!rF@?caaz|NsB=`Q88jkN*FE{Qbx0kN^LF{SO4c|Ns93q<~>E3Pwl>Bm^pN z1m+Wlk|4ieP!bryfFbxhyDBi+ISV`@iy0XB4uLSEsD@VqP>{XE)7O>#E~}idwF2|I z8zDd;sS?+SlHmNblJdl&REB`W%)AmkKi3e2GGjecJwpS7FGUN1AsguF;uzxL{dP)b za8rPUn|Jpe4uka)Y%>*urfi#@>-IbEX42{Z|7A_i+8q88cVS)ayPAhK@)pK-7~Pn> z_^;df%$guzx1e0%{8ke*KtB?4WLxuSO%=yb|BZn>2O0o;qom1O&`9nSFdgMX%Qr-9K$?UforGt=vw` z-wv@fcR4ZFD@auw4xQk!!2E%2Pcy&G6SMlCss#m&*4yr$J9KnGqiN>U?VwI31adEhDcl$<$HIP*^EZWLw;=%EHT{IW6$1 zC6D3`hXoQ_581?U*a@Vh9&hFnNn~YUU}gyL32_CAbFd3=a|!eDit+P_3-C(_3P=hINs9=}h>6OHi^)q$D9Xv` z%FF7hb1>`hawsVnswf$&Dx0XQnrW(AXlYn#t2^jvIqPe?80fef>be=}xf|77P z8hV)-d7B&iSeW=)nfY6r2iRBy#>_ewH|Ijayi1AmFDEUylDzP0%A#wji?63Gxskr~ zX2!Bx*(>knth$%B>QUy}r`hYD=dXR3v*AVV#+P}UUgd9oU9ja%;nugs+uxV$_)xm@ zW7)1x<-0#u?Dn-}fX;GEp9Peiw%7@rRWSxCZCb{f5u;iGC&%!xf zf)AO_Z_9nY(bbDxLQwBRL~cYKXS;({*mI`G-EL1mFt$6S@+%+u-_dsPo%)R<`(_1h z{&jBKM7wh{cmMbxEq-GAnzZ+v>|1yBI9_y6{LoZ<|EOz@&N}@>A(I8a5BuE~V>@(3 zjLntV%l^f-*YkIDoV{{NO3jfuYwi2H9Q*Bsd7qf(ereS0WUG7do_SWIVkiHU^EYId z$>=RGEHgSf&6)XDgQ@?~|4$+_5|YH;-qPi>G%=8kpSAy&V0_e?TYfc{lQItMPCItp~pj}huP~B)b_qMtVziG-)QiM Y=~!WQ)4J!=XMw`r)78&qol`;+0L&6Ug8%>k literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiThoasSwallow.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiThoasSwallow.png new file mode 100755 index 0000000000000000000000000000000000000000..799ebb596a5878d503c8456d8f6e0d04fce05938 GIT binary patch literal 1554 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA^K!5V@^A?Aaf$GAiwW|I3-L*da>)pB%Lwzxh;hq_@XCtw z$V>7`i3-Y#3o5fPXmGM9i1Dk4@u-UPDoF9GN$@F42q;MiDoP3~N((5<3aLtqsLP0` z%8O{p2x-d->&go1%M0tsiRj9Usws$SDGKT+3+pL}=_`uss)*>Rit4M0X)8!*D@kjs zO6e#{>ZnN@DvBB@i5V-4n<$BzDvOz^h#M$L7%EE|sYn^CN}H-mnyE>dt4o`x$rx!$ z8f!^es!LgENLy&gSZc~zYs=ec$=YhmS!gNP>L}RhDcS2QJLoCi-kSPwOY)QLX%Ba% zJl>u5bZ^G<{aG(|XT9E+`(}UM%Y!+u4&}Z+ocHEP{_CTqZ;uwdJ68Dqc+rQ$MIVn8 ze>z(7`B>@4lO>-{m3}^5_T^0Zw{w->&sY7pPz?;gQ808vVExTan}PX+p(MyJ`2WZT z48h;oRe>?dS>O>_%)r2R2!t6$HM|;tg6t)pzOL+dSw)1|t*0LCPzDM~mAFQf1m~xf zlqVLYG6W=M=9TFAxrQi|8S9zq85$UTDOv~&*)UHR#}E(ix05}C4>?G%vL2~*7b!p5 z(O}KSDA;WZC$TNiec+HX{%F zulb5*fBb!36xB)jY0SU+t4ggsfA#Z!H&-g!{Apv`vslvfoP=1aCHKM$4c3$FD$RLy z4rQ4fgV!SBo?#j)ot%T-Z%a%0N^#_45&JHuu2lZ`VDoD%6h v@5|pN5OcuFZ|z$D1Fa93bwA5*Sfl@;u~6k-$rlS?JTQ2=`njxgN@xNANi84i literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/lepiZebraSwallow.png b/forestry_resources/assets/forestry/textures/entity/butterflies/lepiZebraSwallow.png new file mode 100755 index 0000000000000000000000000000000000000000..5018a829f6738bbcf123e616f73447f3ebcb520b GIT binary patch literal 1523 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CAGcmKWv2k*6a&vO>aB=Z+bMtZY@bU2S^YRMu@(J+s3-R-d z2nYxZ3Ia({K|wJgAyHvrF<}ug5fO1=VF^)DAd(UjlN1*RlG5VhG7=K9l9F;#QnFG~ z^3u`@GBS#?vPyDt$_mN~3JR)dML*Dk_?)s#+Qvx;pwg|IOY1TX@`g|KaY3 zkM}=)zW@2lgD;Ps|9<)6&#MPtzCQZ;?eVwoPrm| z)xZC5{{R2-|J#TE|ABrP1*0KAQV3L<{W%WICk!P)e!>4oHed+;&aMg!JkA1-$YKTt zzC$3)D5~Mr02E{|@$_|NzsoAluV|#<=N1VRk}7eHC<)F_D=AMbN@WO0%*-p%^K%VR zC^ObG)iX3O_)@eG7_#P`E{-7{-ft)04r(?KalLwL)zt-|IWNz)9TR(XcU8xfB&GlV zeP0}wOY?J(db9eqYW4HPvnLa8oYdf*v;RP!U{Q%n)^@n@Y8)+-|lNn~YUU}gyL32_CA>#;LvaI)xgFc@(&8}qQ3@Uoimvl|HVm=#7;NKUG7r* zTqSmUNbmKMUErs&&|h;=fY#zb?Il4vOM`Wnh3G90)n5^2url0mb)@m$IHUauCI?ex zj%O>K$WcC-t8yw&^>n`4fke|o$>!H{tZ(Gn+|0ARU0{Ew(BW>8=Dl(6_TAu5E0&vAON$miAj)J8p05 zytBRQ?vC#JyL!Kzp8M8eR=RLG}_) zUsv|KtioJOdX37Sqbqj9g2g?t1rCBNEUvDz_VQ>Q?fPH;wd7;!q~AuJ z`Ay#EU)AIn7Ja@oLo>{@gHL{kMY}|BWZR2^#y!e5Y^E+h-!?tkken=(cchkK(P36U zry^tHzQhB6m|fbrMQm1CoAxFiSj=?sp}nEGhHGs>Q~c-qYcpjV)t`o~EP42mT}oqm zy7Id#JYq|avn{;fpt(=obo2Fy7QfX?WxW39^@;!afbfF=I`EXGp$(YDvjEuQe-UfuYaf>FVdQ I&MBb@0LaT%=>Px# literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/mothBrimstone.png b/forestry_resources/assets/forestry/textures/entity/butterflies/mothBrimstone.png new file mode 100755 index 0000000000000000000000000000000000000000..0bdc9d2867e77780f506d96c0a84ad12a726d5fb GIT binary patch literal 1532 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3-p)I`?e@QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn~YUU}gyL32_CA>+*5x@pBm|vKT9|nkciGs<4}>a+s@eTBvhbYH-_V^Cb!~ zFN zv+EwuZ+O1D?fBxR*UMYpuWtLix$F1#p8vc10q-9K{(t50|Fz@)H%|ZGI{$y?^8dZ- z{||2eKe_`wI|@ca067G7Y@a^{<`agJAiv=MBO5RTe`i+(h7D(dM`SSr1K%MKW)#)% zY5)qdmw5WRvfpJD<}?<1VEuPFP)Mr8HKHUqKdq!Zu_%=xATcwqM9KLSV=`c)B=-czC~^5*geSAkh|m#%%MQ4YAQG4ij<&Ev7C_;fVPE|NaE=_XeM9 zjm{)4J3Vjp^QVtyGV`oaZSB}SK}0S&#Jt02#RnB{OTw??`SKx zXJVsr?EC)Wa{_TrK@kfUMl;tpO>`{h^L)s^G522G*#|6z|7xY?u4OlWWc4QJ!6P9l zi#3&PUk#5gdh^Cn!z3WSB{6@Jq{h_m+ZV8i71%yMexi~+q}mHJ#C>nhrXpn zK4O{LenRlOMA3xlva@cCl z74xx0m6cZ|>cJU#euE_mjYq`Zi>{Ed37GNUVbUL_H~+I&EbCBb0){w)r>mdKI;Vst E0LigGjsO4v literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/entity/butterflies/mothLatticedHeath.png b/forestry_resources/assets/forestry/textures/entity/butterflies/mothLatticedHeath.png new file mode 100755 index 0000000000000000000000000000000000000000..91559a116c1d18c19c02ad49cc1d40c212a8c2a0 GIT binary patch literal 1556 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 PKbEqybtcwWQ?C6RkmTB{ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/alyzer.png b/forestry_resources/assets/forestry/textures/gui/alyzer.png new file mode 100755 index 0000000000000000000000000000000000000000..8107ee076af8223b0953ae137bc0fb3dbef68215 GIT binary patch literal 1995 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/apiary.png b/forestry_resources/assets/forestry/textures/gui/apiary.png new file mode 100755 index 0000000000000000000000000000000000000000..5bb72d7385bceaf28fc454e65b158193f93dea95 GIT binary patch literal 3391 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/atlas.png b/forestry_resources/assets/forestry/textures/gui/atlas.png new file mode 100755 index 0000000000000000000000000000000000000000..c9c4a247d301d30ebb08213c52895e6e232c3847 GIT binary patch literal 14233 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

iZf%gd#jQHd75va2;Bi-}m~GeTZNgd^ZBjmzOb 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 E0Cu{_AOHXW literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/bioengine.png b/forestry_resources/assets/forestry/textures/gui/bioengine.png new file mode 100755 index 0000000000000000000000000000000000000000..da78153137ab6c7efa3e1d4728814aa20d90dcab GIT binary patch literal 1722 zcmcIkX;4#F6ux;RBu0e<8&D9z$YNQ9swl(&4~W5t1gfB*AXF$2H=-bd7I=0UKrld+ zMQBXasEB*x?jRZUvE(UVBu@+M}LQ(FAYrVHeY<!NMX>tf|8|*ZqN96u?w-oJzgan z9|sm+p_$jh865MQ~k4 zZ)obaR`{OoVf z&>@pl)pb1LhN$z-vqm+Ol0Ni(L%6{gWEbgC(p*T_IxnUyK(Q|oLT*y|rc16-siMU| zwu|{Zytcc1ML=r^CN3GA*hi-ft;h{VMqc$o{E;hAU~m!|LV+7-S6eI=`(1lY%G*A( z>B)|svyvgTU=iHW2g<`mg>ntgBeiyPQY;o{X3jrGS3a-T<0blpV#-)R*j(MI*|cB| zUeIPmsR3ow%OI$L0ng;|J_-&G!4N<}f9RhkEkWFgmHttWZfo#p@Pl`So*?Pd1}k5;Q8s?nLL5Vf(b!GhK>%uew+o5#w;|XabEE#xZ%UNcuH{rIE7^f4Oqv z9gm!C#V|s_r?p9uSNIhzA-^0DrjBZQ52Q-dRJ%tGrS2Jd_mz~x((uj}PwN)}ga~KJ z#;ECwCeu9WXY&KDTc?FiE+v!ein+>&`@BcFoa!3l?H5y{ef3VZPK_A~b5z(maC46> z?@S`ayc9wFfb_Yf!(J&LC@4}ic-o}Ls4QZurpJ5pkJx5}Qr)O53yZqtcxQ+ow;4qM zjxi*DSoT$hrme?D-O=iXOsIJd!rWXm%zC!Mz|jDxb2j~Sck*1k;~VH!owF!C>a@64 zCX0$SBIE#morimxheS3W{RM4!;(fPx^{T$E%VrQ_6pDd?us9gmpPKYu9d=mJa968& z#ne5=B|uy8L@;)6>{fdJ!*NM}PsFy;_=wQB^vY#`U#L>4n2VnCrW{Z1#S(e~r1rKE z1R}A=K^U-I8^x-lwZxXW!8pX!Zh*dYbuv;s$Aq9<}`4@f1-&-_UH#jng;w1fk85se(!WF=Ib3R0db>D-$K-r%AQJ`S9J^%n-NXiIVr62$R literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/biomefinder.png b/forestry_resources/assets/forestry/textures/gui/biomefinder.png new file mode 100755 index 0000000000000000000000000000000000000000..3173e576ab04d71685e1c14d3ae28db815b30a9d GIT binary patch literal 2260 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/bottler.png b/forestry_resources/assets/forestry/textures/gui/bottler.png new file mode 100755 index 0000000000000000000000000000000000000000..ad078c25674dedab230ae25c8338bc8158c61608 GIT binary patch literal 2005 zcmcIlc{JPE9>4hsk*JW`IxWvKjOAIX#%nC)$HewZjw;U@QcG(as#Hx4f@)$*rn=g5 zs#DC^%2-Mt+A5}04tl7iwMALbf7 zp;-e%yrZn9uYb2l=ruT@gTYpR^FygT=_rlnh(r5jWv=V+6bv+mGr!RYx|YSxqXnwz zfBWbrGcw3{&FbFin?sD#iE~{-ySWd%>CGZLkM74Tp&e^`_S7Uze-{xI*@0XR9!&3P z6uYq?%UMI<0&Je86WT1#NCbuh60Z*_Hb;XE4~oGWOmH^|$-ZhNxPNJ_S~_BOWnj1L*p zYg$@b`r{SLrKG@4V}z%iAqR5TK@z9GU2R6fCJ)-=JkQG}S(p0-2dA$oy0!{9kSrL_ zEHM1UP0=I2aAek*GG{o^dpPj;I=Bbv2K*A?j-q#|&QFDa*CS`Tz`#asJz5KR`B3@L ztuvykPKvdya7J1Y{HnTs?ktKW8mJx|2*Wj9XNjJZdL3+__u>^09W0Wv>h?H-U<$4j za;7R`A+1)W%;6mz(EDqY8q8%3n8FZ(jI}ObWO3(JoGM^&FPq57_Dwn3hHwDjA+TIX zMAQ@oH}ZoBBLDaIBGMidlYp05gWr?!yqQLZ-9DMm_t>#O@KyE`<~A%>Pv(55typWb zI*>hcs!0acC=0Pw%fAvJtl&`ND?@C3i=}+??!V!;s3)b41vWzzHfgRC_d$)tk;_?_ znQV{i@PjCw{u1*13#y-Ovx9A0nyTfF%r?BtFT<`8=;JDczExUepcFofL=im%&x6x` zbN;?1Q*Zac_prC zeLkU0@61@akRFZ!-0(;73*wwp{GPp$nbbIiZt-ek`AgA8RaWFt2R-20y%$m*n2&1D zc&CKh(TLk@qRh+ zY9*kM8sgv5csySD;#}I?xw-Z)N=Mguq3P-A;bh_tDf_HGsB!v`m?fkOO`nauv-Epm zaV$m+V6~Q`)T`wTgj_3nGb^@^1n`twKT+Y^DHUBIrHj%@lm8BQ9Rf*!;0qw|*-2t8Mc+YMBqW5l{|! zbL%h&aC6JcNZ8^pMJYf7MIhrSb-UTa)^0g3)n_H5p2@0SGvmW50}7!4*1Jjc)O-nwo}BBfc(q_3&qh r6UN|9m;m}rI(#^70|Ni20n3X}E{`h%i*CCw9Hek_A`%)L$yxsZ{a;ID literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/buttons.png b/forestry_resources/assets/forestry/textures/gui/buttons.png new file mode 100755 index 0000000000000000000000000000000000000000..fdf37925f9a53414890b38230cdb9daef222fa51 GIT binary patch literal 10030 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 JR=6;K{TsKC$>ab4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/escritoire.png b/forestry_resources/assets/forestry/textures/gui/escritoire.png new file mode 100755 index 0000000000000000000000000000000000000000..b33afb21dfd6b8617a272bd111669848d8b36bcc GIT binary patch literal 3240 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/infuser.png b/forestry_resources/assets/forestry/textures/gui/infuser.png new file mode 100755 index 0000000000000000000000000000000000000000..28ce0183caf011317551a7cf02eb1ebd456c15f3 GIT binary patch literal 1193 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G!U;i$lZxy-8q?;Kn`1yx4R3& ze-K=-cll(X2xoyuWHAE+-w_aIoT|+y4HRTA@$_|Nzr(`8!y}`yN$3v)1B<4oi(^Q| zt+#g_^Bx&UG+eY-K6jbfL}>YmUF8m+Y%SQhi+B^x?=nxExNb(KvF=h85%s!!W2w-` z6Mg<(^@|QZY9D*RBxG5_oz6GA&izVPn!hDfl}Y($@<(IS-+%A*l^&5j(9R&k$G+L= z+O^lEE-pFSqpceS%NWG$IT#ce91O*#+x__TDXDG8sh1^PXVa3Eo{2PcbX>n4zWK=Z zX{VQZ7O*g|Fw8hE$dI=+YAsv;MHAmErMX7MoChvnzP#Z7hYFinUz<#PjbGefKIKnM zmomcxjst791+32Sahmy-(l&y8r_%;oW(Ld-Y$x^EfbQ6$-%LEfBidgMn(pfhMlj0l2hY>Di^doXNb2Ie^CB2mO*aQ*Z*2f91N^>%n3@2 zAAbM&lQMDn6rUDZ2Gv!sZ>7r3{45~A!cf4nqsf|4@^s$z-vu!T_!tBj96*uAf`iep z{|+Zd8AAgD0~139+Xu~ZrY2cnn1K19z=1L*Ol;MBuzgRx`Gfa%&+az8WtcHDTYT$L zeFhOJ#_o6q4HG7@{R{yaEIM_J3odX({ONz}=dh_xtpQ}#fy4a_1#7QnnO5{H%ajo= z;%cyF{P~hePHCw~`{9EwR!l&vk*tE-31Wb)pK@$&!yVttCKH2<1dF*CVpgxqo?dAI z(&qD;qrhrz($1J!sv3q2v(FymX;ely8fucyfur&)Qm^06y}iw}uP{&U`0ZwU4Tk69 z2^~{{w&Z5ZJicSocVD9f6vsFNi_w5pfx)3s?;g9swcFOx$1R?$?CMzedRIrsf4#T@ z*#n}R{c-rnVfaQXKsTQ>HHq!5*c%*N;aH+1p0$1fy;rRfoZ4U z35%QkhyU&X(~sR2u)k$Er++{oZ;#=*3x#($o=9SN4k_R`8Z?0s&Gp1h;c<#R-}mB= zZVD$RN;k?df}?-O$)oKJd8}rBe2>56vp$>7R8Ys*R`7alVO!thhg&d14U55H31EXC zhb5>TUwfbr961h!x9g8>?C4mvYE|C;`?F&-O4tKz?d@mtsvTxNQ20fCgR!d5mtt`S cssM@O(tXZ4>I_E&JVEApy85}Sb4q9e0M_Gs4FCWD literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/ledger.png b/forestry_resources/assets/forestry/textures/gui/ledger.png new file mode 100755 index 0000000000000000000000000000000000000000..721ca8ba0b323a46df051c007deec70298bac013 GIT binary patch literal 840 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G!U;i$lZxy-8q?;Kn`1yx4R3& ze-K=-cll(X2xoyuWHAE+-$4*&+%YlxEl`lX#M9T6{SGTHKbL{aiG5B$A;}Wgh!W@g z+}zZ>5(ej@)Wnk16ovB4k_-iRPv3y>Mm}){2ByWHE{-7;x87dc$lGin;(GDBvRjH! z1oO$}3Vw6Bu8>ZVrQVYBgBhPr-tlYd6TS_zye7TfwQkPyOumSx=hs)++n-^~mP~$9 z`t$m}_umU;!Wvz-T$`k_w_KcIjSqtZ$YU%F0#suNFbFpQ-ORwjpuj*a2K7vWyJ*x% z(nDZ>=Gxjl`Nikf_cw4e{0QFrU1g0}SedazTlqIk^3i2|guo7Y&B4qKF? zsE48fP=6qM5ce;ioP&)@G0uN?R2oq<(9qrD*&Sj4TW&d1_IbxYpBrs<$&SM+E%tt5 zx=mi?42PzlpXGUAR~!C(*(65AaLz(NzLoyBxMy0sM(~FAZwD;CQ_Od%cp2kjzc2Z` zZ%AI0;qyn?x^BIbbw<77!~g?|5gBb(r9k4do~hh<7|V-n@)zvp>aa#wK40x+1c^lTu$EW*XT$iAJmo8A}31X zo1@^I1Ft7F0JP}Y^UP#2*@1UJCQ%N&&{T5n0tTapMLtel*tr>byJl4ZsDAqHhZZ8* z9}T|r-*~vbpiEwn2l+LtrFzHh)*Q^KD` zzNn9lm>EkNp7X0MlzhcnYwu1u&jGl)_N3zsN%}LwKc&_hMjh#sy+x9`wDnyt-QtkH zG++nyf%enpRi#m1g-ctpIm|;o48ZZJX>Sg_RlYmRYjcXs5xXfh=?Aa`@4nq2p%74k zA3HgjBoa67{If<4h>#Bb8DNvy2Rw}@&*^Oy{*MV=jX_p>X zX$VPaJQech3>Dqd76+uguSzE-r6MeEYY<=n*JV{YcaA}7N?5H}-b|7#^v|qJ9tlOz zQJa2A)j+tR%8Sz_2G1<0LVz2Oc9&r8PbUCp#TKib8u-WCO8k36tMrHGBpJ0CYpOV} zpC%E52%M;c)+Z6w^;oi#c3g6WrWm>niKm>@!f?YVJB1FAb8S1d9KN({v)wL)=z zLD}5Fq4%K+`Kw>zOk4pQ0M7{w_g-l$l}G}5Psf`rNe0$|LA{MELHLPg9SA^(*e%N2 z0nAYh6i?yVvSgt*JsTT!N!QH$)hz%I_t^t^pj->~pH&94U}ISqHfuI-89^dRFtf#}rFb~eeIG*dq`10-a6 z=k-+2WTGZi|Bo>G+Gm6%j)qG+_GqGRcTsS7U?T?;<7S>TMDAsZTJ834OFS)YA|1Vg zSe$K7eamQ=w=}yY2u7Xp-~%19PgPab@kh4PIymvtFD@(Cf*L;m6LWKOK`4J#{^C5a zV13B+$GviI`874ZtLeeJvjh>f{T`-qIn0&$L*0(ZmlMlYX=#_DljJUb9T0Gd(Qr4- zwr<9su{&esRL%ilRpWPeK4&dqMUlTO`H^gRW9b6aNMd)eieBq(3jZZdP2}$HTIqhm zjXNL3>)JAZHgydTP#?Sa&sCPy^=hl!zU$qAcgoAZx1DyaQeRVLW_Vj0pvTDZ4=A|U zF887&srcC{2$-YZ}aj;Bq1jSnil4&uVte0 zY53_(lvRNtBvJdkwap;*;((=Qr~b#T`2!07EdNB={fq6$60cO-39oo#%$3V2(0}G~ zmGa5~@;cMM!y)H=NsH^}pfVEDEF8P-Rh{-QrsW);76BCc+Z ze9%CGsSpHP)ssl1d4Fn*Qr~^%N*R;W6$NbCa(hJ5n9*?Isz?p|#TCU*Le!cG7N6HU Q31y!-JJKj+_VlyA0`I{+KmY&$ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/mailalert.png b/forestry_resources/assets/forestry/textures/gui/mailalert.png new file mode 100755 index 0000000000000000000000000000000000000000..f9c2caf3c267a3717348af8ddd4df28b74e3646d GIT binary patch literal 893 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G!U;i$lZxy-8q?;Kn`1yx4R3& ze-K=-cll(X2xoyuWHAE+-$4*&+%YlxEl`lX#M9T6{SG?^o2AA>hTA`ZLXst}5hc#~ zxw)x%B@E6*sfi`2DGKG8B^e6tp1uL$jeOz^3`{pXT^vIyZoR#;H|utQ2*ZQNlYE^Q zIzRWByUTJ)-p6SRi`(`%yp;OH73(Z_xOj8w=LsuSQeIxs3>I&8W|t0ugoJyEN(1oi#@Q7Z_mfr-?g7aYyW;Tz7-xh>Hj{9+pE9) zur@cpXl0RcrtW`1g~Z>33UwvBKmPr9Z=#pbao}WJb zr8dV37bXoQ&M9Bd%+Ei6GSL23_{|c|s0Q^(2iCFJZ*XFYQ0L^RyU{3?Ft=<0*TMhl zGiNe4q^maASVWz@cj^8V+aKx7HHCZ$!ruiQRD~VtzSa9RWHTnTKVt~nD`c?q;qvtL zPFJ-XO7)qac`nGAdSL%MW(Lj&_RagxcqZJGVaQfwxGle}Y|LM%`QLL9|$jRY5Fo)sF8m5SA!Lx-MW~nxuetlg!vU1vsmg>s6 zp;dnZW{EMZaAY-*>0M+maYH#k`Lg-NU3WtK?s4z{)5Qn?I=^@ivjrz9OZW?ceCz4z K=d#Wzp$P!AQWwMk literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/mailbox.png b/forestry_resources/assets/forestry/textures/gui/mailbox.png new file mode 100755 index 0000000000000000000000000000000000000000..3fc8b3bc3469bb1cb58acb9792cdd09cf31cb3e8 GIT binary patch literal 1293 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G!U;i$lZxy-8q?;Kn`1yx4R3& ze-K=-cll(X2xoyuWHAE+-$4*&+%YlxEl`lX#M9T6{SKQrC!bXNG-gf)29{n=7srr_ zTW{~K&lAa&IQB4oR&F4N2)jdU_~b3sETtV2d4=w$OjgSFJip+0g9evt)6Co^Cxw+t z3Rwac0^JNwn_P*3}-;-zFp7k^5F7coJBU{SB(|6_mf?scry2saPy!ew+ z{#NkDr?dQ)Hg-AJ|Ebu`_}i=>KK-BSf`+%%hb3$!-O3BCVy{m=FfG4s#r0|Wj2sLB z3mxy*@A>y7>*IM->%%`j{%w}EE=wzuv#FV4%^D17%&+h?z8P1<|pX(86#)hi-Om^H1cMAVkF}{!m zS{QJ1@qUJeekPFhKQuOQ*zUONVBYe(@48^~=FQ9A%Qk>KnDYbZPpsbSF63tr zlIlOs#IQB$*+qWF2HwqU=70Ol2aKHu)8rXrN;ZN5ToM{+`??+W?>9ef$LInQIJc@S zhJ^_pve+35+CdHwxpne@tAceI*ITejN3Hdk7_o;nJoGOdhGvf9O_un{s2N z@2q&fS4tD+@>r|tGfn;Rbb%hz&5gy$L?o+81%fB~=63A_1xv52c%zpc>yD7*X%9<@=ncQNxs$>hSMxcvtUge7>irHb z9&AYz9&A93LhG1rZwxjJZ&c(AZ)61JwuV=7|F7o?2%i0U^4*t@iMu}px+WOUXP8yK yKK@shL*nZiMvM3Qvwo>JERu?6V!#7#FxWE|)ib@n7FcKuQs(LE=d#Wzp$Pye$ENTA literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/mailtrader.png b/forestry_resources/assets/forestry/textures/gui/mailtrader.png new file mode 100755 index 0000000000000000000000000000000000000000..534268b95e0be9d429f39660485e0b36df1deb36 GIT binary patch literal 1842 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 Y{)c#w?;KGHIfAWJbA@8HwyHSxFKT#m3ee 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 d|4bi;sd+ulG`)N-FdjLZhvRF+uPAX1 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/solder.png b/forestry_resources/assets/forestry/textures/gui/solder.png new file mode 100755 index 0000000000000000000000000000000000000000..4eb44cac0e642b586b80c3a6c7192ca46559224a GIT binary patch literal 1397 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G$6&6|H(?D8gCb z5n0T@z;^_M8K-LVNdpDhOFVsD+3zxP^6@gh(q6EOfq|9D)5S5Q;?~={8~v1`Wez;F zPg-oa(P-hOO`C48H?*)D9LdVM-{EQMjY-z1A*;}Io1uwoVS;KN|15?4rW(Ec(29aa`7OAgax9*I9w`BkEi+S69 zkLa-~C?#3Q%u@XqzBkUCa~neg1HPL;mMyz|JQfhoZfU|lMlI?xYxXK7Rbz!p5fOVS&W@_3H!m zrayl4=+WU?rX0o_iOZKSFDxq)yP9Qs>ggs6guaM8{HOvd}w)xIe}f()98QYf7g08 z#)Nj|28MtM-L}5L!io$cfosExXSko+$;rXQaDz$b;q~?L+JBqN%gfW|c67Y>S|z`Y zJAx4y}rPp zrw}|8o1UE5r}<#_m#V!>=dZq+rFMp^A$HRn*SC+v8Mvev#rHD=T;SO8gSDZ_?Z8o> z=S`UO{>^{v<4{!V&j4~lgZzD_1Dj@@eRe8Y#WQL4gyjqt!V~QGHiS=HmdV4$ES$-W z&vPIT2bi2=NlBih(rMxgN@xtzLRVjvd6o#$w;?vV;bVo&*Q&cZj)Ke=^0uE9xWR-T zN(aOuel$D0{`K`-v%bO;%Y$5emS4_vIbzQjSD-YZ@RPy0=faIqYr|YzO04GIte)Y!h9OP=fYzLf z-f86mdKI;Vst0G&eIegFUf literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/squeezer.png b/forestry_resources/assets/forestry/textures/gui/squeezer.png new file mode 100755 index 0000000000000000000000000000000000000000..3021bdffe4910d22e0572207460b820092b1680e GIT binary patch literal 4238 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 L4(-mh_B!`3o_QIC literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/still.png b/forestry_resources/assets/forestry/textures/gui/still.png new file mode 100755 index 0000000000000000000000000000000000000000..66bc101223f191b0cd5dd422f83a0e7aafd911f4 GIT binary patch literal 2169 zcmcIleK^zW8-KQ+F+|&8D(V>3@lv5EYSl)=)QMp%MOF?cr!+Cs2{WNLDM^%Gw(6HH zB)v!)8|rw?3X80kHObpXXbX(uhb^3})IY|onN=v_KKs1u^DtS~M`wAcrQTCF z)xmG3sJa?Wy{c5yx!W})EL|rkN8W^d5oy$+0T3vWeemm6)Pj)lE9CFw&@A2hMghNVYW_**} zV&lutWLS&x}4>n8wmgyz%_ zJirD(17HEW;W3ibqJ$&CZ?CbA2;lP&41TH*M4G6WxJ{0Z+X|+y8S;RN8FyRM*~ciq z8GsMb0jsDm%7a%&OZFZcXj|8M9^+{b5wKf2Iy*0(Ia5(lAYE!q09DhiWrKUp0A=se*Li&#m$CgO!qScvI`KP6o&V7bnOpCzDIDg zU~gq2_^%lsAJ@@KdK_N*p}CI{xX4c%XnEX{;ipVkxlLiCCn~OqItRwG zql)$i%tS{=KPgTo#~X3EI+f0uS(luJO9g-nw>)h~<<&N-)AqDEa0}z+1G=t~?x zp(nL~({poEu1zj{Ri9ig@8u0n&&@ybax z2ZY=O#$_ZMYq49>(=10ctONj)3n#B|y@?IYu&pskA|S~6;)3=!5+~pzniR*msb7es zjo4a4ptE7Qey{=97}=5&bA$0ADQ7G*v?C`E6z5Xgo7*lkx3UJ5$<&%e+r|w7Eo*l7 zL)dFyOz~BdeeEFw9y9N09AQGpzzd;mG=dhh7yqWK>hs;_r7;$Y$PI>hbi7l%p}-96 zGyztNM_Ts>gvmrjCG7mvK8W}uYlf+0jplppqta{Ix~QwwqpB3%R;sz8HXwUWYRF9y z8%vA;)gEzmJh=zIg{k%s<>any)L*FxISjO^h_%##{-)=m;cu@tvS&9#g56#!-Cwb} z{;{$QkPf}QDC*Zu?aoo7(T<7gxwA8LQ9_)8IX`KuZfg&Rb0=FmDYTew^<4Vt;f^l6 zSBlI0IZmT#sexU+4Z+#Z`I=_@mFdlVN*_hM=-WH_pndu3~AKh$E z7+jp|;w7dZ-yUFf-V0NVBq;`i$_&t#1;9%^Ro~2g!wZ}0G8LBHZEe^Cb2?7>vktvu zCx%~6)<2r@oY_X#vN-_$s|lF}E&c`FzN|bT8T30s$J?k>?(JGNEe`-~zj|I#fRFbL z<^zBMW5WttYiP#;{;!Bg3St%igKEDKAn%YJorpsZ2f@I1e-KmeC3SB%BXb=fb0 z<&3R+m|R7`Nv{cR8kfhagYPY3&uZ@>@>FQ@2yczsR3`cXJDz_5 zhErp?J>5G~tyZa2YHe`U_hI|t^Q|l40QJ8PyYN*3e%ZAljli~cQn))V%Xg)@+ui2I zSnu7Y<#Hlcm38}OpFz^}9E(U)DwSW_?F#r{#Da$QEN>RyQB8_ThyTV!0O0TRaKaL( zoBvjKmLRoCz!hFFNP6l!&Afqpnx}(Jgd2T+WujUuh0sFSKMaxJuUtqF1nK!^7VvQ1 zsH%92y_d$x4N>M9R#5(-AYO-lHRt*!mH3`w=6NCVxS)>1c6A!_$E7_BIVLsyN5Fq2 z#zJm-;V3}R+l<+RyGK9$?wGY*{W0s}KbZ-thQ#bHAEJYCdd(rH<^6&DaKziX$3N3E r7U{AZ*UOSt2D#j6w*mjJL8(;37C+h|yh3^)Sn%QD>Pakep`H8>&o-@s literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/gui/swarmer.png b/forestry_resources/assets/forestry/textures/gui/swarmer.png new file mode 100755 index 0000000000000000000000000000000000000000..d5d54cf19be25192edc332190a9252356b0c7503 GIT binary patch literal 2157 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 aBlZgjyU4cSk+2T{fc*|fM)@}X@BRh54ODpm literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/ambrosia.png b/forestry_resources/assets/forestry/textures/items/ambrosia.png new file mode 100755 index 0000000000000000000000000000000000000000..e2b84fde3d8fb10cd2dde3784e5c298dbcf758e1 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFX}M{{DK)6$|j$+0P+}6 z<*y$(0OW8MctjR6FmMZjFyp1Wb$@_@j-D=#Asp9}6B-!Z92HenT^$`2oNubEVLIgD z*=%&_fl@%*vhLSh9EZ=EG9U6NjBeCo4evQSr+~wG(c;B|XBrq7+CGX#IxW~Z8)%qn ziEBhjN@7W>RdP`(kYX@0Ff`INFxNFQ2r)FYGBvO=HP$vTvNABxcybh|9!W!PeoAIq zB~*ijuAym&p^+6xj|D`-WnFVdQ&MBb@09h=8=Kufz literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/anything.png b/forestry_resources/assets/forestry/textures/items/analyzer/anything.png new file mode 100755 index 0000000000000000000000000000000000000000..d91d29a41d889b4dafa039d74fe5451b41719462 GIT binary patch literal 469 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF uIjMPxxv5qqKn6oWVtT4xrM{tAY&@7*0b*v~NGbp-XYh3Ob6Mw<&;$V2kCLwd literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/bee.png b/forestry_resources/assets/forestry/textures/items/analyzer/bee.png new file mode 100755 index 0000000000000000000000000000000000000000..8399150618a369afa78949a6d9a2df554413463c GIT binary patch literal 454 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF)poOA`MXDSKu3ua&_n|#&+$YV_Mc6VV) z)eL<+B zW5KkJ(_Ry#92FH6XNYomH!?6d%7{AroZeRmv`e+bHKHUXu_VdYa19@85pQNajiqqkei>9nO2EgL-@|WhkzQCK{lji=A`B&=B8Se m02vGgiRr0&mHLKevGHJL1&En_BdGwWoWax8&t;ucLK6V1gNw8P literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/cave.png b/forestry_resources/assets/forestry/textures/items/analyzer/cave.png new file mode 100755 index 0000000000000000000000000000000000000000..1fca561d8952e1978ad0fe2b8b475df3c015b8f5 GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF#m0k~6(DBz Sjidsgat2RVKbLh*2~7Yq0CVX8 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/closed.png b/forestry_resources/assets/forestry/textures/items/analyzer/closed.png new file mode 100755 index 0000000000000000000000000000000000000000..35dcaa0d92e42fcb608812022d1df6d3012df06e GIT binary patch literal 455 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LY0b9W5kz;mw>$ zO=>Dq&2=fV5=?K;sk}HLa)yE7|NsB-OU%1~ia1Mx{DOfr1Qe&tUI=6{CV9KNaAjQh z5(eaO7I;J!Gca%qfiUBxyLEqng0Y@1jv*Y^lM@cGFflRlcqy!C8<`)MX5lF!N|bSNY}tZ*T_7? z(9+7l*vimc+rY@mz(DPZYaNP)-29Zxv`X9>!gu~X1k|7mvLP)qCp9lIH`S^H$Y3Z) hOi$IT)HgJXjR!L;K+NnLNd-XV44$rjF6*2Ung9XNg3bT{ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/drone.png b/forestry_resources/assets/forestry/textures/items/analyzer/drone.png new file mode 100755 index 0000000000000000000000000000000000000000..260f8417d8a5ea43208a2d12274f4854030f9465 GIT binary patch literal 453 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF`6Os#mFRXcij}W>$ch**B63fXW#>UHx3vIVCg!05hwK2LJ#7 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/flyer.png b/forestry_resources/assets/forestry/textures/items/analyzer/flyer.png new file mode 100755 index 0000000000000000000000000000000000000000..7732b620762dc88b0662e5bd246bb48c3e6d2621 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XI$U)KJpB!!%*X z|NsBpQ@R3y;*3e&?k>!NJU$=`I14-?iy0WWg+Q3`(%rg0KtVlE7sn8e>&XcR*qodt zB_y1kWhEk?)FK#IZ0z|ct7z(Uu^JjBq_%D~vl&|KTV$jZP#?TKq0iiX_$l+3hB+#14n{yhZL zpbWAhEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1K;;acu6{1-oD!M{M^uVrXDw#FeyJoFSQ) zv;IX<%m<(iswJ)wB`Jv|saDBFsX&Us$iUD@*T6#8$UMZ*(#pWt%FtZfz{twLK<$ZZ z9g2qB{FKbJO57U4cm6#D)SwKqAuTf}H7_wY)v5%@U?@mTPt~i`H#Ccl2Qw=`%zopr0Ollom;e9( literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/nocturnal.png b/forestry_resources/assets/forestry/textures/items/analyzer/nocturnal.png new file mode 100755 index 0000000000000000000000000000000000000000..b8228fee63b5fbcd91b57ef6ccbc515e80e7d654 GIT binary patch literal 515 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>V8U zYiR3R#HUvUgr)I|s{a4~|4p0HVW7#3N#5=*l5g_1b^tk?1s;*b3=G^tAk28_ZrvZC zV56stV~E7%)c%`%EebrY+R=^O0n-lt{I4&&SZ&tEeA|`^NCE*LVE?Y0t#V9sYs;@+P2TR7+eVN>UO_ zQmvAUQh^kMk%6I+u7QQFk$H%rrImrPm7%$|fsvJgf!Y(-Ius4L`6-!cmAEy8@BDiR zs6iQILt17|YF=V)s#OV)!BCKxo~l==Z)g@94`x#m+jA2BR0pkR)ti(?4K_2h&GMmJYiS4V|}1S2COp%5k` ziK)G!tuZ2vJPS5>tq`7|xJ2cN6q8V(H!~-L=-CZF%~b$IJ!UDn{rvUTa!16eGsEiDJaIGh;fFfuSKmEb6QkiQ#fuWE^FL`h0w zNvc(HQ7VvPFfuSS(lxNqH8Kw|w6roXwlXx=HZZa>Fi?BqT8E+`H$NpatrE9}@ST4T z0W~OtY)H$@NzF^lO|>ckG8hUH(^K^-^$pEpvTYk1@&H z-GwQQyCwz5;VkfoEM{Qf76M_$OLy!300m<`T^vI=t|uonFuFN%G#E@-z@sQE&f#py zazr3V$cWYW%B3mJjzK;zGfy7WQgDlkI=)6XVP(%dTkA4SCeiFS_ck6)6%N>aflq;1 zLurNXTGlXS4HXrZ%}j}!z@S)SCHCP);cXwFMXDvP5hW>!C8<`)MX5lF!N|bSNY}tZ z*T_7?(9+7l*vimc+rY@mz(DPZYaNP)-29Zxv`X9>!gu~X1k|7mvLP)qCp9lIH`S^H l$Y3Z)Oi$IT)HgJXjR!L;K+NnLNd-XV44$rjF6*2UngCp?iOv83 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/pure_cave.png b/forestry_resources/assets/forestry/textures/items/analyzer/pure_cave.png new file mode 100755 index 0000000000000000000000000000000000000000..12e7e38cb46d5be33e1f7acba3837624ac9df1d2 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF|EmB0Z~p)PU*Y1-IY0%BN#5=*Y>8<*YJnWi0*}aI1_o{+5N5n|x9$&6(B9L< zF@)oKazX>MBb&-LhMuEKSd@B!-~f-XxVSopvdI-sPljU&4#^hATn9wBm9pEVIkqyb z=m``^lk8w)I2OfaqSsq42Q*5x#5JNMC9x#cD!C{XNHG{07#issSm+v=hZtH~85mm` znrj;vSs56pJ#no=(U6;;l9^VCTSNHHzlVStltDJ6W#**jCFZ7Dl>iwG1&QgYdX@Ty bX0h>LW(A0ueIuy=sGPym)z4*}Q$iB}6O3|w literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/pure_flyer.png b/forestry_resources/assets/forestry/textures/items/analyzer/pure_flyer.png new file mode 100755 index 0000000000000000000000000000000000000000..0f96a478a5036f7853338c00c33ffc0452560cb6 GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFFi?BqT8E+` zH$NpatrE9}@ST4T0W~OtY)H$@NzF^lO|>ckG8hUH(^K^-^$pEp14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>V8U zYn)+V(AKwzPp=9HOZ)%-zu~rD8-XS>CV9KNNWRJ2+5zNn7I;J!Gca%qfiUBxyLEqn zf_0uQjv*44Q~N#n4lD4u%BnG|9rRKCZl9^Uae>yopPuzhJEoXjQ?$z7vdf`P-XO?J z#IQo~)P4R`y;ft}?coa!JI6%7U)yKc#MXR7<@?O_3?>Q5>$Y?>WE>PUk8)wKJP`7W zjnn^w^2}b>O}_V2cO^gXx_k7NR#}MsvA^g4GugOtAAb7nWG>JpswJ)wB`Jv|saDBF zsX&Us$iUD@*T6#8$UMZ*(#pWt%FtZfz{twLK<$ZZ9g2qB{FKbJO57U4cm6#D)SwKq wAuTf}H7_wY)v5%@U?@mTPt~i`H#Ccl2Qw=`%zopr03H34r2qf` literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/analyzer/queen.png b/forestry_resources/assets/forestry/textures/items/analyzer/queen.png new file mode 100755 index 0000000000000000000000000000000000000000..4b0ace511c41c71b994a8b783f92d45dd2b05db6 GIT binary patch literal 473 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 wZDl%iX>4TxaA9Xz>% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/apiarist_armor_1.png b/forestry_resources/assets/forestry/textures/items/apiarist_armor_1.png new file mode 100755 index 0000000000000000000000000000000000000000..44acd522155d54eda63aba28dfdcac4c55503179 GIT binary patch literal 798 zcmV+(1L6FMP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01m(a01m(bYSxJf00007bV*G`2iyb@ z3?ME{`B$O<00N##L_t(&-tAevj@m#Fo<$TF0g+G|5HuiS=^`EhiIfyHp|~O)-Xf*r zv}x%H1?dcR8Y)L|83{kZL4hn}r?4*RB4G~FZHfqoHU3!}IG@o?GuoZctDV`I+1W9I z03z0e_{mYOgCN0_Ww%@z_Iv=XoMY?-9nIh$Kk}V@wRgK$S`*GT*Hu4cZ6`^4|ImK4>G9>%^M` zMNvc;_fM}pBab@_QvH6P+SD=18-_tC_s_WA%8Q~He+~$W@pE%{qL`E5!L2}Usqyvo z4RuP3#e({#*Xu#I+l5l8^uK?Qt-;;h3p5^&K~WR{0GLic6Id_d{{D}D!C81qt>0)g zDEai;2Wmf9kU`Tl#Bm(aG!3b$dd9avL@Jld)Hsv5a>cnBr`2kCm*wjvRI6140A$Bi zRYi}^0LPG`D7FDj(}a)0D@v~GI@xSCNY{0uXllx;^ z5fAyXc;+!n2<%Syq!hM?5JS)5sU^k&Di-o~9#~mhrYkKerNe~_jGK@we#Pd9f!XLa8M!Ak>r`fG4W5GvNp2Y}fc?*PXb^GDZ csXPF{U$hRntb7!@9{>OV07*qoM6N<$f`*k`K>z>% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/apiarist_armor_2.png b/forestry_resources/assets/forestry/textures/items/apiarist_armor_2.png new file mode 100755 index 0000000000000000000000000000000000000000..43ce12a6f48f8bee5fbedfb448ac9dbe0b0ff731 GIT binary patch literal 830 zcmV-E1Ht@>P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01m(a01m(bYSxJf00007bV*G`2iyb@ z3?DCJAWaAW00O>AL_t(&-tAbwZ`wc@eU2EYOe&!c1;GNMmQwK_6v-RD@4Me8 zzyVZiZ1oH0?{LfraH&Em>vDa7V@H5nX%5ydDMyAgSL#seWCHh=fD=T(mHGtcy!Qm0 z*wA;EfD`O_V;gtc=MUZhpU)9zN}&k=Pzp^T^p@e?&sUb^yndtJE$lm})&L;{lu}FX zcDo+^cU^?ob3BSs9Y{HjoKyn(P+d3_cyur!551~|JMMgIeutGz@t)E2 z`+Y`VDwUASY8VL(d=X~D#hFkqU?iztr@Lurz{Mp8wT(^xtZ2Y_Gxow^)ukEJwgpTQGroT_cWm1Q?5(X%yJ`jy?gqEP%7w z1I4UoD(pG@#IF~{py2x==#(H)3<_7*w~zcXZOvw#gZ`gDmSxDY45~FK)f!Zv)R}Kp zzS8CMdFIn6bxH`K06++#%O^IveDd1hm5xWhtQ$+MC+1FoU4Tx0eNwj%%EV@!lYXu4 zgC#+bWtk~Rr_+qx>-Dz!zkYc`4>>}wu5X2EwF*KAys#7g0HTDuEIVthM*si-07*qo IM6N<$f&g}Z&j0`b literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/ash.png b/forestry_resources/assets/forestry/textures/items/ash.png new file mode 100755 index 0000000000000000000000000000000000000000..a6daf7bafd169429d0925849973b65af2789bf26 GIT binary patch literal 3033 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 LNkvXXu0mjfmL*B` literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/backpacks/t2.cloth.png b/forestry_resources/assets/forestry/textures/items/backpacks/t2.cloth.png new file mode 100755 index 0000000000000000000000000000000000000000..c179ef3ea987afe270cc6382b5a7fa3856553514 GIT binary patch literal 3048 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 Hu0mjf*daws literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/beeCombs.0.png b/forestry_resources/assets/forestry/textures/items/beeCombs.0.png new file mode 100755 index 0000000000000000000000000000000000000000..9f3a69aeb379686225ba8ec0f31b09af27149f12 GIT binary patch literal 3045 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.png b/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.png new file mode 100755 index 0000000000000000000000000000000000000000..bf43cf61152a94e6b82f03b17165599de80bf08a GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^0ze$V!3JWj{>lra*pj^6T^Rm@;DWu&Cj&(|3p^r= z85p=;gD_)LH*XYBkiEpy*OmP)3opBc{4ckf<3OQx=zbCQ&Q!fqOw9e~X z+wN_N*Uet4t~99b=loV%5uK7K$?%}aPU$qaxORb|!lpF7W+k_-v%4>RnpgkXHSgV> zf+zbmJ~h^S*lM@oz!ZLwpAL3Ej!c}!|AhIc!*|xo2kEs9HyS^MNic|?zUtlS-^lo& yYPWyitAu~fKT2*S@4dNGMBeAnr^a{O=WQ6+mdHEDvdjZ{hQZU-&t;ucLK6Vv!+TEv literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.png.mcmeta new file mode 100755 index 000000000..0e1c12b68 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":5,"frametime":1,"frames":[{"index":0,"time":64},{"index":1,"time":2},{"index":2,"time":2},{"index":1,"time":2},{"index":0,"time":96},{"index":3,"time":4},{"index":0,"time":128},{"index":4,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.txt b/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.txt new file mode 100755 index 000000000..1ec941484 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/drone.body2.txt @@ -0,0 +1,8 @@ +0*64 +1*2 +2*2 +1*2 +0*96 +3*4 +0*128 +4*2 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.png b/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.png new file mode 100755 index 0000000000000000000000000000000000000000..494920b75ffe3577dd15e7b66472ae6a7ea3362c GIT binary patch literal 366 zcmV-!0g?WRP)3hM!aiw#-;000McNliru-2@E?03YUshXDWp0RKruK~zY` z?Um6D!Y~X(-&GxtvDg6iV+JNTKGL*K(i8*~fkZ0x!*@By_9=l~mThms%fAaZ6g$aw z;XAwgY3LuPsHAt|g3{A@{48}PE1J0vxhL;hx~Dbp6v23lV1zPdScQR18Ru{gsw9rZ zt_DtJF5x;&w+bzlq(-$Gvr_J)r+p1&2%;^+Xo!hzG563ZaU7PXKA0f4*EIir*xL^v z6nTXogoT$&W5o|(ko@<<@B2YmH7h89t3gki_5Bcg^5uSD+YjKgitDiYeB#0h+qm%q z_^bnPjrL1iW2fC0j&m%+m>PD+FwHDp@k239h1Vb}j1hJ{^v}E(H!8{i0!cf(YXATM M07*qoM6N<$fn+a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.png.mcmeta new file mode 100755 index 000000000..0e1c12b68 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":5,"frametime":1,"frames":[{"index":0,"time":64},{"index":1,"time":2},{"index":2,"time":2},{"index":1,"time":2},{"index":0,"time":96},{"index":3,"time":4},{"index":0,"time":128},{"index":4,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.txt b/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.txt new file mode 100755 index 000000000..1ec941484 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/drone.outline.txt @@ -0,0 +1,8 @@ +0*64 +1*2 +2*2 +1*2 +0*96 +3*4 +0*128 +4*2 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.png b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.png new file mode 100755 index 0000000000000000000000000000000000000000..0f63aaf51876f1dac737a719a69769eb2a2031db GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!3HFyJAa%3QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0WWg+Q3`(%rg0Ktc8rPhVH|yR6J2qADwP^eh7kNtL)plmzFe zm6RtIr7{F0X6BXX`MHKDlo{)p>KPgsd?{K8RQ1Et#WBRgd+Ag~z7_)k*Y6cFi?=`Y zQeokDRN!bza7-##akI|Q`*h904Ubwsefodp!Y59}Kde*bR(x?-+7S?Otz(f!M&!=t zy&i{O?>ct;G~@9?4z`k5@%VTihss&YcI-LzV4k^C^I?M-ch7$|sZ=((vu*8_(z(2a zya_f^3=unZyk{*nV%@!IuBeu6z{^H2{*bB#mzaUZv%HB;u+)l_+^|M4Gcj`7j|$6# z`{g&c`4+5*<2_JoaQ^dpo*R`0PKO^`c!h=*R`PmWtO;Y2%9!Q$YhS;2G~2B6r!?10 yS+sM_lu2!m&pz4D|Dm2igLxVw#Q5`^^YwozIsP-86W$IC0|rl5KbLh*2~7Y9!JerA literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.png.mcmeta new file mode 100755 index 000000000..952d5f222 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":2,"frametime":1,"frames":[{"index":0,"time":64},{"index":1,"time":2},{"index":0,"time":48},{"index":1,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.txt b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.txt new file mode 100755 index 000000000..c3822c62c --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body.txt @@ -0,0 +1,5 @@ +0*64 +1*2 +0*48 +1*2 + diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.png b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.png new file mode 100755 index 0000000000000000000000000000000000000000..a50272330d1f3049a2158502b515a66de447914d GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!3HFyJAa%3QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0WWg+Q3`(%rg0Ktc8rPhVH|yR6J2qADwP^eh7kNtL)plmzFe zm6RtIr7{F0X6BXX`MHKDlo{)p>KPgsd?{K8w29Tz#WBRg`|cD&u0sw2uG=?XtbWSV zCBdzDD?_uhX>CsSM59=~gqcdyH+hQwJvh*gi=_*j_eY0o{y;X_4C*Y8_k)2?MKfeQrg_)8 z`0au!|IK*V#5o@7{aE>+a&q28hR=2mj1!oqF+xnaFTC4YFVdQ I&MBb@07WyOHvj+t literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.png.mcmeta new file mode 100755 index 000000000..952d5f222 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":2,"frametime":1,"frames":[{"index":0,"time":64},{"index":1,"time":2},{"index":0,"time":48},{"index":1,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.txt b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.txt new file mode 100755 index 000000000..c3822c62c --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.body2.txt @@ -0,0 +1,5 @@ +0*64 +1*2 +0*48 +1*2 + diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.png b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.png new file mode 100755 index 0000000000000000000000000000000000000000..44430b19e6cda09c512f9f7e5ef5b142b21a607c GIT binary patch literal 403 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!3HFyJAa%3QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0WWg+Q3`(%rg0Ktc8rPhVH|yR6J2qADwP^eh7kNtL)plmzFe zm6RtIr7{F0X6BXX`MHKDlo{)p>KPgsd?{K8RQ2A|#WBRg`|cD&zGedfmb*{0|0wo) z?^@zF@4@qcpbwf-;ZLr8QhXDw;#Xps*<$i$o&!g_#ADqRUmTXQYfW8y&Vc8OodMIs z%wINH;@+ngZB}(t=xFMh_Fc7BOrmjtPrTl~^GwPDQw*OL*0fEzr(bnt(RWHY{r$RtmyKThAyo@5F;A5P+NNspXX+RA zpcOIK*IV*O@JW0;{@iizyNrFB%qoH}4w(3T_KkFuT6k)k&gr-iliMQw9xHhGgdW)O nf3R%SOOOOP);6GWu0-AB>!#aQJ)a~F^g4s5tDnm{r-UW|Fg}#a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.png.mcmeta new file mode 100755 index 000000000..952d5f222 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":2,"frametime":1,"frames":[{"index":0,"time":64},{"index":1,"time":2},{"index":0,"time":48},{"index":1,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.txt b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.txt new file mode 100755 index 000000000..c3822c62c --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/larvae.outline.txt @@ -0,0 +1,5 @@ +0*64 +1*2 +0*48 +1*2 + diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/princess.body2.png b/forestry_resources/assets/forestry/textures/items/bees/default/princess.body2.png new file mode 100755 index 0000000000000000000000000000000000000000..d23d00bb80074bb4e76f00100c9db5b68116691d GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^0ze$V!VDxIwZ5l*!&%@FSy0mP{@Rn5sZfd%$O$X=mju_ zi>q&7Xzu0?QSD~#W}fnrDcQn7Qb&hp3G=Jn?X8IucC{xK>|hs+=b5srol|Yq8iwKs mh8wm#r3hM!aiw#-;000McNliru-2@E?03YUshXDWp0RKruK~zY` z?Um6D!Y~X(-&GxtvDg6iV+JNTKGL*K(i8*~fkZ0x!*@By_9=l~mThms%fAaZ6g$aw z;XAwgY3LuPsHAt|g3{A@{48}PE1J0vxhL;hx~Dbp6v23lV1zPdScQR18Ru{gsw9rZ zt_DtJF5x;&w+bzlq(-$Gvr_J)r+p1&2%;^+Xo!hzG563ZaU7PXKA0f4*EIir*xL^v z6nTXogoT$&W5o|(ko@<<@B2YmH7h89t3gki_5Bcg^5uSD+YjKgitDiYeB#0h+qm%q z_^bnPjrL1iW2fC0j&m%+m>PD+FwHDp@k239h1Vb}j1hJ{^v}E(H!8{i0!cf(YXATM M07*qoM6N<$fn+a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.png.mcmeta new file mode 100755 index 000000000..66c135896 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":5,"frametime":1,"frames":[{"index":0,"time":128},{"index":3,"time":4},{"index":0,"time":96},{"index":1,"time":2},{"index":2,"time":2},{"index":1,"time":2},{"index":0,"time":64},{"index":4,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.txt b/forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.txt new file mode 100755 index 000000000..91fce38b1 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/princess.outline.txt @@ -0,0 +1,8 @@ +0*128 +3*4 +0*96 +1*2 +2*2 +1*2 +0*64 +4*2 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.png b/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.png new file mode 100755 index 0000000000000000000000000000000000000000..2cf8292d45a12df9146449844600f1e67a862cdb GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^0ze$V!VDxIwZ5&4ZqIg^?m z-oFhLZmvs_pOe26$YLxB@(X5gcy=QV#7XjYcVXyYmGuB}I14-?iy0WWUV|`WQ#WrE zP>{XE)7O>#E(yb)yAjAb tyu_C$fzO*^cl*I3yszXoFigF~&+yGoUN7dg&~%`c44$rjF6*2UngE!{PZ0nB literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.png.mcmeta new file mode 100755 index 000000000..ec8d8cac2 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":5,"frametime":1,"frames":[{"index":0,"time":96},{"index":3,"time":4},{"index":0,"time":64},{"index":4,"time":2},{"index":0,"time":128},{"index":1,"time":2},{"index":2,"time":2},{"index":1,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.txt b/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.txt new file mode 100755 index 000000000..f873d1c37 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/queen.body2.txt @@ -0,0 +1,8 @@ +0*96 +3*4 +0*64 +4*2 +0*128 +1*2 +2*2 +1*2 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.png b/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.png new file mode 100755 index 0000000000000000000000000000000000000000..494920b75ffe3577dd15e7b66472ae6a7ea3362c GIT binary patch literal 366 zcmV-!0g?WRP)3hM!aiw#-;000McNliru-2@E?03YUshXDWp0RKruK~zY` z?Um6D!Y~X(-&GxtvDg6iV+JNTKGL*K(i8*~fkZ0x!*@By_9=l~mThms%fAaZ6g$aw z;XAwgY3LuPsHAt|g3{A@{48}PE1J0vxhL;hx~Dbp6v23lV1zPdScQR18Ru{gsw9rZ zt_DtJF5x;&w+bzlq(-$Gvr_J)r+p1&2%;^+Xo!hzG563ZaU7PXKA0f4*EIir*xL^v z6nTXogoT$&W5o|(ko@<<@B2YmH7h89t3gki_5Bcg^5uSD+YjKgitDiYeB#0h+qm%q z_^bnPjrL1iW2fC0j&m%+m>PD+FwHDp@k239h1Vb}j1hJ{^v}E(H!8{i0!cf(YXATM M07*qoM6N<$fn+a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.png.mcmeta b/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.png.mcmeta new file mode 100755 index 000000000..ec8d8cac2 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":5,"frametime":1,"frames":[{"index":0,"time":96},{"index":3,"time":4},{"index":0,"time":64},{"index":4,"time":2},{"index":0,"time":128},{"index":1,"time":2},{"index":2,"time":2},{"index":1,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.txt b/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.txt new file mode 100755 index 000000000..f873d1c37 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/bees/default/queen.outline.txt @@ -0,0 +1,8 @@ +0*96 +3*4 +0*64 +4*2 +0*128 +1*2 +2*2 +1*2 diff --git a/forestry_resources/assets/forestry/textures/items/beeswax.png b/forestry_resources/assets/forestry/textures/items/beeswax.png new file mode 100755 index 0000000000000000000000000000000000000000..6d8a4070bd7e6a59d83e8749d0a4559e3e7c7387 GIT binary patch literal 3043 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 lWiELyF*aRaaA9XQQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw00006P)t-sSiv^`|NlfWb5Q^Q00Cl4M??Yt0xjME000SaNLh0L01m4F z01m4Gj_kzz0000CNkl4TxaA9X< kE_p98HeFwEVP|D7crP(FU2E84Z~y=R07*qoM6N<$g7}YB@c;k- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/biomefinder.mcmeta b/forestry_resources/assets/forestry/textures/items/biomefinder.mcmeta new file mode 100755 index 000000000..de7ddb4ff --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/biomefinder.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":1,"frametime":1,"frames":[]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/biomefinder.png b/forestry_resources/assets/forestry/textures/items/biomefinder.png new file mode 100755 index 0000000000000000000000000000000000000000..2b4122bdd1da3bd66d84a575fe066945a05ab08e GIT binary patch literal 1239 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/catalogue.png b/forestry_resources/assets/forestry/textures/items/catalogue.png new file mode 100755 index 0000000000000000000000000000000000000000..2a414a1808b06ff8dff1305a41a29bf684d4b1b8 GIT binary patch literal 408 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/caterpillar.body2.png.mcmeta b/forestry_resources/assets/forestry/textures/items/caterpillar.body2.png.mcmeta new file mode 100755 index 000000000..3e353516f --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/caterpillar.body2.png.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":2,"frametime":1,"frames":[{"index":0,"time":7},{"index":1,"time":3},{"index":0,"time":9},{"index":1,"time":2},{"index":0,"time":5},{"index":1,"time":2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt b/forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt new file mode 100755 index 000000000..1f70057f9 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt @@ -0,0 +1,6 @@ +0*7 +1*3 +0*9 +1*2 +0*5 +1*2 \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt.mcmeta b/forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt.mcmeta new file mode 100755 index 000000000..312732717 --- /dev/null +++ b/forestry_resources/assets/forestry/textures/items/caterpillar.body2.txt.mcmeta @@ -0,0 +1 @@ +{"animation":{"width":1,"height":2,"frametime":1,"frames":[{"index":0,"time"7},{"index":1,"time"3},{"index":0,"time"9},{"index":1,"time"2},{"index":0,"time"5},{"index":1,"time"2}]}} \ No newline at end of file diff --git a/forestry_resources/assets/forestry/textures/items/chipsets.0.png b/forestry_resources/assets/forestry/textures/items/chipsets.0.png new file mode 100755 index 0000000000000000000000000000000000000000..6ae93b3af3cc5eaceee7094eaaea40a95961950a GIT binary patch literal 3134 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/apples.png b/forestry_resources/assets/forestry/textures/items/crates/apples.png new file mode 100755 index 0000000000000000000000000000000000000000..41d47c763e252cef5ec7fa8b10ac333bd30fd6e2 GIT binary patch literal 483 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>8MU-v7DXc}LCvs7y`~xX7Hc$i+eG#SiJF8JZoRU&kHmnlW+x!*}nG`JFk?{$L$L z)a~u=n&vm^)|S3$$>P0x>}JB;stZNT$`+!tBGX@dmUyhWjL}}lxj@ys`;KP^`wwdt zmpe88X9_$=BH$)RpQnVxwCc;P=hkahP2F_)V##pRI3sogP|ZXJyow#-_R^J9?Yx&F|%(Z Q6@V=8boFyt=akR{0N3N0_W%F@ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/ash.png b/forestry_resources/assets/forestry/textures/items/crates/ash.png new file mode 100755 index 0000000000000000000000000000000000000000..c2d0c215d248bc0da7cd0ba41fcdbc89269e340b GIT binary patch literal 484 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFB6rsA0cubN*^ri*lbV;9n`%`8WH1yYrl;yv>KmHH#)Fv^AZGTB Qqymryp00i_>zopr0I7DC5dZ)H literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/beeswax.png b/forestry_resources/assets/forestry/textures/items/crates/beeswax.png new file mode 100755 index 0000000000000000000000000000000000000000..80ce6eeb16335d174f5f2ac93aaa17c8a8070101 GIT binary patch literal 483 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF#jVc&|NkGm_u?E-nz1CvFPOpM*^M+1 zC&}C0g)e`vfj^MLS>O>_%)r2R5QG_bOw4`@6fE_0aSY+Oo}3`U!pO?T=BBKgD*RMI z;joUOude2v#>R^go+pn=9O2+)S;c7BGbK$*vQffo(rWdc4Oh=Zl?HJhnGmz}+Zh*u z!$ogb83!N8DqCyAJiwt|WZ}=m^yk*NBpo#FA92Q(9+n#IP0nH3;r S_Kl14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>~Q?gt!9f;yBCsExvnZ zByE`xl^J3T6!CLVkM`6_4r2ZLYX9$x{KuDZ*JrW!)^O}zz&*d6Biw`a|NsA{Cf-g! zrHmy(e!&b5&u*lFI7!~_E<)9Na)4|G&H|6fVg?4jgCNYfV`BDOpkRroi(`nyW!Jty zp%w!UXGMpp*IrfqKdl$$ZT#nn?}?U<=??u70z!cu4_TKMXm)JQl}~U9akWcGi$CtO zM|Q$brVXpAY*O2ITrW#dyOEu{_Uk-ZIlU8>@ejiD_kZ43++M}cz9vyeS~Gb=#M>>Ei1APYQQ{an^LB{Ts5Vi}zb literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/brick.png b/forestry_resources/assets/forestry/textures/items/crates/brick.png new file mode 100755 index 0000000000000000000000000000000000000000..65c3553bd225d14545324674c347d30db0ef1669 GIT binary patch literal 549 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>C0VBhO!TjOe$ZKL1hY0>Fpy)@c=euQg>kJa)x_hwJa z>A{YRqun7?=QSz7Zc30tgS*B5|NqrK=Whj?$XF8O7tG-B>_!@h zljQC0BG1YzuouYTEbxddW??)FK#IZ0z|ct7z+BhJAjHtn z%GAKh)L7fV$jZP#14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>(#dJ_HTlsKl0k2Z1L&1#Pnr?1mETc(e)FHPf6D8dV5$xQ1IFL zfUE11)$Z|qs9~JcF~i=KefHF<1hq+1gR*VUzc2`2yVWi}VgKr{b@w+qzbRr}llW$_ z1<#8li56XnSsDB>e;C=1v9uW|=T8Q@K()j*q9i4;B-JXpC>2OC7#SEE=^B{p8X1Hb z8d{keSeY7Y8yHy`7-&2>3RI7zAvZrIGp!Q0hRB_@dw?30K{lji=A`B&=B8Se02vGg hiRr0&mHLKevGHJL1&En_BdGvnfv2mV%Q~loCIF1#p&tMM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/cacti.png b/forestry_resources/assets/forestry/textures/items/crates/cacti.png new file mode 100755 index 0000000000000000000000000000000000000000..9214a36d72fe5cfca4f75ef7de897a596ceba8f0 GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>=!i%CFE(f`fUW_87zosnj2*wpmFTd_wVbV(b3g5DX4tJ`WD z7GClC!tQG^PbO&D!S$0vL!XI@gjVk^_FY_m#Dyr(~v8;?@wkvvvbP0l+XkK8O)%; literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/charcoal.png b/forestry_resources/assets/forestry/textures/items/crates/charcoal.png new file mode 100755 index 0000000000000000000000000000000000000000..c1ad81ca5ecda7597b0b03bfd40e6ffc4b2f329b GIT binary patch literal 522 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>G0H#0MnmX_Aj)6>@0R!~qdHa6DK&`?!X6%`d#R#xWX z;^OA!=H=z(=jZ?b|No@SCLW-E#*!evUY$v1ghJAfR{0*}aI1_r)^ zAk4U9V)k30V6~@IjMPxxv5qqKn6oWVtT4xrM{tAY&@7*0b*v~NGbqX;OXk;vd$@?2>`$e BnXv!> literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/clay.png b/forestry_resources/assets/forestry/textures/items/crates/clay.png new file mode 100755 index 0000000000000000000000000000000000000000..d8385fb7e3aada1c384c0126d8c6114dd3aee9b8 GIT binary patch literal 483 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFHTe8P0HWWH^x!pwHgK#m2_g$ET2yz`$_ioVuW1 z*eX+?15`^~BT7;dOH!?pi&B9UgOP!uk*14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>G0H#0MnmX_Aj)6>@0R!~qdHa6DK&`?!X6%`d#R#xWX z;^OA!=H=z(=jZ?b|No@SCLW-E#*!evUY$v1ghJAfR{0*}aI1_r)^ zAk4U9V)k30V6~@IjMPxxv5qqKn6oWVtT4xrM{tAY&@7*0b*v~NGbqX;OXk;vd$@?2>`$e BnXv!> literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/cobblestone.png b/forestry_resources/assets/forestry/textures/items/crates/cobblestone.png new file mode 100755 index 0000000000000000000000000000000000000000..b4886b481b6cc512d39ebae6c0991fc0e56d9584 GIT binary patch literal 632 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>hg4aZOE4b#-+e9UYC0jceAdnJ{6( z?AfzZQ&WS2f;u}p6B837BO@0tUc7qs>Xw$4w6wI6l9KrN_?(=a|Ns9-nHt6dt!FI> z@&kF4f#Fa#+eRS8nB?v5V&rhi=LC?$S>O>_%)r2R5QG_bOw4`@6rAPh;us=v*|qCbKkXJN(${`Do? z^=vajEP<|6Epd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_ z)gx)h%}>cptHiA#a%b%xpax}-4QZJFVdQ&MBb@0QZdPQ2+n{ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/cocoacomb.png b/forestry_resources/assets/forestry/textures/items/crates/cocoacomb.png new file mode 100755 index 0000000000000000000000000000000000000000..1778d1c133ebf2cb321fc1082ed7f36e87f8afe1 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFn)WFKrSlhtJ%D_P5$x)zsBn`Rw zDVb@NxHUxXtlb0DpbWAhEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1APYQQ L{an^LB{Ts5iU*G3 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/cookies.png b/forestry_resources/assets/forestry/textures/items/crates/cookies.png new file mode 100755 index 0000000000000000000000000000000000000000..e0c3418c8d6436d40b35c0793e8d653108eb4840 GIT binary patch literal 486 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>w&z471rz_Ztg4gMW}I=8VZHvw z>I5b2!kKp;mqmA`)y+H}a-7Hb&hn7sJwdZqSi8()h(2<2&h@=ayF48&y6$wIQ<^5P zuFf(is*a-14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>*(X{eV2ND`@)q^*BH%?SKE-Sy*5+JO|g!0?*2ySH$|*#65lMg z;CYcG(V{CcD}z7g414Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>~Q?gt&hE_z}o__Uzf7 zJ$trp-C7)HIlsks&y1uk6QVLhjDb>q4(idKIy+lqrsa55hFV41YPPqx|NsAg*JAN< zpfqbqkRQk)3=D^|*){?x#w2fd7oqAsIUq640*}aI1_r)^Ak4U9V)k30V3ntfV~E6M zSN}kCs6e)%_DcGt?r^%I`7PI=K#d`@#>fy0swA^!x|24>4d&$sK;)O3B~ zA7UyYvtVgJPhqT>+2;udP6zG@V4c?VsB7XTW1V;FzUgrv*5SFaP-y1mk}l6FQg78h zKCCk6c>O4S@$urH`+mFa`OljCm}66>c~>*g6{;n!5hW>!C8<`)MX5lF!N|bSNY}tz z*T^8m(9p`%z{=EE+rY@mz(C{4QIKB{8glbfGSez?Ylz%gy9cO28Dv9RW=?8eVs5Hc m36Q~1keHsTSE+Ak78?&{R)Cn+)? z^wrhe)7W@1!t>-&i6b1mEUOp|drZR5nlTwpxpv0pDN|C!*;zY_1UnQfU!9rNnGmZT ze)bkq@M4yv85Oy4ENK$6C8QfAd=@G&q!_H2&g{s_%*^c0E?@%m>5t>;$F{5690gjh zTH+c}l9E`GYL#4+3Zxi}3=EBQ4a{|o3_=VItxOH9OpUb-jI0a{G@gLeBWcLZPsvQH z#H}H6XYC%K24#>9X_+~xd5O8HRwY0NLqTGCs$QkOp;>G^m{|d0X5UCE09oMa>gTe~ HDWM4fU>}bx literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/fertilizer.png b/forestry_resources/assets/forestry/textures/items/crates/fertilizer.png new file mode 100755 index 0000000000000000000000000000000000000000..5b40a22d8509aba392f54f4e3b819549eabe1998 GIT binary patch literal 484 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFg)|NoGq79dL)OM?7@862M7NCR<_ zyxm>+^7k6}138=p9+AZi415Pcm~qF%?6*L{GEW!B5RU7~2_h_vtZZy<%BrctPZbmn z>lpg#YVK)lycpqm@~FfS4&FJM8XQRynd|1Iuq0`mwcLD}bxqpURkytq+McWou2yf7 zn6}#Q?L4Ni&DCFHH%#d~?W1aN_{NbN97htkSQ!hExvr5xh@qjCsezTLv9^Jcm4SiAlcPZO zNE&kUQ!>*kachX&S-S_QK^bI2T4qjaUSe*lRSA&6P>`6Os#mFRXcij}W>$ch**B63 PKo)qq`njxgN@xNAy4jQ5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/frozencombs.png b/forestry_resources/assets/forestry/textures/items/crates/frozencombs.png new file mode 100755 index 0000000000000000000000000000000000000000..862f135737f9b57c8e536ca829840479820b2936 GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFp#YoNipu)Y#a#n3+RLg5lu!G0dLL(ALKA|35==GLZZ)&i`#UPz7U2kY6x^!?PP{ zAWo9Ey9>X>E{2;x4rhT!WHAE+-$4*&+%YlxEl{x3)5S4_<9c#}2n!=C8=IT5YO3&4 z1%<;phQ7L*dm0-rMtGh)DshB^mt_^BVb7E_Dal3&uSu)bcQ#x-6IB|-d1OM&)^BHA z1P&LyU1c16AnV*3Ywl@Ag)>*Oq)E({kZzRlS*XB}Vz6R5vm+}rGqXFpfCF!YETB*kd~Q~nwOZHYE=ScFcc)Fr|MPe8=A$&gP9c|X7-Jw P0+0osu6{1-oD!M_4OqsCH?*V85tS>|NnnFXstV1TA}kF&Y+s8MRwN`OJb1y-#Ky+3pho9q zY}9$6hZ$5$Tq8hExvr5xh@qjCsezTLv9^Jcm4SiAlcPZO zNE&kUQ!>*kachX&S-S_QK^bI2T4qjaUSe*lRSA&6P>`6Os#mFRXcij}W>$ch**B63 PKo)qq`njxgN@xNA|16o# literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/honeycombs.png b/forestry_resources/assets/forestry/textures/items/crates/honeycombs.png new file mode 100755 index 0000000000000000000000000000000000000000..d3a7a79d3bde0cc19c413a96df36808a4d9071fc GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFF!YETB*kd~Q~nwOZHYE=ScFcc)Fr|MPe8=A$&gP9c|X7-Jw0+0os Lu6{1-oD!M<5;TbY@1YtV!3L6RZ0F|NrHVU4MYmj3q&S!3+-1Zlr-Y zN#5=*eEE9~{DBn)WFKrSlhtJ%D_P5$x)zsBn`Rw zDVb@NxHUxXtlb0DpbWAhEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1APYQQ L{an^LB{Ts5A#9Gp literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/honeydrop.png b/forestry_resources/assets/forestry/textures/items/crates/honeydrop.png new file mode 100755 index 0000000000000000000000000000000000000000..5b1982267a8d67a036cab4021f853a1584b9f80d GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF_!@h zljQC0!k53-z#qurEbxddW?)FNGyZ!*kutCrn|+>1X{^1)K#=2()y} zxtqxpws>bXSH!6!smp|BB<3XLup}9@HZe>%xFC*?MU;n!M@H7+!T|<`FejCV-*4ZJ z0@|)x;u=wsl30>zm0Xkxq!^4042^UR%yo?nLJSS9Obx6|jkOJotPBh^o*V_LN79g+ zpOTqYiCaVD&e}ad4ay)J(lT>W^AdAYtxA9lhJwWORJ}@lL$la;FtY;0%)XIS0J6Z- L)z4*}Q$iB}jN_1n literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/humus.png b/forestry_resources/assets/forestry/textures/items/crates/humus.png new file mode 100755 index 0000000000000000000000000000000000000000..7505bb06b02f298298f0e4288624e01da5e6fd46 GIT binary patch literal 487 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFiwt|WZ}=m^yk*NBpo#FA92Q(9+n#IP0nH3;r S_KljTa+4Pac&x!okb3iqWtktEb0-M^$jTr(S~Tw9Vf%8YL#JE_=V1 zBPrtDzP-OWI~G=!-T&>c(0209f3F17V`|6T6xf0_I2a^(UOjaPIC$W|fs2eRygUq< zd1@cI3=Q3Z4p1#|jVMV;EJ?LWE=mPb3`PcqM!E*(x<&>ehK5$A23DrV+6G2e1_l~W zjsn#qX~@k_$xN%nts!z}?H-^8WsnVNnK`L>iMgp(B|rv4L1KEUUZuXFS!_I*Spi~Z S-$*I|S>WmF=d#Wzp$Pyq>z3RA literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/lapis.png b/forestry_resources/assets/forestry/textures/items/crates/lapis.png new file mode 100755 index 0000000000000000000000000000000000000000..e8196c42f3c1c37df79c42cf91e90b194e8b7691 GIT binary patch literal 491 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>93-i9*O9!|NsAgieiK(P#t4Q zkY6x^!?PP{AWo9EyNlqXt+u;>9L@rd$YKTtzJnmlxMO1WTcBWxr;B5V#AVmMNTI_D zJkEP3oiJJY-9A@V=#2D#59LaiBhm|{!#qQLuRJx3dVEdge1EZ&aniD1Qt!?=G*qg( zT(B44ptW-UMdPHe%(X{ErzXhNDkS|s;PJP4T^GZNCeOD94{iqeo4RL8KAN35LFVWc zm-LB`_^ofV%sR9FOcT(4)e_f;l9a@fRIB8oR3OD*WMF8dYhbQxWDsI#Xk}_(WooQ# zU}R-rpz-7=P(6}{-29Zxv`X9>B6rsA0cubN*^ri*lbV;9n`%`8WH1yYrl;yv>KmHH Y#)Fv^AZGTBqymryp00i_>zopr0GSD%&Hw-a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/mulch.png b/forestry_resources/assets/forestry/textures/items/crates/mulch.png new file mode 100755 index 0000000000000000000000000000000000000000..8483579b69c7f7d8e27b2fc01d0de6f4a64e78c3 GIT binary patch literal 487 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>sS2x#$x(LrBw%#XWZPpQTXe7zJu#J zHXJ{``iiui;LAcptHiA#a%b%xpax}-4QZJFVdQ&MBb@068O;!T14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>*~g1w$D zjv*44UHfhdH7oGADl&%jh`dO9lXU(6|D#G`Hj}5%*?BTX@d;Z8Yv%-qkOrx+#2yp2 zOD~q4RdS!=^oRTI&3l&~lxIjMPxxv5qqKn6oWVtT4xrM{tAY&@7*0b*v~NGbqX;OXk; Jvd$@?2>|4X#}EJj literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/netherbrick.png b/forestry_resources/assets/forestry/textures/items/crates/netherbrick.png new file mode 100755 index 0000000000000000000000000000000000000000..a330ec97ecf3ac12c6d712c1696da6b4d7865815 GIT binary patch literal 514 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>*~ zf;FBljv*44efw?;9Z}$L7QA9MWz*f;|Np;Q6r0=s$w4jAX^P$qDNhT5lRB;b3$KM} zAJ;#9t2OUrhzL^)kno&1!%AGVR-;k|jGH@ZHJZ^4v^Grf`pa z{293$x-x0uhMhrc?`jt8e8Ke5=%w{VtIntF>ld-s$rr>b0o|cm;u=wsl30>zm0Xkx zq!^4042^UR%yo?nLJSS9Obx6|jkOJotPBh^o*V_LN79g+pOTqYiCaVD&e}ad4ay)J v(lT>W^AdAYtxA9lhJwWORJ}@lL$la;FtY;0%)XIS0J6Z-)z4*}Q$iB}@x`2- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/netherrack.png b/forestry_resources/assets/forestry/textures/items/crates/netherrack.png new file mode 100755 index 0000000000000000000000000000000000000000..abccdde163eb616cf9bfe0fb962d58140d782d3b GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Xo}OxA63NC^ zU}e?J%R4X8ds}vPpoWINsOZh6rWM)2RSphG=H^9QTx&|% zMnvd~i2VQm|B;-0IM98JB|(0{3=Yq3q=7g|-tI1z*BPcd06Clm9+AZi415Pcm~qF% z?6*L{8J;eVArhBe`)&#~8SuE?UZN}F>bh1*??Kb=egFSYkL=1l|3o!C&uF^9E5;y4 zL6Z)i3C_AL3!EC{&XcsER3vdY;MY`slrbc6b|bc z`s!-#X>7b0;d%0?#1W3(m>q!vM+`1S)tuls5-`awbt}u7v}<{%eHGdgu4HydCBJT- z?Ry|=N|+C3Z2~1adeFJR*x382Ao?FyoGi*>8b@rJgR1Asp9}6GT`TS=rd!lvPuO zpDHLE)-m+e)!ftAcrn8BY1q0AkHHbVzz!e z<05dl=v~-Gb)_9k|j-IwuE$}gwH|+h7^Mp)0rJvnVFg0*#%61K2F@F zdV2kPy>CDVsFt`!l%yn14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>H^SW#*!evUYon3beR|7em1s;*b z3=Dh+L6~vJ#O${~!G2E{#}J9ju6;L!4k_@sIx}rqnGslcxOG?l|Nr$tT3>wPik_(z zGalh^>R0Fy@KkASz7UnsTNo0mK2a%1=x=LMo?6Z_Dyr(~v8;?@wkvvvbP0l+XkK;v20e literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/peat.png b/forestry_resources/assets/forestry/textures/items/crates/peat.png new file mode 100755 index 0000000000000000000000000000000000000000..579133265590d0f94ec382d10cb96bf7b03754e0 GIT binary patch literal 482 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>^30{I#YIGh)@ zzMQk`_x-RtGW$MUUZyH~QT{}?5M$hExvr5xh@qjCsezTLv9^Jcm4SiAlcPZO zNE&kUQ!>*kachX&S-S_QK^bI2T4qjaUSe*lRSA&6P>`6Os#mFRXcij}W>$ch**B63 PKo)qq`njxgN@xNASZ0(N literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/phosphor.png b/forestry_resources/assets/forestry/textures/items/crates/phosphor.png new file mode 100755 index 0000000000000000000000000000000000000000..ebdfd4b991721c048643f3f31003e796e0544bcf GIT binary patch literal 484 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFu#{Rxuj(Ofl*0ao|~cRlPUnK-RlCGncR=am>40 zTdfrF;oyQeJ{D0P9v&H4hYJT77#7B< za|-zfYyeuXTH+c}l9E`GYL#4+3Zxi}3=EBQ4a{|o3_=VItxOH9OpUb-jI0a{G@cv< zsz=h0o1c=IR*73f{vX42FWl^i;h{eM7U@crdd9#LT{t QQ~PGOWPF{3T&)HE|NoyIvAh~6$5;~N7tG-B>_!@hljQC0 z!uxGY;#VMtv%n*=n1O-sAP6(=n3(+*C|Kg@;uyklJvl*yg^`tw%}rS~Rrslb!eJdl zUtP^Tjg1#0JWn2#IKt5zvm;R8h{2_(niCvH0w&p|Ze>}Mb}jF;uR>eGmCO#QK2ZJQftEUbD2M-)LaFLOPmxp1=Q`I?K8e1L$ z?N=>vjVMV;EJ?LWE=mPb3`PcqM!E*(x<&>ehK5$A23DrV+6G2e1_l~Wjsn#qX~@k_ z$xN%nts!z}?H-^8WsnVNnK`L>iMgp(B|rv4L1KEUUZuXFS!_I*Spi~Z-$*I|S>WmF K=d#Wzp$Py;9g*As literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/propolis.png b/forestry_resources/assets/forestry/textures/items/crates/propolis.png new file mode 100755 index 0000000000000000000000000000000000000000..53971e4da3a154ba0088be6d8778aa54b595ec65 GIT binary patch literal 515 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>yV9vL>4nJ@ErtU#vK#0 z-vR||JzX3_Brd!5-4;5mz`;7PyE9a(=iC4Kty$VPAGXeAE@n8yd`LxruS3G~gL)E= z;UfvlbE;u2GhgVts4Ow5f5Wn`NblFO+NK%nb5@+Pc!RkHS(*Pq3akEY#4xxvb%`ehK5$A23DrV+6G2e1_l~Wjsn#qX~@k_$xN%nts!z}?H-^8 yWsnVNnK`L>iMgp(B|rv4L1KEUUZuXFS!_I*Spi~Z-$*I|S>WmF=d#Wzp$P!*$E+Cu literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/redstone.png b/forestry_resources/assets/forestry/textures/items/crates/redstone.png new file mode 100755 index 0000000000000000000000000000000000000000..6d00a4b4759129a8ce7faf2f63170465f34faf99 GIT binary patch literal 486 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF?3t1#CD|z9HEFf_&W5XJqDq4}k4%W!`t6L1 zz~Q2|tBivWWSv`M%{|SiaOO&uG>O>~(v1>63l$hr3|35Mc4TE{W_D*6Fai2FahK}p z_3!n*0Ue-P;u=wsl30>zm0Xkxq!^4042^UR%yo?nLJSS9Obx6|jkOJotPBh^o*V_L zN79g+pOTqYiCaVD&e}ad4ay)J(lT>W^AdAYtxA9lhJwWORJ}@lL$la;FtY;0%)XIS P0J6Z-)z4*}Q$iB}qTY=M literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/reeds.png b/forestry_resources/assets/forestry/textures/items/crates/reeds.png new file mode 100755 index 0000000000000000000000000000000000000000..f013d93f008f502bc96ec4d7396976b390c8b3f0 GIT binary patch literal 486 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>^39L0_(a5x(> zMqj-2`+nJ#mA~YrorFX^*-t14$_6i}v|Y8tHKHUXu_Vlzt^7#doc8d#YcYa19@85n3h zISN#dq#-vyB{QuOw}!}_wR?aXltDJ6W#**jCFZ7Dl>iwG1&QgYdX@TyX0h>LW(A0u SeIuy=WPzuvpUXO@geCw1Je$`5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/refractorywax.png b/forestry_resources/assets/forestry/textures/items/crates/refractorywax.png new file mode 100755 index 0000000000000000000000000000000000000000..9736cf4bb67924a6439712e63eb392f648a92283 GIT binary patch literal 483 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFjTa+4Pac&x!okb3iqWuVN}7~pqlDL_)#^JNuAYf14dOg9A!h5hGcE#$ zi{7p>4nB}ow$_Gwno;4*l`Lrzvn8Y(C43etFr*l)n9l6T%FN8{&MsgA^lq${>X!MB zr3`@%P%UwdC`m~yNwrEYN(E93Mh1pPx(4RDMg}2IjMPxxv5qqKn6oWVtT4xrM{tAY&@7*0b*v~NGbqX N;OXk;vd$@?2>^}YjPw8i literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/resin.png b/forestry_resources/assets/forestry/textures/items/crates/resin.png new file mode 100755 index 0000000000000000000000000000000000000000..3560a527b3d963830f5fcd9017d4c218fb538636 GIT binary patch literal 664 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>t|;FGbTng0kY6x^!?PP{AWo9E zyNkoWn=vi^MKOS975?Qd0HvQboEJIb$cMZj><5f2SkuZ40if4a@!FuoY?G1Ft&rI|Vnz6pBq z8q-dRRySRZ+Iul)EAzHazZ-AAvLBx4d!WK-?pg8EQ-5!~ms9@RxnPTW$MVllt9CDb zeeh4kzI*c{UffE#<;s-WBgkaiezWz1Y}HSu_sU#V8=`s{f$mc+ag8WRNi0dVN-jzT zQVd20hDN#u=DJ1(A%=!lrUq7~#@Yr(Rt5$dPmTiBBWcLZPsvQH#H}H6XYC%K24#>9 vX_+~xd5O8HRwY0NLqTGCs$QkOp;>G^m{|d0X5UCE09oMa>gTe~DWM4f+xh0U literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/rubber.png b/forestry_resources/assets/forestry/textures/items/crates/rubber.png new file mode 100755 index 0000000000000000000000000000000000000000..77d5f4be72101a3a43fd16f0c48bf474d8af933f GIT binary patch literal 493 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>$rAMAW`Z~2Qm8=u`=_x$$y>!;`6zqxSFwz|{%r|jR+bnX0%J6Gr5y}sbV z%|&k?ZhLTL<)`Pn5AJHdc5cS~n~PR1&N+Ud^ZLb^AD``d_F(0$D|6mG+IIQO)JM0L z9N*vh;Ofc?CnsJ%KjYrz_!@hljQC0 zVr|LyB?rjiEbxddW?i>}q) z|NiyAy^j~`xhJaWc}CL(UNHta2%2>8OmNn0S>V(lC)eUOgCn`4{-AcC&T7xKez{7y zCeeY{rhQ|v@+z&~G~al(1dsd42;XI9j_IFUqt;!!^!G+i`R~IYMQ#gQ#D99NyVE|V z|I5#=d-LDC?p~-Dx<#9{pkI)Msr@D=r)14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>+W1xaP8dOTbGudJJECh#+Lot z3y&RWyL)5x-D_*!KHLBJ7Er;$H;=d6y0rSy?Nvwj)!w)`YUi`)&`xyXM()aO^dX{XbzF21X{ z8&_{|h0{vPzv<~<7QW-b1^Z(1mmUB6v1YIRJ9E9ZO(8e*gbpN6 zQAm)y;@6Qo;WU5YE$+R?6_Uz<&QvXNjVMV;EJ?LWE=mPb3`PcqM!E*(x<&>ehK5$A z23DrV+6G2e1_l~Wjsn#qX~@k_$xN%nts!z}EhyZSK{lji=A`B&=B8Se02vGgiRr0& dmHLKevGHJL1&En_BdGvnfv2mV%Q~loCID%#FpmHL literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/saplings.png b/forestry_resources/assets/forestry/textures/items/crates/saplings.png new file mode 100755 index 0000000000000000000000000000000000000000..58caa9acfc507c08a1fea650735085a4b3c4eb5d GIT binary patch literal 478 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF9 znO2EgL*&ldJwOf0ARE#$b5ipXb5pHKfDDF$#Pn3XN_|7K*my9r0>sR|kyHS(z|+;w JWt~$(697&9kmLXW literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/scrap.png b/forestry_resources/assets/forestry/textures/items/crates/scrap.png new file mode 100755 index 0000000000000000000000000000000000000000..06d3b30410bd897e563c623c24018dc7179d1f79 GIT binary patch literal 497 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>;OkH}&M2EKzJ%(!D>_FJG}iKmNWh{R>r zzG$Jt1{}b~}N-5e|7*3#^^KMbsY|W!^Q-5zZ3+I08*T;eOtCqM%l%ynYzWlug{y+|Afk$L90|Vbd5N6ylG5al0u*lQJF@)oKa)Jm8BP$!5o3d)E@KXha z!#ak(x|(|$8!tw9o;)gXgoBr56{BH~nr5_AqlA}tOi#>#ET1*Ke2o%K8x0#1OvB9D zPN^lBdUe-Mao`c2e%Q-P;OH?o1-4)f4hBh{S5F-R4jwpg;36XnFAu|Se+AX!`rqdP zZC5REjVMV;EJ?LWE=mPb3`PcqM!E*(x<&>ehK5$A23DrV+6G2e1_l~Wjsn#qX~@k_ z$xN%nts!z}?H-^8WsnVNnK`L>iMgp(B|rv4L1KEUUZuXFS!_I*Spi~Z-$*I|S>WmF K=d#Wzp$PyUmy9(4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/simmeringcombs.png b/forestry_resources/assets/forestry/textures/items/crates/simmeringcombs.png new file mode 100755 index 0000000000000000000000000000000000000000..615ed9399962bbd6de33b900ef3d463fa9e31461 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF_!@h zljQC0!k53-z#qurEbxddW?zm0Xkxq!^4042^UR%yo?nLJSS9Obx6|jkOJotPBh^o*V_LN79g+ zpOTqYiCaVD&e}ad4ay)J(lT>W^AdAYtxA9lhJwWORJ}@lL$la;FtY;0%)XIS0J6Z- L)z4*}Q$iB}f)|l1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/soulsand.png b/forestry_resources/assets/forestry/textures/items/crates/soulsand.png new file mode 100755 index 0000000000000000000000000000000000000000..1496527d921d2a71f0ab5b963e57514f50b5f6a8 GIT binary patch literal 623 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>w=AMR_!@hljQC0V&rhi=LC?$S>O>_%)r2R5QG_bOw4`@6rAem;us=v*|qPcP_qJ$t0LnS zv4gj6g7%?mMq%!fs)uo6qyxIrcB#d}-~=L;SJn;-$I0_Kj!m z>~gv*ztBC>HvavS&$8VMb+2xhX89nf&f&tiU08_y%_nAGW=ehK5$A23DrV+6G2e1_l~Wjsn#qX~@k_$xN%nts!z} z?H-^8WsnVNnK`L>iMgp(B|rv4L1KEUUZuXFS!_I*Spi~Z-$*I|S>WmF=d#Wzp$P!Z CddA2A literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/stone.png b/forestry_resources/assets/forestry/textures/items/crates/stone.png new file mode 100755 index 0000000000000000000000000000000000000000..80e7f2c54d634279f8c3de80d20bdfca94bf7b27 GIT binary patch literal 659 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>q>L;+lmTT%$>7w+3MV! zoXs27FYIoe+|yH0T+%;bQd&af^zM$ivu4enI<>aCw!W@@QcrhVZB0#GV_QpGVNOnD zaA0Vl|H2tlCr_EaeBr!FogD>Dl#_W$V|j?QW=Rt|+U`&-(xWe@B3kAJDmsB|(0{3=Yq3q=7g|-tI1T zo+%8EfgH{PkH}&M2EKzJ%(!D>_FJIfR8JSj5Q)pKec?if6?j-3ncisZwcPvt)t7m{ zOVf0YQ@vrT{0cDUZAwUO_QmvAUQh^kM zk%6I+u7SC(kwJ)|p_QqDm8r3|fsvJgfyR@gK=nu(a`RI%(<*Umh}>Db2dF_AWJ6kJ tPHJ9aZmLxYkik%pn4YRvsc&c&8xLkyfSB1gk_tc;c)I$ztaD0e0swbz`6B=T literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/stringycombs.png b/forestry_resources/assets/forestry/textures/items/crates/stringycombs.png new file mode 100755 index 0000000000000000000000000000000000000000..8e7e2b1a0b7caa20697ee8f99d2522960aef1a15 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFA~%e^b@qC=$q|Nq}#ct{B-%~%rT7tG-B>_!@h zljQC0!k53-z#qurEbxddW?zm0Xkxq!^4042^UR%yo?nLJSS9Obx6|jkOJotPBh^o*V_LN79g+ zpOTqYiCaVD&e}ad4ay)J(lT>W^AdAYtxA9lhJwWORJ}@lL$la;FtY;0%)XIS0J6Z- L)z4*}Q$iB}UAB^Z literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/crates/tile]-16.png b/forestry_resources/assets/forestry/textures/items/crates/tile]-16.png new file mode 100755 index 0000000000000000000000000000000000000000..b348a8687fb2045a6d2bb2edd7f641551de42c19 GIT binary patch literal 478 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 WSpi~Z-$*I|S>WmF=d#Wzp$PyYPhv{| literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/forcedCooldown.png b/forestry_resources/assets/forestry/textures/items/errors/forcedCooldown.png new file mode 100755 index 0000000000000000000000000000000000000000..3765df9776622f739d38f31847ee17267959879e GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFe4eK?r+T>hWi zc5sq{%_|n>z2Bd25t!`XvTiDrj$i~v-`;0J&*g#l^q?+fYz#(xJHzuB$lLFB^RXvDF!10LnB=Sb6q2Y5JN*N zQv)kgV{HQ?D+2?KCr5$mku>Dyr(~v8f;1TG8W`#tnTHq|fi#!^H5dXl7&7qG12rgv wY)H$@NzF^lO|>ckG8hUH(^K^-^$pEpfHgL3j*NhW&osm0A5y`mh0XEAdaiOAS;W~Q=61C;4u+ibC{T*5gXLDvCbp!;7mKhBBZE1F*E5n7X&gDppjO6j zWBmNGrXX&I*R{#LuL^SF8PpyMIBCR6AO_T}4PuT6b9a+;1$+kIQ?1{l4F)D@%t`sp zp4A~5GyW2p-wICC$asWu9d1t-cBYGN9j6d04jb9ns7cyyr_ss7>Q{u_$9zw89BC)K zmMAq9!kjp436WFDw=i~E(OC9*WXqPe-XrA@9>{K!Q&x5HZzl}L0XU?Qovi+H-KBz{OWUi*9Z&-&Ju z-M@b8>iYc;AxK!3%%2tuC_&@de-8AVE&f8#*Z+Ar)K_-C?9Jk}?#HX&_vlwwPC+NK zPiDC*DytP0@a}p2kU_gKIBe{Pvd%Q!u~{KEwm3yRT71ktT3m1s+8)~HPA@I5X5ky8 zqwt4Wi_P|6nw*|U{jkRP;+3BAQ}4WYA(@Bg2mFl}Y&;AA3s1?)z literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/isRaining.png b/forestry_resources/assets/forestry/textures/items/errors/isRaining.png new file mode 100755 index 0000000000000000000000000000000000000000..e09e737d19ddfff6d31e487b6381789857c45044 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XI$U)KJpB!!%*X z|NsBpQ@R3y;*3e&?k>!NJU$=`I14-?iy0WWg+Q3`(%rg0KtVlE7sn8e>&XcR*qodt zB_y1kWhEk?)FK#IZ0z|ct7z+BhJAjHtn%GAKh)L7fV$jZP#sR| RkyHS(z|+;wWt~$(695VBUjqOD literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noCircuitBoard.png b/forestry_resources/assets/forestry/textures/items/errors/noCircuitBoard.png new file mode 100755 index 0000000000000000000000000000000000000000..d51a4fad021759f3420dbe8d51bd882364ccaafb GIT binary patch literal 524 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Vh1?TO8<4^L&!?DBN5lmZ zmbgZgq$HN4S|t~y0x1R~14AQS19M#?gAhYQD^mk2Q)6udBP#;~jVDKe>X9_$=BH$) zRf04a>lzs98kvU}8G$sI05uo_H5fAR)B`mrgKS94%t_5l%uTf_0Wug064O)lD)kM` ZV&lQg3J^2zmvv4FO#qxtqWAy+ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noDisposal.png b/forestry_resources/assets/forestry/textures/items/errors/noDisposal.png new file mode 100755 index 0000000000000000000000000000000000000000..2127d992a2e18f0454af503499721b5ce6b74348 GIT binary patch literal 562 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>*JLwBUBF^I@H$I7GfthAx%qLP2NmjRYzTZ>C&ZTWo0_* za`H0b`NvgOHLi_I(0N;%fJ8Px7Z)C7kt{bd9!g~ z)^&$$4HE_l#thB#Nty?CI+w25YoF^dyZCb1UPEz1ryYEEby*DG^%u^1o?7$CzN;m} z&}++raJ6Z7wA@O5Ce?U1&$REfT>5_B@w)wmY)+z+=3NC^uUg_7QIe8al4_M)lnSI6 zj0_BobPddPjSNBz4XsQKtW1ry4UDV|3^bk`1*%8Vkei>9nN|tXV61CksB2^%Vq^r; zU;@-&2-IN6z*7&@pbWAhEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1APYQQ L{an^LB{Ts5F7&Q^ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noDrone.png b/forestry_resources/assets/forestry/textures/items/errors/noDrone.png new file mode 100755 index 0000000000000000000000000000000000000000..70ca46c72ca9e7b0fd6cb9bac128681c1c23d67f GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFrMq>1fP!J3E{-7_*OLLm|x2F)<?!ndeUg1hID+tlZeC-nhlkz{rRzX|p&(GB0QS zi=vnhKpRv`Tq8hExvr5xh@qjCsezTLv9^Jcm4SiAlcPZO zNE&kUQ!>*kK^ly84GeXS%tMTfKpISd8VrFN3>kRpff|%SHl$_dq~;~&rdpK%84Lx9 g>8W~^`i5q)@nB{Jh?#vOsQ_ewr>mdKI;Vst0L5o}j{pDw literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noEnergyNet.png b/forestry_resources/assets/forestry/textures/items/errors/noEnergyNet.png new file mode 100755 index 0000000000000000000000000000000000000000..1ed8eacbb80cc44dceff9f0d68225693c5a451fe GIT binary patch literal 380 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XFV_U%h(u-_zm$ z|NpFegiiqZj3q&S!3+-1Zlr-YN#5=*%z`{VAlo<#JR*x37`TN%nDNrxx<5cceNPw1 z5RU7~2?v-Yn74=-7+9={VpI`p=vW}i)6*E^VCc4vO@T2?gf+#mVTT3-Lo^ddOq~QL z&IjMPxxv5qqKn6oWVtT4x drM{tAY&@7*0b*v~NGbqX;OXk;vd$@?2>=kkV@Ci0 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noFarmland.png b/forestry_resources/assets/forestry/textures/items/errors/noFarmland.png new file mode 100755 index 0000000000000000000000000000000000000000..ee8039fe59c745e5b8172fc34d0c11b0010fb46e GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFQz@c^t^$EbxddW?U}b8oZD3?&V4(5jC{R6;hTQy=%(P0724h_VLtP{D z5F;ay1{0tLL!bsj2A+DL24#>9X_+~xd5O8HRwY0NLqTGCs$QkOp;>G^m{|d0X5UCE P09oMa>gTe~DWM4fVcvb+ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noFertilizer.png b/forestry_resources/assets/forestry/textures/items/errors/noFertilizer.png new file mode 100755 index 0000000000000000000000000000000000000000..e4e9f1b8ba7e39b13f2ace09d9a2a2debe975229 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF|%)>uYnxS0*}aI1_o{+ z5N5n|x9$&6(8troF@)oKa>4;_3DyH5lP7JMJV|Iq;+iE(mM|pE(6V%rIH=~S&^BRG zp@s*qa6se6NlF15Crw&4(_6`9I=2TWbMqo^u9kxe8XZ@i7(yR$s^-V*^#ILPEpd$~ zNl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cps|0B< z)-^EHH8Kw|G6HEZ0ctP=YA|HrsRwFM2HB97nUk8An44-<0%R~0B&Mh8Rq7j>#m0k~ V6(DBzjidsQ1)i>cF6*2UngGN?dx-!5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noFlower.png b/forestry_resources/assets/forestry/textures/items/errors/noFlower.png new file mode 100755 index 0000000000000000000000000000000000000000..c56f41308c89a5a5f80dfde06a215495d6f6568a GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFIW*3KZ1%<%vJe}?C?l!4NWB|(0{3=Yq3q=7g|-tI0OZTF^D0Xdun9+AZi z4BSE>%y{W;-5;Q!qo<2w2*>s0gagbHtO_$415X?{B5))@AjC+N<+S1K7A=R6PF1I= z-BU#yGQVvp+7QKdaFf%9Bsa%xOpc5x%!N!0Yj3bwPhK=DA843riEBhjN@7W>RdP`( zkYX@0Ff`INFxNFQ2r)FYGBvO=HP$vTvNABxcybh|9!W!PeoAIqB}jv@u7RPhk$H%b z5lDjxP=g^*gCPS?Jy3%($cD7coYcI;+*GR)AcLVGF+EkUQs2-lHXh8Z05P*~Bo%-x N@O1TaS?83{1OT{jcS`^O literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noFuel.png b/forestry_resources/assets/forestry/textures/items/errors/noFuel.png new file mode 100755 index 0000000000000000000000000000000000000000..e4e9f1b8ba7e39b13f2ace09d9a2a2debe975229 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF|%)>uYnxS0*}aI1_o{+ z5N5n|x9$&6(8troF@)oKa>4;_3DyH5lP7JMJV|Iq;+iE(mM|pE(6V%rIH=~S&^BRG zp@s*qa6se6NlF15Crw&4(_6`9I=2TWbMqo^u9kxe8XZ@i7(yR$s^-V*^#ILPEpd$~ zNl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cps|0B< z)-^EHH8Kw|G6HEZ0ctP=YA|HrsRwFM2HB97nUk8An44-<0%R~0B&Mh8Rq7j>#m0k~ V6(DBzjidsQ1)i>cF6*2UngGN?dx-!5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noHeat.png b/forestry_resources/assets/forestry/textures/items/errors/noHeat.png new file mode 100755 index 0000000000000000000000000000000000000000..9e284468af6b2eae46f8adf093ea4ffd843f1b9e GIT binary patch literal 454 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFzm0Xkxq!^4042^UR z%yo?nLJSS9Obx6|jkOJotPBh^o*V_LN79g+pOTqY3DRJ!Yhb8rWFBH<1kzvv)L;nI zV93Bz57eLxvLP)qCp9lIH`S^H$Y3Z)Oi$IT)HgJXjR!L;K+NnLNd+JaJYD@<);T3K F0RWF9l2`x$ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noHoney.png b/forestry_resources/assets/forestry/textures/items/errors/noHoney.png new file mode 100755 index 0000000000000000000000000000000000000000..8a3ff84cb335ad251acf6c4e2ed4effb9e7c40bb GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFn)WFKrSlhtJ%D_P5$x)zsBn`RwDVb@NAPvU428Oyu<{?H#APpu!4TeAs zh73IQKn={vX42FWl^i;h{eM7U@crdd9#LT{tQ~@P5LY1m|Ns9NC$wH% z&HC@@FlSPenu=6&U5cy()7x_@FHVRo$x%%QDq<`N@(X5gcy=QV#7XjYcVYa`q)~W&^FZ)*NBpo#FA92FVdQ&MBb@0QDP# A)Bpeg literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noRecipe.png b/forestry_resources/assets/forestry/textures/items/errors/noRecipe.png new file mode 100755 index 0000000000000000000000000000000000000000..40be185dd0f048c87ce87ca2e2d9f3b1f6b4f6be GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFeZ|No(|Wp zT?-5h{Qv*I#Tq_ zsFt`!l%ynKd7c7#V>ym;f~x0yP*i@YDk}D1&TB%gjm5OUzBRDgiPW3KG*(^(yrZ a&0^!h%nA@Q`$kd$$O2DSKbLh*2~7ag4TC2D literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noRecipient.png b/forestry_resources/assets/forestry/textures/items/errors/noRecipient.png new file mode 100755 index 0000000000000000000000000000000000000000..b4611f89c8edb7520279752c97a5074cab285b0d GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFli9O7E0OjXcT9s;Z_2 zha)&OI8$5LoR>~HsN{9Z(Mv&aMj4yBsJOVgXiXRsL&aO3XUA7b06oE=TH+c}l9E`G zYL#4+3Zxi}3=EBQ4a{|o3_=VItxOH9OpUb-jI0a{G@cvEal|aXmTV03VB@$l?W)7-nSWzm0Xkxq!^40 z42^UR%yo?nLJSS9Obx6|jkOJotPBh^o*V_LN79g+pOTqY3DRJ!Yhb8rWFBH<1kzvv z)L;nIV93Bz57eLxvLP)qCp9lIH`S^H$Y3Z)Oi$IT)HgJXjR!L;K+NnLNd+JaJYD@< J);T3K0RXSYm8k## literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noSky.png b/forestry_resources/assets/forestry/textures/items/errors/noSky.png new file mode 100755 index 0000000000000000000000000000000000000000..5b731463f83f7aee2cbe474e291b5797b5fbf6be GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF|EmB0|9Ad2FaydmCV9KNu>Qz@c^t^$EbxddW?Wr(8TwO6oABH!P80P3U5s zxaBZ!OC)2+F%6E5JW5Oqk4o9u`&Tt}0?kw{ag8WRNi0dVN-jzTQVd20hDN#u=DJ1( zA%=!lrUq7~#@Yr(Rt5$dPmTiBBWcLZPsvQH1ZgnVH89jQG7m8_0%KmHH#)Fv^AZGTBqymryp00i_>zopr09vbb A6951J literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noSpace.png b/forestry_resources/assets/forestry/textures/items/errors/noSpace.png new file mode 100755 index 0000000000000000000000000000000000000000..f6a18e992f8a7e47645bbfa1084e731a71ce9c92 GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>0a|&%XSnvdkT2^hX_4>;`+mK%8{b=A7-^qHCEdGT<86niob$=5>9I# zDXTMNF*yp{=+psPq*~${QIe8al4_M)lnSI6j0_BobPddPjSNBz4XsQKtW1ry4UDV| z3^bk`1*%8Vkei>9nN|tXV61CksB2^%Vq^r;U;@-&2-IN6z*7&@pbWAhEi)%IFEKaO nsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1APYQQ{an^LB{Ts5r9F|- literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noSpecimen.png b/forestry_resources/assets/forestry/textures/items/errors/noSpecimen.png new file mode 100755 index 0000000000000000000000000000000000000000..70ca46c72ca9e7b0fd6cb9bac128681c1c23d67f GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFrMq>1fP!J3E{-7_*OLLm|x2F)<?!ndeUg1hID+tlZeC-nhlkz{rRzX|p&(GB0QS zi=vnhKpRv`Tq8hExvr5xh@qjCsezTLv9^Jcm4SiAlcPZO zNE&kUQ!>*kK^ly84GeXS%tMTfKpISd8VrFN3>kRpff|%SHl$_dq~;~&rdpK%84Lx9 g>8W~^`i5q)@nB{Jh?#vOsQ_ewr>mdKI;Vst0L5o}j{pDw literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/noStamps.png b/forestry_resources/assets/forestry/textures/items/errors/noStamps.png new file mode 100755 index 0000000000000000000000000000000000000000..2f373319d52d9bf2c8724bc7b29ae7c7a9ea319e GIT binary patch literal 458 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFur)B-u21s;*b3=G^tAk28_ZrvZCV3MbcV+hCfF9wqT4wd~ljqgkS7p`M;7TY%eg#*kB|B^K>qT{Gk8(j>8n z-5u4>UnwgvxAr(PoJcS;FiSIYuwY_%A|Wgh<=u4?Xq#$@YeY#(Vo9o1a#1RfVlXl= zG}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@NkeXaN@iLmNQ1GifuXLEd5Dn_NP`Jb zgCS6ZAp=i6P=hkahP2F_)V##pRI3sogP|ZXJyow#-_R^J9?Yx&F|%(Z6@V=8boFyt I=akR{0R4rHK>z>% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notAlphaNumeric.png b/forestry_resources/assets/forestry/textures/items/errors/notAlphaNumeric.png new file mode 100755 index 0000000000000000000000000000000000000000..f58b38d7cc105666ab68c4a7116f33d64e29c72a GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFMTvRU^}X$;met)HZHQ&I`2TnzUMR z3dhapD>XYqQziT)C%#$!zQ(nNqjTMje?Nexsg}4#l%ynKd7c7#V>ym;f~x0yP*i z@YDk}D1&TB%gjm5OUzBRDgiPW3KG*(^(yrZ&0^!h%nA@Q`$iHdG#ETx{an^LB{Ts5 Do*8`6 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notDay.png b/forestry_resources/assets/forestry/textures/items/errors/notDay.png new file mode 100755 index 0000000000000000000000000000000000000000..18507c0bbc1b80bd045018c8853671cbb63ff27a GIT binary patch literal 515 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>V8U zYiR3R#HUvUgr)I|s{a4~|4p0HVW7#3N#5=*l5g_1b^tk?1s;*b3=G^tAk28_ZrvZC zV56stV~E7%)c%`%EebrY+R=^O0n-lt{I4&&SZ&tEeA|`^NCE*LVE?Y0t#V9sYs;@+P2TR7+eVN>UO_ zQmvAUQh^kMk%6I+u7SC(kwJ)|p_QqDm8r3|fsvJgfyR@gK=nu(a`RI%(<(t4jCBnR zb&bqJjEq1UOn@2;ff@`MciwG1&QgYdX@TyX0h>LW(A0u SeIuy=WPzuvpUXO@geCw>;+Pu% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notGloomy.png b/forestry_resources/assets/forestry/textures/items/errors/notGloomy.png new file mode 100755 index 0000000000000000000000000000000000000000..ffc158fc565c3b2b77b10229da68d8a4118b0e31 GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFFVdQ&MBb@0IOATzyJUM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notLucid.png b/forestry_resources/assets/forestry/textures/items/errors/notLucid.png new file mode 100755 index 0000000000000000000000000000000000000000..5b731463f83f7aee2cbe474e291b5797b5fbf6be GIT binary patch literal 398 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF|EmB0|9Ad2FaydmCV9KNu>Qz@c^t^$EbxddW?Wr(8TwO6oABH!P80P3U5s zxaBZ!OC)2+F%6E5JW5Oqk4o9u`&Tt}0?kw{ag8WRNi0dVN-jzTQVd20hDN#u=DJ1( zA%=!lrUq7~#@Yr(Rt5$dPmTiBBWcLZPsvQH1ZgnVH89jQG7m8_0%KmHH#)Fv^AZGTBqymryp00i_>zopr09vbb A6951J literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notNight.png b/forestry_resources/assets/forestry/textures/items/errors/notNight.png new file mode 100755 index 0000000000000000000000000000000000000000..bdb4730edacd2255d7015bb42b7ae6b1ddfa1264 GIT binary patch literal 514 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>QK$!8;-MT+O z!3Iwk#}J9jsr{ZpM-(_*JB785F`7R6r{23!{O;9F4Zr%C>=@c7cuBh~o+`rblPg=r z)o5d7-MJxs$rSICosTkEJ;Y~bzup`A?1hSkN}AfPW6=SP-&X1w1^dP|FT4|Hn7qY@ z&0xyDTQzt0vixC9Zp=-I-Zl5HRJMHb?5}Tk{{JptwTQ>KBqgE-=oZxy*NBpo#FA92 zFVdQ&MBb@0HzU>Z2$lO literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notPostpaid.png b/forestry_resources/assets/forestry/textures/items/errors/notPostpaid.png new file mode 100755 index 0000000000000000000000000000000000000000..2f373319d52d9bf2c8724bc7b29ae7c7a9ea319e GIT binary patch literal 458 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFur)B-u21s;*b3=G^tAk28_ZrvZCV3MbcV+hCfF9wqT4wd~ljqgkS7p`M;7TY%eg#*kB|B^K>qT{Gk8(j>8n z-5u4>UnwgvxAr(PoJcS;FiSIYuwY_%A|Wgh<=u4?Xq#$@YeY#(Vo9o1a#1RfVlXl= zG}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@NkeXaN@iLmNQ1GifuXLEd5Dn_NP`Jb zgCS6ZAp=i6P=hkahP2F_)V##pRI3sogP|ZXJyow#-_R^J9?Yx&F|%(Z6@V=8boFyt I=akR{0R4rHK>z>% literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notRaining.png b/forestry_resources/assets/forestry/textures/items/errors/notRaining.png new file mode 100755 index 0000000000000000000000000000000000000000..9a01ac3047cc392130b435a514c11c5265f7b4e4 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFO>_%)r1c1j3A$?$-SQ3c7i^IEHXsPfj?% zEWxTUqcJeR(^KF`f{;j%NC<<`6cJX|)+r544x9^?Ff|=qkisz~h;3D(m`H+%34;+2 zt0d2XTMyYDu`r}5v9e3uI{gr6qH2k2L`h0wNvc(HQ7VvPFfuSS(ls#GH8Kb>G_*1` zurf8)HZZa>Fwl5%6sR6aLvDUbW?CgkgR!oGp{|j6h>;OUg9%WBAy9)M15Z6rgEGj5 vw9K5;yu{p8s}dlCp&&6mRj*Rt&@46{%&Y)0vu`97fGqHI^>bP0l+XkKmC9@4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/notUnique.png b/forestry_resources/assets/forestry/textures/items/errors/notUnique.png new file mode 100755 index 0000000000000000000000000000000000000000..c23ecaf8926f7f5bdcd8976b8e11dc91f53b490c GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFud*ZefD~hrx4R2lV%m;cAcwQSBeIx*fm;ZK z886+f`vVm8^mK6y;kcfh(7@>C$l+ixqc>J&Vb28t4P})pM^Ccqh`y2%dc~2_aX@07 zqLM=@Pmj{Vz67>_jolh9S|ZDi9d$i&(N&;3)_{%SPQFm|^)v1un^a3&BT7;dOH!?p zi&B9UgOP!uk*!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8U)v6XFV_|9d+8|NnpG zJ2q(`hp{BcFPOpM*^M+1C&}C0g(;1@CIzItz$3Dlfq`2Hgc&d0t@{HMRQ7an4B@z* zoN$0oreTI5gU5!Zh(!tu1y%^G)(+?}6j5v8Vn`HYI_fUAy8)!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8U)v6XFV_|9d+8|NnpG zJ2q(`hp{BcFPOpM*^M+1C&}C0g(;1@CIzItz$3Dlfq`2Hgc&d0t@{HMRPl6i4B@z* zoN$0G!nvU(Lt}z~AnQj*9k&S*$qYW6Gg==U0=iX%scUa?%p{iMgp(B|rv4L1KEUUZuXFS!_I*Spi~Z-$*I| OS>WmF=d#Wzp$PyBpJ4U? literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/errors/wrongStacksize.png b/forestry_resources/assets/forestry/textures/items/errors/wrongStacksize.png new file mode 100755 index 0000000000000000000000000000000000000000..c23ecaf8926f7f5bdcd8976b8e11dc91f53b490c GIT binary patch literal 417 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/fertilizerCompound.png b/forestry_resources/assets/forestry/textures/items/fertilizerCompound.png new file mode 100755 index 0000000000000000000000000000000000000000..77f34968aa75a166501aac23ec42422419e7dfee GIT binary patch literal 3025 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 M07*qoM6N<$f;~fjfB*mh literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/frameImpregnated.png b/forestry_resources/assets/forestry/textures/items/frameImpregnated.png new file mode 100755 index 0000000000000000000000000000000000000000..7e888ad5142c51ed2417790188eaa6f4c5cb087d GIT binary patch literal 3079 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/fruits/cherry.png b/forestry_resources/assets/forestry/textures/items/fruits/cherry.png new file mode 100755 index 0000000000000000000000000000000000000000..e95909732722afd44c164e411b08698c92e56df3 GIT binary patch literal 3146 zcmV-Q47Kx#P);QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-Az9>Nv%ZWK*kqtikEV84R z*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?%E8;ie*i;TP0{|3BY!`4? zi6S-;F^L}%f`(o2L0Dz>ZZyndax(`h}FNp#{x{a}MR#uh~ zm%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJr)Q)ySsc3IpNIG#2mW;) z20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ7KzgM5l~}{fYfy=Kz{89 zC<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c#B`Ac>67n+__r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQHqKX(I48#TTN1~8;gpaI8 zijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2wRf4KU9Y%GadQmq~W2jlw zM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=gjj_UbVj?j~n6;P^%sxyT z<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynEso>0T?zku%50{Utz#YMz z!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~fge1ZyLM5SA?cA^NYNxAX$R>L=^W`U=_Q#=)*?HSqsRjC4stX3 z0{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe3CZh{Gg5ddEh!f%rqp_= z8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{7i7jM2t}RZLSa!hQyM83 zDHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T7cGTWN;^&)roCIDw8Uu% zXUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo40i~d)5U7x)uwUV#!pu_Y zQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21QMwzDUsGOu+u6#y$T7{xw zufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~TE1GF+Cz1MIzv5Pys-#cBCZ~;MXm#GGH#)6)ozd6)!Y-@ zTijj2>R4 zy()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x(W?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)BP)E2$IF@OjS(EuDD=h0o zwsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2x4vhC`i6oH6B|7?9^ORQ zl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@>)Hd$6f$iqotG0hEVi#R4 zHYu(seqX{Wx%!RiH@;dd*9H0$NjB!N_E9` z?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k9U46xbhx+Ks=4`y;*ru8 zxJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8NoCm1JMf6)A)ww=;m)B$zm zbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834Bs>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)zk?4`pJM24CcT?`ZxR-fv z;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F|_DjYu?mT-%DP~zdZD6*{hzp zfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z!Kc(upZ)~{nDhK<*act! z000JJOGiWi{{a60|De66lK=n!32;bRa{vGis{jBFs{xMe#QXpN00(qQO+^RY1p*8@ z2E|Qaf&c&kq)9|UR5;6}kv<VHAd+&uDCjdeb)CDrq3LDmPGT>(JE69|Wnii;JU6 zk%DL!7eUZfvSnzoIBMu56o+m?Gl)wE{|JgAF}aXS5`&4_)I>f9trB9i(K8*s_dDl( zcn{oCTcLowNiVxeTse-&#hF>|Rj+->I}f|3&WGQAtu1|t=D%{*yu~SsW*{P0eJEU_ zyLl+z(fYZ>96ZxX!9eBke=d3VY+76l+Ae9z0Z!vO zF<^V)C-dwhE8s8B8D~dU0_(vI9Kj3^&E+_N$~q~yfr9#)e=IvHjy z8llraDe?$ue1P3ESp0;OPc=EFY6a)| kR_~E>)@Sm2*Fb@G2I;QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-Az9>Nv%ZWK*kqtikEV84R z*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?%E8;ie*i;TP0{|3BY!`4? zi6S-;F^L}%f`(o2L0Dz>ZZyndax(`h}FNp#{x{a}MR#uh~ zm%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJr)Q)ySsc3IpNIG#2mW;) z20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ7KzgM5l~}{fYfy=Kz{89 zC<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c#B`Ac>67n+__r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQHqKX(I48#TTN1~8;gpaI8 zijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2wRf4KU9Y%GadQmq~W2jlw zM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=gjj_UbVj?j~n6;P^%sxyT z<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynEso>0T?zku%50{Utz#YMz z!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~fge1ZyLM5SA?cA^NYNxAX$R>L=^W`U=_Q#=)*?HSqsRjC4stX3 z0{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe3CZh{Gg5ddEh!f%rqp_= z8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{7i7jM2t}RZLSa!hQyM83 zDHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T7cGTWN;^&)roCIDw8Uu% zXUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo40i~d)5U7x)uwUV#!pu_Y zQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21QMwzDUsGOu+u6#y$T7{xw zufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~TE1GF+Cz1MIzv5Pys-#cBCZ~;MXm#GGH#)6)ozd6)!Y-@ zTijj2>R4 zy()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x(W?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)BP)E2$IF@OjS(EuDD=h0o zwsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2x4vhC`i6oH6B|7?9^ORQ zl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@>)Hd$6f$iqotG0hEVi#R4 zHYu(seqX{Wx%!RiH@;dd*9H0$NjB!N_E9` z?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k9U46xbhx+Ks=4`y;*ru8 zxJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8NoCm1JMf6)A)ww=;m)B$zm zbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834Bs>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)zk?4`pJM24CcT?`ZxR-fv z;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F|_DjYu?mT-%DP~zdZD6*{hzp zfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z!Kc(upZ)~{nDhK<*act! z000JJOGiWi{{a60|De66lK=n!32;bRa{vGis{jBFs{xMe#QXpN00(qQO+^RY1p*BK z32~XpT>t<9!AV3xR5;7klHW^HaTvxw=f|cy?rcq)NmQ_5LAHxX@Gc{Wpa=xPg6K8^ zQS7Rl{s(XR3l`N)kkK!^%fN^zvQW^a;lz_}Zfi%6XXl*F?b}sjk_+#o_v(Fl-{*Os zm-m7HKBQ)iWZ!8a`vM5c1S4SvU%i+1MesHGLj3wZPpIt2oPJ76X9UmZ=VvZWV*CMi zYKH!sqjj9z2)-X{6-K^<8t+9t)HI;o N002ovPDHLkV1kaX5A6T| literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/fruits/dates.png b/forestry_resources/assets/forestry/textures/items/fruits/dates.png new file mode 100755 index 0000000000000000000000000000000000000000..8a53c59baf624867a72a4ca417a1e24aadc0554f GIT binary patch literal 694 zcmV;n0!jUeP)WFU8GbZ8()Nlj2>E@cM*00J6GL_t(I%e9kDOH^SP zhOhU$=RM~=A9H5Z@v|bZT?j=%P)KdtwQ1AOYty=4U}UC&BJ>kXLrF*HIOEKmulH#o zi4cVl-Rt|hxZ&Y}e~h|G>GkSkaSoiTdH?0By0PHZvqw^l#>`|1Ht7&}9zRZx3AN_k z#*X@<;KjoS!lXy2d;*&hXoVoeNgH1#%yehz_0M^`wxNC#Jh^vQGNTxc9Feb?Ub@A} z;XYAk9z+O4NK?yFH|E>XA^JMJy1Xcztc~$vn*5A7PAG;Kh%zLt45=H^#1MN!T#=KH zOZ;E(%asL5<2lO8qdY&R)oCLr!ZgEbO&C~A-6!;727?K8T{1DzrQpreWeH6O7fw^| z??Ev}#3P!WLx&cneVXwRiPiM-g7MJdr_%(9y%d~X6tq&y#qj|~Af1^9Kg5^_rG%=# z$DR3zqrO8X4PlgU>KZmbZ7Lr?=>&0ts|su@!^SO&sv__ez6`m&*ybcJ$pJi&^~#F&LKkHWCQcxZkTk=e>e841)y|Nq zHXpCSR|^2N4LR%QC}S8k4dwX&L4oHnv=J%@`S5u|{q>oi-(L~sYXS|;WB@?~amL!# cmg0ZqC+P9umlK?F1ONa407*qoM6N<$f~sCGsQ>@~ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/fruits/lemon.png b/forestry_resources/assets/forestry/textures/items/fruits/lemon.png new file mode 100755 index 0000000000000000000000000000000000000000..63d106ef2ea11e2506832ff0e4b0d16b63dd5ad9 GIT binary patch literal 453 zcmV;$0XqJPP)F?#O|+f+dLQ+x<_F#Aa?XYId`KlHxQ1<93B?rb_+`nm28> z(?E^t=nb88F3YTzq^7peYZeN*49i}Dq&KL3)G!UhjKkXF1}f6a6KH2GY0eK$uK9uFp@S)17g5`_DsK?EE+Mr_D2jn(;%9ao={biW|2tjk_ust@ vS$I4$*_4jm1v^Lmy?wR2ggD$rFxdJAS*U*t;#1+J00000NkvXXu0mjf!j-=5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/fruits/papaya.png b/forestry_resources/assets/forestry/textures/items/fruits/papaya.png new file mode 100755 index 0000000000000000000000000000000000000000..50edde07b2d7fc3a1df2c5ffc42e1e4b1be237d6 GIT binary patch literal 603 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/gearBronze.png b/forestry_resources/assets/forestry/textures/items/gearBronze.png new file mode 100755 index 0000000000000000000000000000000000000000..adb151fbec2847cd99369c4a5000c6386b9ae165 GIT binary patch literal 3084 zcmV+n4D<7eP)QQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000XP)t-s0002p!gk%lc7kXhyp}D`r#O#tBHhAv>e#11GY|j&|8pIs z7ytkO19VbOQve79tEL}p00001VoOIv3TV*uRsaA132;bRa{vGis{jBFs{xMe#QXpN z0CY)2K~xCWV_-l6CeC1r#lba7PuuA#veB_YNPAR+g5kdY=Xp&=e1#QQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000XP)t-s0002vw~phtj*eF&uxl&Jd@`F~CgZn`@Y=;jD-r+y|L6~4 z9{>OV19VbOQve79tEL}p00001VoOIv3TV*uRsaA132;bRa{vGis{jBFs{xMe#QXpN z0CY)2K~xCWV_-l6CeC1r#lba7PuuA#veB_YNPAR+g5kdY=Xp&=e1#QQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000XP)t-s0002Z7PuuA#veB_YNPAR+g5kdY=Xp&=e1#QQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000gP)t-sYd?S1fB#cL6iGG}C>{$_LKNM?cIw!t`scDqHWg@29*Jis zC>{&{|Nmk59~}Sy00neXPE!B?0002OYX-3Z0004EOGiWv_OxO300009a7bBm000iF z000iF0gmj%`~Uy|QAtEWR0!8&V1NNeK?r~_ghHVV)$~9xLny2Q!ca|bRRl9ED}umk zBv&6*1T$vsasq3YT)hTj&a7Pr!3>B1kZ}qu0A$Qw1GP)?Ad;m(002aq6}RWj;QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-Az9>Nv%ZWK*kqtikEV84R z*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?%E8;ie*i;TP0{|3BY!`4? zi6S-;F^L}%f`(o2L0Dz>ZZyndax(`h}FNp#{x{a}MR#uh~ zm%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJr)Q)ySsc3IpNIG#2mW;) z20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ7KzgM5l~}{fYfy=Kz{89 zC<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c#B`Ac>67n+__r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQHqKX(I48#TTN1~8;gpaI8 zijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2wRf4KU9Y%GadQmq~W2jlw zM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=gjj_UbVj?j~n6;P^%sxyT z<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynEso>0T?zku%50{Utz#YMz z!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~fge1ZyLM5SA?cA^NYNxAX$R>L=^W`U=_Q#=)*?HSqsRjC4stX3 z0{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe3CZh{Gg5ddEh!f%rqp_= z8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{7i7jM2t}RZLSa!hQyM83 zDHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T7cGTWN;^&)roCIDw8Uu% zXUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo40i~d)5U7x)uwUV#!pu_Y zQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21QMwzDUsGOu+u6#y$T7{xw zufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~TE1GF+Cz1MIzv5Pys-#cBCZ~;MXm#GGH#)6)ozd6)!Y-@ zTijj2>R4 zy()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x(W?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)BP)E2$IF@OjS(EuDD=h0o zwsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2x4vhC`i6oH6B|7?9^ORQ zl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@>)Hd$6f$iqotG0hEVi#R4 zHYu(seqX{Wx%!RiH@;dd*9H0$NjB!N_E9` z?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k9U46xbhx+Ks=4`y;*ru8 zxJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8NoCm1JMf6)A)ww=;m)B$zm zbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834Bs>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)zk?4`pJM24CcT?`ZxR-fv z;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F|_DjYu?mT-%DP~zdZD6*{hzp zfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z!Kc(upZ)~{nDhK<*act! z000JJOGiWi{{a60|De66lK=n!32;bRa{vGis{jBFs{xMe#QXpN00(qQO+^RY1P2Kv zCrArrD*ylhib+I4R5;6HU>I`1#l_{ni;K&DvNaz(c<}#?8#hQd1X=U{|NludfFjKd z3=9mOW}-MXGZNA$FTu&6D9On%fBO>#88u6WJ$v>r5@i6g=KIgTGtAiZ2&-BqVl*GP z@D`^l8Hv$+14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>z2ecWCD+f*xp86c!y8L)Us`ze%&beN zr`)}^=9n-MhN%&ZVUft}VZNdC|2qbI%{0asK$U zbH^v&x-#p=#W`2c&3b%m@!jilpFLRh?7`|657ytlviRP$#Wyd^JAY#Ox#Kg=9i4pP zo3tDcLTj#1Nv*tu1Z6$-tVM zU45047@wXAV_04ZV~3>8o|->QO-_fD79~9rniO=2$7oa0C$289Q(CLCUP;Z0y2WF~ zwX5nETbtW4wPk6~#HNMuTr=BN_KmO4@0{McymxYo<}t*UaSLR>)F}kIK()j*q9i4; zB-JXpC>2OC7#SEE=^B{p8X1Hb8d{keSeY7Y8yHy`7-&2>3RI7zAvZrIGp!Q0hRB_@ zdw?30K{lji=A`B&=B8Se02vGgiRr0&mHLKevGHJL1&En_BdGvnfv2mV%Q~loCIIcz B8hro& literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/habitats/end.png b/forestry_resources/assets/forestry/textures/items/habitats/end.png new file mode 100755 index 0000000000000000000000000000000000000000..db90385369e65f1c31ad6a516134b3b78d09248e GIT binary patch literal 473 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>5KU?KkZXk1<=jv_yN~hj^(~y%MmK>z(qf*6~lgpf{ zBC@;yXt-*LYeY#(Vo9o1a#1RfVlXl=G}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@ zNkeXaN@iLmZViz;Yxe*(D1&TB%gjm5OUzBRDgiPW3KG*(^(yrZ&0^!h%nA@Q`$iJT OK@6U*elF{r5}E+nKCZa{ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/habitats/forest.png b/forestry_resources/assets/forestry/textures/items/habitats/forest.png new file mode 100755 index 0000000000000000000000000000000000000000..038704e8be2cdc5d7cb91aeb2a07baab1ddc0707 GIT binary patch literal 567 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>?rBpp=7FL z8D$w@CMC?ltdk?5=c%VB%N0N0bk6CV(yiV(Yn-}vMm25-Y~BEY9L6Bd}|O>_%)r1c1j3A$?$-SQ z3buN>IEF}EEa>1dAsqfai-&S1r{uj1cDpVh3* z?|ixJB)cWwNvVGo+x1g)3*Vp7S+ulDEOG7X>B`xqUqjZ_X}>d`!L#qj3Q7NEGtS;k z+8Jd&TlejQ@9Z*#R`Kh0+;z-oWM^nsXA;n8`{Bg1(p_5VkaSE1yXtzsdwf6#sg}4# zl%yn14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>m5ys}&W$-FDaq%0#-Z0DVu>2lKUehrg!0po^8Tuf7rg(($o+i0oa zp?b5uGMIx$LhiN1J)fhyR@uvDr5*NJ6w$v*aW~`AV{8xJoZZ+2bd73>YeY#(Vo9o1 za#1RfVlXl=G}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@NkeXaN@iLmZViz;Yxe*( yD1&TB%gjm5OUzBRDgiPW3KG*(^(yrZ&0^!h%nA@Q`$kd$$O2DSKbLh*2~7aY(y=K3 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/habitats/jungle.png b/forestry_resources/assets/forestry/textures/items/habitats/jungle.png new file mode 100755 index 0000000000000000000000000000000000000000..03f0eaab2e55ec075e14d6fd2ffde894a60891ce GIT binary patch literal 607 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a><5r3OsBN0)iGkSn(_SZguFv@AWp!Ywxty zNXoc)iO%Y{A|Er&_2dy-6U~(=dWU-)Z<%h(=29t6)LPl&=~0_hHrF_1? zrq7)i7rl7$|A1MseR50ol-jxSe=4)^x)_`6Ke@_kcJjuYu-9j|-Fy48;ql8J?seOL zGoKgd(EY%6;XyM4OP6AuV6#MS2Z#N>OI*t`_lEKSovB*l8c~vxSdwa$T$Bo=7>o=I zjdTsnb&U){3=OSJ4XjL!wGE7{3=A}$90jUJ(vX{14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>l{+gt*#z_5Q!=_5c6P zlI|T7b3^}WX+07WDhhM{|Ns9HS+!Z>G8xf9o(@*$&Yhb!ZCZ_kQ@E~fPD){Ma(Yj3 zc}7CEhlz5egHC)@w3Vhzeo~6ItZ;5(ZdO8ec5;4xMp<%fTtZ}gR#I+$azSON)wCS1 zovksEwwgIPInOzDT!C(2O!9Vj;b^-zwF=1LEbxddW?sgJJO2M~XF8{PS^Cn2$#D()b&8%{Fi|!*_UuD&WL?m{ zImHLHJTy=56LNYP6rX?UiPG|`yPPz)IBoTM{g!2dc`W}vh7GsN4H{3bZ<2i2a7|YC z;mOB8i@vg?!%YLR$kd{iLFYrQ~l1+&T;&U{XvA5K8G zsg}4#l%yn14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>VkRMEC@C3cV4y20xgd&L zpP5;Zot>MN)m~9igo8t0T3U{U#a&a=MoCFoSeS=}Iwj?jFnvjqT zA77Gzfh#+^o|IIdx01W2{I|P?k7fvaXlV(su=r?bc&e)_2?&ImYumH4t1~m3%gX-z zKkelfF+*nNR!vPuRaGx-B~DgWQBF=i78WBJnHU2DBPl5v78U~;88H?X1r`<$4i0|< z)dT|rOIcY7E-qG9)-Epx&{YI5?(8M09v~=!=N_|NlSynwJAG<`|Q_-Cf#x?penI zIh+L^k;M!Q+(IDCc#Ib}AnVkYRXm|MAOSf^sHLZ4!9lA_!FI-&dzBtyayx;oT?d1;jCUytdSBm-ZbRM3V!X=5$1)2SPw8b`rrF8d+3TO7bXje=!n_a_xjAmeo160U>^3sUG3}Cb>h?aZ-L>JA z#DuM-Q-2FCvzUEPVRmG|p6D8D-$I7d*1M0aJ~%IN#?Co2_202OC7#SEE=^B{p8X1Hb8d{keSeY7Y8yHy`7-&2>3RI7zAvZrI zGp!Q0hRB_@dw?30K{lji=A`B&=B8Se02vGgiRr0&mHLKevGHJL1&En_BdGvnfv2mV J%Q~loCIIb2C-49O literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/habitats/ocean.png b/forestry_resources/assets/forestry/textures/items/habitats/ocean.png new file mode 100755 index 0000000000000000000000000000000000000000..feca8692f0c3b2dd76407debed76d8fb67b6ebaa GIT binary patch literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFT_2ycu1XC4Ibf1lU}fSUs3oWfHUw@}!9BB{+(! zii?X*P!O=z+-b4$z>*k-cSZu@FJAru8qc6w;u=wsl30>zm0Xkxq!^4042^UR%yo?n zLJSS9Obx6|jkOJotPBh^o*V_LN79g+pOTqYiCaVD&e}ad4ay)J(lT>W^AdAYtxA9l jhJwWORJ}@lL$la;FtY;0%)XIS0J6Z-)z4*}Q$iB};Z}2K literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/habitats/plains.png b/forestry_resources/assets/forestry/textures/items/habitats/plains.png new file mode 100755 index 0000000000000000000000000000000000000000..9fd1a584204d61f73c8bae6484850fc68ac50e2e GIT binary patch literal 529 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>;M0o zCEYvf_lL&MH=T1jCuNCM=~nNYHBMbSqZ&5^Hg5`!wAIX5VVAVXV)CKn3HuX@H+v>7 zG*4e{o4wkxcTa5QO8bHhZY5j1CLK(gek?tFx^BV(vz(lq!j0~^Yn>}Yt)}I8?QD(t z|NsB3lOH;ORx>7fySu1tVf#4~$l)yTh%9Dc;1&X5#!GkW{s0B@JY5_^BrcbB-{xy_ z;9=!H-K4O15mQrF+28;5CCtAM?Qlky@G5%7^dlSY5CpdUtX6U(Eg9{ zxCX2KQJKX>K$}%dTq8hExvr5xh@qjCsezTLv9^Jcm4SiA zlcPZONE&kUQ!>*kachX&S-S_QK^bI2T4qjaUSe*lRSA&6P>`6Os#mFRXcij}W>$ch T**B63Ko)qq`njxgN@xNA;!(Vq literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/habitats/snow.png b/forestry_resources/assets/forestry/textures/items/habitats/snow.png new file mode 100755 index 0000000000000000000000000000000000000000..0feccbf40bd8d513a30c2a6eda9f2eaf4cfa54d0 GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF-f%Jjaz#9b* z4jede=zze1Lk|uxB`sOn*1n^4*HVL)_8slZ+orS{hfG;MeR;e8`jm*ByRyRdP`(kYX@0Ff`INFxNFQ2r)FYGBvO=HP$vTvNABx zcybh|9!W!PeoAIqC2kFoJ8Sm14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>m1!wtBLG4!VJky2h%akA#FK=7we@WX}?p@pQ22 zDK7UgQI2%biI0l5(v-Tx!Bh`-ncbfs#EYeY#(Vo9o1a#1RfVlXl=G}1LN*EKQ-F*LL?HLx-@ z);2J*GBD71aulc@NkeXaN@iLmZViz;Yxe*(D1&TB%gjm5OUzBRDgiPW3KG*(^(yrZ a&0^!h%nA@Q`$kd$$O2DSKbLh*2~7Z0FvQRR literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/habitats/taiga.png b/forestry_resources/assets/forestry/textures/items/habitats/taiga.png new file mode 100755 index 0000000000000000000000000000000000000000..12d771524857323a6b9972602b9fe5a8f60e79c7 GIT binary patch literal 476 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>;3=*OFdm2LnJPjo@L}atiZtX$jMJ@0Rp2)hi8;Vr)B8*igXGcc+b!XIApO8Om8Q$w@T~8h=>)SIc#a z0v(`Q;u=wsl30>zm0Xkxq!^4042^UR%yo?nLJSS9Obx6|jkOJotPBh^o*V_LN79g+ zpOTqYiCaVD&e}ad4ay)J(lT>W^AdAYtxA9lhJwWORJ}@lL$la;FtY;0%)XIS0J6Z- L)z4*}Q$iB}bab4G literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/hardenedMachine.png b/forestry_resources/assets/forestry/textures/items/hardenedMachine.png new file mode 100755 index 0000000000000000000000000000000000000000..715cfa2ecd2d8a60ad9560c0976925c4dd92384b GIT binary patch literal 3055 zcmVQQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000OP)t-s0000fPgsV!$H?F1sLt0xeT;6byZ`_HJLkyi)@Pq4xgs0UwqRJuF{GEC2uiC3Hnt zbYx+4WjbSWWnpw>05UK!GA%GSEiy1vF)=zdFgi6eD=;!TFfb_O#Q*>R03~!qSaf7z zbY(hiZ)9m^c>ppnF*7YNF)cDTR5CI;H846fGb=DLIxsLX01STs001L&MObuZX>4U~ xVQpnPbZKm50B~VvWiELyF*aRaaA9XijdcJ3 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/honeyDrop.0.png b/forestry_resources/assets/forestry/textures/items/honeyDrop.0.png new file mode 100755 index 0000000000000000000000000000000000000000..52ba983ee37bdb33f922c625da3e357ff69d6d9d GIT binary patch literal 3005 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 ZE_g37HeGAjVsHQe002ovPDHLkV1ia2f*Ak+ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/honeydew.png b/forestry_resources/assets/forestry/textures/items/honeydew.png new file mode 100755 index 0000000000000000000000000000000000000000..ea87e950c8b80f62d35e6516fa7d68bc157dc524 GIT binary patch literal 2991 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 lWiELyF*aRaaA9XgYRdos literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/honeyedSlice.png b/forestry_resources/assets/forestry/textures/items/honeyedSlice.png new file mode 100755 index 0000000000000000000000000000000000000000..c2e9f6bcf37f1c7266cc3486e1ffb641bdefae48 GIT binary patch literal 3107 zcmV+;4BYdHP)QQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000mP)t-sYd?S1fB$AxRkE_2jEsB#|LZdKQ0%q*Ik>(C$%-%V(EzKBca_`I=K05UK!GA%GSEiy1vF)=zdFgi6eD=;!TFfb_O#Q*>R03~!qSaf7z zbY(hiZ)9m^c>ppnF*7YNF)cDTR5CI;H846fGb=DLIxsLX01STs001L&MObuZX>4U~ xVQpnPbZKm50B~VvWiELyF*aRaaA9XQQXW*8-A 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/liquids/bucket.contents.png b/forestry_resources/assets/forestry/textures/items/liquids/bucket.contents.png new file mode 100755 index 0000000000000000000000000000000000000000..e73b04662c99247aff6cc68bf908eb08cffe5089 GIT binary patch literal 2827 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 HB{Ts5wzzoP literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/liquids/capsule.contents.png b/forestry_resources/assets/forestry/textures/items/liquids/capsule.contents.png new file mode 100755 index 0000000000000000000000000000000000000000..63df1e035f3b53a29a549a060710aa66bd0d0797 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)0$go(%hUxL&#f6yYrJ zh%9Dc;1&X5#!GkW{s0BpOFVsD+3zw7@ai*4@Ck1N3dMN3IEGl9emdzO?*Ri2X3ygZ z>dR7jpB+fvu|A|yWmS;e+7SDRIdd5&`fD3Y3hJ;<(R|0zr{y@C*Hh?#gbKrvGq=PV ySH-o>tkj(JMzo5z{P{J$WB>a7e@?cqh*zJm-o3Ve!jm|lJq(_%elF{r5}E++DM14O literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/liquids/glass.bottle.png b/forestry_resources/assets/forestry/textures/items/liquids/glass.bottle.png new file mode 100755 index 0000000000000000000000000000000000000000..20d042faa20407fadfed6743f65f9196dde48d7d GIT binary patch literal 466 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>|LgT;Y$&4#Am_suq5`nI*cuY1NNeaX*>)AW)1kVcH{;##^>Omp^m~{IK(y@`sHRxwC?p^=v-u%>Y`WTH+c}l9E`G zYL#4+3Zxi}3=EBQ4a{|o3_=VItxOH9OpUb-jI0a{G@cvuuhP2F_)V##pRI3sogP|ZXJyow#-_R^J9?Yx&F|%(Z6@V=8 MboFyt=akR{0ExYr1ONa4 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/liquids/glass.contents.png b/forestry_resources/assets/forestry/textures/items/liquids/glass.contents.png new file mode 100755 index 0000000000000000000000000000000000000000..172ddec506600f81f51b4edc589fc3163d041107 GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFhExvr5xh@qjC zsezTLv9^Jcm4SiAlcPZONE&kUQ!>*kp&Bf74NXG~jjTX=EFc;#8~bJeH7J8@NXyJg r%}dNpwJHHJ7zz^8Q}rtK4b5WX!ORK}Gy6tT0muSRS3j3^P6m(SpcbZ*AirP+hO)_LEr2}6 zByV>Yp2p3A$v_Tgfk$L90|U1Z2s2)~TlWVjXyNJN7{YNqIiZ2k&5^?)kz=NV$#7sBnX89%}_0IjVMV; zEJ?LWE=mPb3`PcqM!E*(x<&>ehK5$A23DrV+6G2e1_l~Wjsn#qX~@k_$xN$+YOv5X zGz~E{vI6O`fM~dE?3)49pbWAhEi)%IFEKaOsszYjC`e3C)vMGuG>eS~Gb=#M>>Ei1 PAPYQQ{an^LB{Ts5f~I|o literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/liquids/jar.contents.png b/forestry_resources/assets/forestry/textures/items/liquids/jar.contents.png new file mode 100755 index 0000000000000000000000000000000000000000..b78668d21a88abab323e97d0c3d8859aa45708ff GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv3GfMVy^`y>C)9AIyXu+sOP@S> zaxlhnm8;@(bFp*h&Upsk*tKid|NsAWRc37ks%I<-@(X5gcy=QV#7XjYcVXyYmGuB} zI14-?iy0WWg+Q3`(%rg0Ktc8rPhVH|yUYT-hUUy)cYXj0DSEm%hHzX@PEZif`53{F qnA2cvbwM&(DuIVxqB)r{E|_sm7Wc}AHjX<$#SEUVelF{r5}E)beLngC literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/liquids/refractory.bottle.png b/forestry_resources/assets/forestry/textures/items/liquids/refractory.bottle.png new file mode 100755 index 0000000000000000000000000000000000000000..45cdf9bb699eda1f2430e95211e57f61820460e6 GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFU}b8oZD3?&V4(5jC{R6;hTQy=%(P0V1`Az7(-1==E07)w zh=$9?z8OFb${-ukGILV%5_40nN`MT8g2ePxy-IyUv)FhrvjW7-zL8V_vcS{T&t;uc GLK6TA;dAZ) literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/liquids/refractory.contents.png b/forestry_resources/assets/forestry/textures/items/liquids/refractory.contents.png new file mode 100755 index 0000000000000000000000000000000000000000..2a2bffd48817ad722b7af2e865292d8d175ea863 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)0$go(%hUxL&#f6yYrJ zh%9Dc;1&X5#!GkW{s0BpOFVsD+3zw7@appl?uefY6pHb5aSX9I{dCen-U9|4%$~;+ z)R(35K0A=SV|_@a%Bmo_wITKsbLKKm^w&0)6x3mzqWO-aPs?#Oucy!f2^EGTXKsl# zu8M1$S*bbcjc65b`SWXh$Nu&E|D0@J5wAXBy?br{geP%8dl)=j{an^LB{Ts5S3N=H literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/mail/carrier.player.png b/forestry_resources/assets/forestry/textures/items/mail/carrier.player.png new file mode 100755 index 0000000000000000000000000000000000000000..0b2c5f1a46d02ae50771b191b2153aff4ef03f3f GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%Y)RhkE)4%caKYZ?lYt_f1s;*b z3=Dh+L6~vJ#O${~LG}_)Usv|KY^+=i!oi1AP6LHxGeaUuobz*YQ}arITm}Z`qSVBa z)D(sC%#sWRcTeAd6une-p!hmZ7sn8fIgTe~DWM4fK)-78 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/mail/letter.0.emptied.png b/forestry_resources/assets/forestry/textures/items/mail/letter.0.emptied.png new file mode 100755 index 0000000000000000000000000000000000000000..90c99308b5ba416eb99de387bbce94cd028c053b GIT binary patch literal 3108 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 tbZKm50B~VvWiELyF*aRaaA9XQQXW*8-A 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 lWiELyF*aRaaA9Xgfjs~K literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/mail/letter.1.emptied.png b/forestry_resources/assets/forestry/textures/items/mail/letter.1.emptied.png new file mode 100755 index 0000000000000000000000000000000000000000..a1526f9dfb373d9b60adf5e8cda2575bf6173143 GIT binary patch literal 3021 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 Bg3|y1 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/misc/access.private.png b/forestry_resources/assets/forestry/textures/items/misc/access.private.png new file mode 100755 index 0000000000000000000000000000000000000000..8d269150d6fb36278a7cc0ac3e8e809260aec2d0 GIT binary patch literal 565 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>9#Zk$QiotcHqgeY{d-gzBL~huYfOLhQsQq-klZ$(!k`>Zr>v zUAnZatV~B;PF_a5Jjx)^Q+?vZiLRznXBZe_JX_?qpTD;GIWp0$K2;0B^_8u2?C$6~e z|NTkPOVyLp#fty3D6ph3F{H4pF!6q9#FQNN`mEXcTm~nx-J5QCS9Wkd?_2)r&77s? zJ7Qi(U%vC2U9dIiN(Yzvf2NsvGc~?tzIeeSUoGA6eV_ad{`39Um)BU`cKUy;chy^t zD9?`~kAconEpd$~Nl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_ z)gx)h%}>cptHiA#a%b%xpawyZ4QZJ14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>qW z@=KR4Eh{V2QJ0gK5igH2Nc2>nIB}w@snmi0nyxnblaiJD64i?RO>_%)r1c1j3A$?$-SQ3U+w9IEF}EPVK)b)MUWpDi}2D+O7c6wNj2TTL1pDOXXOf zsQ6TJ{?192$ZyAUxVrzeD>!gyuri!b3CMJNXv3K-cKYhBRXHL~dE0hZ=|5F8ont-k z)#l=9O*>59Zhf8ic5cU`per3*?SDj<)@=x!)4k(yW`)IVjXmGj&ny0a?)c^QIzfN_ z3qS5m;s5@hIjMPxxv5qqKn8zopr02UOy761SM literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/misc/access.viewable.png b/forestry_resources/assets/forestry/textures/items/misc/access.viewable.png new file mode 100755 index 0000000000000000000000000000000000000000..0d145c36de9eb8ed8cf8539fd9a167564b424371 GIT binary patch literal 559 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>=VmR4ewEOLP<~50Gh!R$HDYKQ%{B zOI21!RaQ$?PEl6;KM>S3&jq@KsU*k`=$o?1XDxs{#w2fd7tK@KTUCG@&H|6fVg?3o zArNM~bhqvgP_WU{#W6(Ua%uldp(X>K7Q>~PE7_Na^)kt^-uutVIpy4g6|>`ipY@y6 zyGTFR?yGQvfB-kc1jYrIbXq+bj^&j9cAk~SEnuX7>XpV*O_epa@vByEm8>k-eckuA z-79rLUGG3;tvP>qlKv(wN_#JyfB3LnOyRjw+uwB&d*6M2t@ma99gdKS_ zqgvt`QIe8al4_M)lnSI6j0_BobPddPjSNBz4XsQKtW1ry4UDV|3^bk`1*%8Vkei>9 xnO2EgL*&ldJwOeDARE#$b5ipXb5pHKfD8tMcw2V`+|tMvjKcnFos=y-9lXCgo7V z8jTDcjSQ8JfaVLXH@Fy1GIPyVc8r`4G)1+lzt^ z7#doc8d#YcYa19@85n3hISN#dq#-vyB{QuOw}!}_wR?aX1VJ{WW#**jCFZ7Dl>iwG W2Jr?vST`zwjPrE$b6Mw<&;$VUWNehK5$A23DrV+6G2e1_l~Wjsn#qX~@k_$xN%nts!z}?H-^8L68k;nK`L> eiMgp(B|rv)LA>F4rp9d`<2+scT-G@yGywpkHgKc> literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/mouldyWheat.png b/forestry_resources/assets/forestry/textures/items/mouldyWheat.png new file mode 100755 index 0000000000000000000000000000000000000000..8fa5755cd3d37c739c5f17467629bbd2d378a35f GIT binary patch literal 3100 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/naturalist_armor_1.png b/forestry_resources/assets/forestry/textures/items/naturalist_armor_1.png new file mode 100755 index 0000000000000000000000000000000000000000..4ba3e7a5250c2a63f04f3b42d5e568888356551b GIT binary patch literal 838 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3HERU8}DLQfx`y?k)`fL2$v|<&%LToCO|{ z#S9E`2SAunP;c9IpdfpRr>`sfT{bQbb}74^eG?cMm@a#|IEGZ*dVAYGLnKq;_{aCg z?^W2uwgm?4aI#TRP!h{zaSh;8iHJNkSFbUGWustjuF|rAoS-!~ek>0X*l5stMlEEzkW~a~W`5bXZi{oXF@1NS;cgrhp&iuYvU;p&Foz}0u>t56qU{Gc7 zVwl39!5F}_fW?8cK?u9Rm2Db#S9MOCHjUxM_uo@ePyRc9{KuE)+Pm)R1qTPu?t5>y zT7F3$Hv=~}cSxw~=9_=|5=-9~m+>A`S69#68fD*8pK)jTS8n~Bx;i-qj@v`^}yWPwVb|O0}-tuKe zMN3Iae%!dxFf1&L=f^j}?P;4|{;jLupysyz`s4YJ7e8@se5h3PAf($|Uv2_F>zXs2 zODD1%U){3*T3sOkg=cfsLB@0OJ5L^t4*#gK;rRp3cX9h! z6d3|S|H&TT{QutHdkkEw`x)K55<_cs43tkBecH6obDl+-W@wLySVTL++yB;n=fMd<%ROvT-+fWl};Ny zdQjNW$LMM@X;q#6((1kOQ<=l(Jvex>v14Mz0fQnX&4q3c8zmAeD`)cd1US7EusJ%( z;{uz*uRs6$?QKuqxg%3KkNJW|qOH^N%MXvewEXslXHQ)0--kc*Z6kktIIWjcRyNI^ zZ+=Q{Zm-+ogLjv|2L^IV^w;wXIy*Vt+}#;%P8*fgRHocim+*UdH99>l?bv3W)#lO( y$EUmBsbA^*U>oCtFSfYS0O3@Eq2kK5uc9t}LVK!%uJ!{{JcFmJpUXO@geCwdi(NMW literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/oakStick.png b/forestry_resources/assets/forestry/textures/items/oakStick.png new file mode 100755 index 0000000000000000000000000000000000000000..9208738d3009aa88c0eccd6eb2ad6baa29b12cfb GIT binary patch literal 2991 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 D?l?s~ literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/particles/flame.png b/forestry_resources/assets/forestry/textures/items/particles/flame.png new file mode 100755 index 0000000000000000000000000000000000000000..3f1966252a108691dceba5233e7c74cdec8cc70d GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85sEXfH33KJw={CLG}_)Usv`!EKH(o5-Y3Rz5swc6x=<11Hv2m#DR*OJY5_^BrYc>I57Q}l=x@7fKg2(POQw8 zLpaai&;R+Ys~S2RBR<%7Km7k+TA=6lkM+m@Esk!^Y<*+M)@H*LrZAg?9j@5qurnmv^4+yc SmGuQGWbkzLb6Mw<&;$U(I57SI literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/particles/poison.png b/forestry_resources/assets/forestry/textures/items/particles/poison.png new file mode 100755 index 0000000000000000000000000000000000000000..5183d1c3dfb0a5cda6cd21194fe6c024f25d05f5 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqY)RhkE)4%caKYZ?lYt_f1s;*b z3=DjGK$vmro+3}6AbW|YuPggq7Cug6+4s}kjsS&ZGeaUuobz*YQ}arITm}Z`qSVBa z)D(sC%#sWRcTeAd6une-ptzf-i(`ny<>Ukhwm6>uk{1|+x%`EK1y?aiuTYx9wSl3f zDP_e)vlZ726s6^}1iA{i^|YOMofMZjFmlf+ZD~w2J)C7B&Bk!>CbzU$qWT(;Ri3VX JF6*2UngC)OJ?H=c literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/particles/snow.1.png b/forestry_resources/assets/forestry/textures/items/particles/snow.1.png new file mode 100755 index 0000000000000000000000000000000000000000..69fb8fbd7611ee90a8eef39d98b408da48a3e2ab GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enkiEpy*OmPa4+kf!a^+gyML;2`64!{5;QX|b z^2DN4hJeJ(yb?V>*ARs=V?9$nLqqq^PUb*W`JOJ0Ar}5y`?$FdDDXH}|M%Xl)VsvA zj_r1Hf^X18t+iX1t_$eCAeuFCYpb^*^S56%jT5}<%EBs{)TU~!ob2Gi+WAWDaH!=^ zd7FTG!Sc>mdfjKBIqPAt>jzyh?I N!PC{xWt~$(698fzTLl0B literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/particles/snow.2.png b/forestry_resources/assets/forestry/textures/items/particles/snow.2.png new file mode 100755 index 0000000000000000000000000000000000000000..5e92bb1a33605f5592ab2f1dcbfbccbaf9e770f2 GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enkiEpy*OmPa4+kf!a^+gyML;2`64!{5;QX|b z^2DN4hJeJ(yb?V>*ARs=V?9$nLqqq^PUb*W?Vc`w=(+0_-T!B>XLg*7de^Q*O-5? zO`Oc5FIXxbe_Zw(L%G}J`|=kKfCc;uZg0MM;ro$;?(tJ5S8>1V>~-1Pd9SyG`h6EbLnhbP|K7tDnm{r-UW|JfUUa literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/particles/snow.3.png b/forestry_resources/assets/forestry/textures/items/particles/snow.3.png new file mode 100755 index 0000000000000000000000000000000000000000..6da05f7f31c5f3b4826ca8540fffdc0f920099ae GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enkiEpy*OmPa4+kf!a^+gyML;2`64!{5;QX|b z^2DN4hJeJ(yb?V>*ARs=V?9$nLqqq^PUb*W9iA?ZAr}5idl~r-8*niH{J-3|z$Z=P zqSjj#?JMpuDRFy_i$-zv112yJ!0^#6P?x{OjNL8Sdi6 zic-5$xYeJ<%3cutSKsjB&6Lx3ML$jc#8p0lY0ZMWPv)-JzuvH+c46ra_MeKJ1@C%` p1N~K=N~C_8cz=?QT~gXNM(;xwPwIp;egoaa;OXk;vd$@?2>|FUZV&(f literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/particles/swarm_bee.png b/forestry_resources/assets/forestry/textures/items/particles/swarm_bee.png new file mode 100755 index 0000000000000000000000000000000000000000..31114894bcddc585a35aa27c6b412e30b126d3c6 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=Dj0L70*6eM34>kiEpy*OmP)3m>P6uzTKL7NF2nPZ!4!i_>o>267!T5O66M;=jnz zE4rxtBS#bacHIuKZ2iRJ>tCt4iTru{`_!hHH$B5rp5-s-&W$Ltx}MwrdF8@)>#s>K zVRP%||9yA%%=Jw_v{H@+GTFwuJh>6Gxcgq@&O7gz7;dtZ-c}Z^PCsfbEjhJS@#OOj zt$A9)b-(v)GI-M_sPEOq;jWW1zswZpKeE`g=rz-+r9cNVc)I$ztaD0e F0s!x9WZ(b* literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/peat.png b/forestry_resources/assets/forestry/textures/items/peat.png new file mode 100755 index 0000000000000000000000000000000000000000..b5c81a61a1b3cadef0e35691c0fc32013c86d5a6 GIT binary patch literal 3048 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 p0B~VvWiELyF*aRaaA9XQQXW*8-A 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/refractoryWax.png b/forestry_resources/assets/forestry/textures/items/refractoryWax.png new file mode 100755 index 0000000000000000000000000000000000000000..b3eb0749b94ef82d3e637114234e3a5aedf1e28e GIT binary patch literal 3025 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/slots/blocked_2.png b/forestry_resources/assets/forestry/textures/items/slots/blocked_2.png new file mode 100755 index 0000000000000000000000000000000000000000..cb36e1d7f0cfd4f9e5a19e3f15ebe4fe60a28695 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqRw*t{wb>bJJAgudo-U3d7N?UFB;p)g!@lkBTJxqp z=*i3iO%=DEMj#NJf5^ID-uRKw;Yt2UIg-5|1-hG`B f%O7za0lMVJLBqyP&0c~)lNmf+{an^LB{Ts5Twp$7 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/slots/container.png b/forestry_resources/assets/forestry/textures/items/slots/container.png new file mode 100755 index 0000000000000000000000000000000000000000..a6fe90e28c9bcf00b5787130cc5220d02e2ed6b0 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFhExvr5xh@qjC zsezTLv9^Jcm4SiAlcPZONE&kUQ!>*kachX&S-S_QK@em^T4qjaUSe*lRSA&6U=VM5 SBHwjA$T&||KbLh*2~7YOjceWj literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/slots/liquid.png b/forestry_resources/assets/forestry/textures/items/slots/liquid.png new file mode 100755 index 0000000000000000000000000000000000000000..bb472236567bdb819cd123e18a6f9408b9bce449 GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uop6XKd}Uw^Ise_C4F z|NsBn`uf{};!Gt$e!&b3Ws}cZ0C|i_-tI2Uf;>JT>o^NMB8wRqxP?HN@zUM8KR`h} zPZ!4!j_b(@42%~qTnJ#hxM8J%QkG`Vi6~CxFkNQB%MN#D8ZfP4S;L&eFoA)A!%JlS z!Sf3r0d=aDxJHzuB$lLFB^RXvDF!10LnB=Sb6q2Y5JN*NQv)kgV{HQ?D+2?KCr5$m zku>Dyr(~v8;?@wkvvvtmPz literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/slots/locked.png b/forestry_resources/assets/forestry/textures/items/slots/locked.png new file mode 100755 index 0000000000000000000000000000000000000000..3bb8f80f0a6f6939caf038e33ed7b6ca1c0ef75f GIT binary patch literal 2816 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/stamps.0.png b/forestry_resources/assets/forestry/textures/items/stamps.0.png new file mode 100755 index 0000000000000000000000000000000000000000..9f5df2830b90a0cc8f8f527e20d60d835e187a26 GIT binary patch literal 3043 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 lWiELyF*aRaaA9XQQXW*8-A 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 xVQpnPbZKm50B~VvWiELyF*aRaaA9XQQXW*8-A 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 ZE_g37HeGAjVsHQe002ovPDHLkV1mH&d>#M* literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/treealyzer.png b/forestry_resources/assets/forestry/textures/items/treealyzer.png new file mode 100755 index 0000000000000000000000000000000000000000..c3025bcb27d7b1c824e62e2a3f99570fbaf92087 GIT binary patch literal 3055 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 HB{Ts5seyPl literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/lowFertilizer.png b/forestry_resources/assets/forestry/textures/items/triggers/lowFertilizer.png new file mode 100755 index 0000000000000000000000000000000000000000..e4e9f1b8ba7e39b13f2ace09d9a2a2debe975229 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF|%)>uYnxS0*}aI1_o{+ z5N5n|x9$&6(8troF@)oKa>4;_3DyH5lP7JMJV|Iq;+iE(mM|pE(6V%rIH=~S&^BRG zp@s*qa6se6NlF15Crw&4(_6`9I=2TWbMqo^u9kxe8XZ@i7(yR$s^-V*^#ILPEpd$~ zNl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cps|0B< z)-^EHH8Kw|G6HEZ0ctP=YA|HrsRwFM2HB97nUk8An44-<0%R~0B&Mh8Rq7j>#m0k~ V6(DBzjidsQ1)i>cF6*2UngGN?dx-!5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/lowFuel.png b/forestry_resources/assets/forestry/textures/items/triggers/lowFuel.png new file mode 100755 index 0000000000000000000000000000000000000000..e4e9f1b8ba7e39b13f2ace09d9a2a2debe975229 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF|%)>uYnxS0*}aI1_o{+ z5N5n|x9$&6(8troF@)oKa>4;_3DyH5lP7JMJV|Iq;+iE(mM|pE(6V%rIH=~S&^BRG zp@s*qa6se6NlF15Crw&4(_6`9I=2TWbMqo^u9kxe8XZ@i7(yR$s^-V*^#ILPEpd$~ zNl7e8wMs5Z1yT$~28Kqu2Ijg(1|f!qR;C74rpDR^Mpgy}8c&V_)gx)h%}>cps|0B< z)-^EHH8Kw|G6HEZ0ctP=YA|HrsRwFM2HB97nUk8An44-<0%R~0B&Mh8Rq7j>#m0k~ V6(DBzjidsQ1)i>cF6*2UngGN?dx-!5 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/lowGermlings.png b/forestry_resources/assets/forestry/textures/items/triggers/lowGermlings.png new file mode 100755 index 0000000000000000000000000000000000000000..fae6e5dcc3f3e73e0ca705578f7d4ee4c2d35a85 GIT binary patch literal 437 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFQK$!8; z-MT+O!FW#>#}JO|p=Yi68WaRrE-)?>f5ga<^zdN-v*LdsKz{&!T%} z4g5^&_slzG%EKJ#Xv8hFzU%hPF4I%TrW`!9nDs=ijWdhYt9g;kh1)mhc+V2~@bGso zD}QDducX)XTl0Zdsg}4#l%ynKd7c7#V>ym;f~x0yP*i@YDk}D1&TB%gjm5OUzBR mDgiPW3KG*(^(yrZ&0^!h%nA@Q`$kd$$O2DSKbLh*2~7Ylh=Z*F literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/lowInput.png b/forestry_resources/assets/forestry/textures/items/triggers/lowInput.png new file mode 100755 index 0000000000000000000000000000000000000000..5456205dee802d8646f957dfb5732b0736cdf5bf GIT binary patch literal 448 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFKmV#jMBhqJ&VvY3H^ zTL^?1FWs&C0~Ad2ba4#fxNdr8w_t;UK+8kr4GqkO;m4RHuG~33VR0UF)_>CzyuaMz zH*9vP?<$^Uxj4Bj?!gx0;v95uku910&kr7CP2~dL}P=g@@Pd!kB yGRTIs%$(G`#N1S?5+H-2ATd2vuTtO8EH)m@tN<~yZzL6fEbw&ob6Mw<&;$TsABi&n literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/lowLiquid.png b/forestry_resources/assets/forestry/textures/items/triggers/lowLiquid.png new file mode 100755 index 0000000000000000000000000000000000000000..c7996a85bedd151fbf9e67fe9c75aac65dc1f380 GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>Px!M^$Id1Zrn0 z3GxFvp=|P53m}g%$=lsUVCp7b9UzCZz$3Dlfq`2Hgc&d0t@{HMO!jnf43W5;dOlF7 zL4kwiLX_5;mRS{7b2Ee=6?Ki^SG*F zm9gdNhWqj@3vN76HkiPW!g@Momhuj>Ia|zB*sOGe5=1na*{`48wq!LscX{*c`|IWN zKHKv9R~}lg0JKH5#5JNMC9x#cD!C{XNHG{07#issnCluDgcurHnHpG`8fzOESs55; zJUI$fkE9_tKP5A*5~RUc*T7KM$UMZz2&BOTsKF4Z!H|Kc9;iVXWJ6kJPHJ9aZmLxY lkik%pn4YRvsc&c&8xLkyfSB1gk_tc;c)I$ztaD0e0suuWgjxUq literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/lowResources.png b/forestry_resources/assets/forestry/textures/items/triggers/lowResources.png new file mode 100755 index 0000000000000000000000000000000000000000..1635fc01d6a9d162c9750becec15bf7ae59576bb GIT binary patch literal 467 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFe`3bh6{tBdTi`vmWs%e5p}h7<7X#-EwMnrjco-&pm+}nW5OfG=t7?gB zL`h0wNvc(HQ7VvPFfuSS(ls#GH8Kb>G_*1`urf8)HZZa>Fwl5%6sR6aLvDUbW?Cgk zgR!oGp{|j6h>;OUg9%WBAy9)M15Z6rgEGj5w9K5;yu{p8s}dlCp&&6mRj*Rt&@46{ X%&Y)0vu`97fGqHI^>bP0l+XkK^0}aS literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/lowSoil.png b/forestry_resources/assets/forestry/textures/items/triggers/lowSoil.png new file mode 100755 index 0000000000000000000000000000000000000000..2836e4dca6b4b124117f4b1e6392a4935a99a440 GIT binary patch literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>TjIz8; zYC_C%e2hT%2(mN$|Ns9e>(2?mKu{?O@&g4VLBPfs$OBZwnB?v562zOJ3)0M4;1OBO zz`!j8!i<;h*8Kqrp7V5Z43W5O+W)ew$w0u(eI=KaPSn`zqDwQ!3mX=+611nfnFz*CMd5mG;5!%`8Kjm zM|;9{-eWWVy)!uYM({*U}%W!f`!0p@Gp&(N$Gd(bbX7 zO;x~v(a@>!0P6_>Z*E?1Z)T$_mrh;2bVDyr(~v8f;1TG z8W`#tnTHq|fi#!^H5dXl7&7qG12rgvY)H$@NzF^lO|>ckG8hUH(^K^-^$pEpff-+kG9^~sbYHw!kNoqgiY(sK{~|NmcEw*3H57jsFFUoepVRd(ba zkYY^oc6Z_Zwk7c^ki%Kv5n0T@z%2yAjF;}#{Q(LVdb&7F){*aFac^X1Zps3;Hd{{PzKqMmYI{9mzbMsRRUx%6eOmn e>Q(9+n#IP0nH3;r_Kl2}g>7mZp>@CxfJtpO*k* zxVY*DhQ-_yChBoaz2qUzpc&>JbjpJz^Zbc`AoebUl^Z+N8@Cu57#VRTZ5C%p=H;w^ zQ55q5XoG5rYeY#(Vo9o1a#1RfVlXl=G}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@ zNkeXaN@iLmNQ1GifuXLEd5Dn_NP`JbgCS6ZAp=i6P=hkahP2F_)V##pRI3sogP|ZX gJyow#-_R^J9?Yx&F|%(Z6@V=8boFyt=akR{0D*XT(*OVf literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/triggers/missingQueen.png b/forestry_resources/assets/forestry/textures/items/triggers/missingQueen.png new file mode 100755 index 0000000000000000000000000000000000000000..71d5a1d2114774360eda9330ebc985ba81f0b5af GIT binary patch literal 452 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LY1m|Ns9NC$wH% z&H8VtKW9>tnu=6&U5cy()7x_@FHVR!?=4yjRK!>k(o5jGX8wa73t3D1oPt z!6+g|!X;M5u}H5^QBUD(lBS+O;};Y04GhUr6E13UO#SpqghBILM&ZjWmdy9BiaxS* zZKx>l*k;kBo0!59-N?sKcvrxb>&h`%plzxpt`Q|Ei6yC4$wjF^iowXh&`8(7T-V4T z#L&>n)WFKrSlhtJ%D_P5$x)zsBn`RwDVb@NAPvU428Oyu<{?H#APpu!4TeAsh73IQ zKn={vX42FWl^i;h{eM7U@crdd9#LT{tQ~14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>O>_%)r1c1j3A$?$-SQ3PyOkIEF}EECERZ{4M-()5kBYSKi-ORo1{GAd3u=zMI33&W%adCi*~ZLe2l*}UQn zObe|;CUQ0Lp4zDe)*Zz*8%zs%Igd?D2sXoqTvYeY#(Vo9o1 za#1RfVlXl=G}1LN*EKQ-F*LL?HLx-@);2J*GBD71aulc@NkeXaN@iLmNQ1GifuXLE zd5Dn_NP`JbgCS6ZAp=i6P=hkahP2F_)V##pRI3sogP|ZXJyow#-_R^J9?Yx&F|%(Z Q6@V=8boFyt=akR{06`y`c>n+a literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/vialCatalyst.png b/forestry_resources/assets/forestry/textures/items/vialCatalyst.png new file mode 100755 index 0000000000000000000000000000000000000000..cef169ef6098e41a25ba587c4c2192fc41d21b9e GIT binary patch literal 3035 zcmV<13ncW3P)QQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000aP)t-sYd?S1fB*mLb?DVk0_N%{2qUNO4<% zDg{@J&75!uL!zUj5zK%90EY1uSwf((n*aa+C3HntbYx+4WjbSWWnpw>05UK!GA%GS zEiy1vF)=zdFgi6eD=;!TFfb_O#Q*>R03~!qSaf7zbY(hiZ)9m^c>ppnF*7YNF)cDT zR5CI;H846fGb=DLIxsLX01STs001L&MObuZX>4U~VQpnPbZKm50B~VvWiELyF*aRa daA9XQQXW*8-A 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 tbZKm50B~VvWiELyF*aRaaA9XQQXW*8-A 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/items/wrench.png b/forestry_resources/assets/forestry/textures/items/wrench.png new file mode 100755 index 0000000000000000000000000000000000000000..6c4df621b187eb40cae2a23ea3c777486a522246 GIT binary patch literal 3013 zcmV;$3p(_PP)QQXW*8-A zzUY7=mKSrvA{%}7S!8E1vr~C&5sS~9&Q4{Exl6=bvxFQGBYq+-%HndeMSMrZS}DR* zu87}?V^cZIOaM?Mv0cDnC5qTg#3X)5u$zdN0DvPUe8q8Jv4E2!5MRnIEj^ddO-K~b z^;r6Jb2~c*-J6r0!Vw6J1DUL3CZA1rOG`~>@^S%Kyz^(th-*t171_qz&c?>r!o>Wm zLjBjxzbSEV7wJ{d=bk~do-ek)@=L1)fH5no&CV~jxJm%pHUl7k|BFrQ5CD>*zP0v! zbsw5|UJ?a@bbC|N?Cfk4E{A0zF6bZnpALURU%k&nobHeE(A_!lOks+EF0LCZEhSCJ zr)Q=!Ssc3YpNIG#2mbXrjDk7w96pC9iU<=;8JCwJYB!I~6>!sdbT02dHSr&Y{Yi^+ zEfS^f6QIVJ0I5DIKz{83C<+lE(Fep`|D$hy_%IMCdWNe_EYAIBLI0i=E)_4C+=S0@ zZowgRmXM#dxF`NB0U8j1B%lHXpb9jB9xw(Lz!o?FXW#*rfdCK!BEf3F0*N3M@If}n z2OB{VC;>acUQh)Nf;vzSn!qX02F`*@;3~KYZh=AY0E~cf@Epv5H((xuAS^_ND3AiA z25CcvkOjnmmO>to9~2BlLa|T+#Dj!TKC}rcfy$sN=rB|deGi?1Ewr27{qt zbTPIVZ%ia639|;X9kUWF4|IIf^VG?;zKcFOwgW-%3y~GIwLD1Yb6^dnjq(xY9_3jTRTVFlbd^e#%PP~V zG*xHSB-K5t=T)cFC~8a9xN3XUE~q`D%hFxwDf9|@7kx%uS>0P*sD4GLqA!6zy2))*udH#(V*I(&k#1WG2|NVH|#e;8`&B0 zjB1UBjY-BX##zRV#-k=Q6F-vzlQxqVrdp;^rn^kLO+T4go28i5nLRLRv9>j~ z!wf1Tkg=U{%?@qnYPa6*tlc|%8+(EMDf{0Xj2)648XP8<=q}+bsarDUsNu+TJnT5K zl)f}}>7k_~PU=ofr&^~c&YI3_=cCROF8VG>E+<@GxSF~0U0Yn|-0a=fx?OZf+`Zh3 z-FrP`JVHIHJRW;$cqVu@dd_%Rd#&-h=#BRF_1@(@?4#nt@~QWkS!TOz?XoUklJ5%N zD&Hr527Y|M4u9Bxng4G8hs(8>^Om;-fB>I>-2smRbpta3e+kO!f9p~BG4Fv+m!u==pMaQE=C@R119h_w+nBNZdLk?m2~sIaJ` zQL`&OR_#G%4r>s5~BN@YtIUS3R4UcVz{lE-h)-q?~eBx^2 zW>{{leXQqfXZ9ZU6vvTM#+itBj4z9yOmIxtoiLT?lvtiP&2{5eabG5RCml?hOAbgr zmb{P>p3^cpbDZ zZe8bk&Gm)r$2WLwIKGjvF?r)p1!e_h1+O=SZ|W#iDcn#vw%KcQW06D=zi4=i!_8Z@re^c?z!jAYIy`?s#2XMans>uT64)sa8h{k+4r&E51sNo z)p?q6y6Fe)A8J}CEyb-+Yi{dITVmTtdt`h6nPq1>I~+P%el+><*je?n)#qf-m7XV@ zFFe0+A@9QM#q^8Qml7_Gb;fi)xEyi$PFGM@?-k!G*RFbAz1;26ec_tpwX@glub;WW zxY2gg=4NY;bx+Gr)<3oM+Vr;e+4i;Hvb)vMzoh^CfYZRG+wQlo-toC}b8z`!|4``A z-Qnork-O}>llM~Yy}X}wfBwOShv)Fa@ES}^!ot4*1DNyt(xfk}0000WV@Og>004R>004l5008;`004mK004C`008P>0026e z000+ooVrmw0000LP)t-s000000000000000yp}D3XdnOo{|PESg8%>k19VbOQvd-1 z4P%tE00001VoOIv24QBneEwVmm|a|g86esqGRO>95*Wz!-Y literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/unsorted/tile]-10.png b/forestry_resources/assets/forestry/textures/unsorted/tile]-10.png new file mode 100755 index 0000000000000000000000000000000000000000..373882cd70a93086bbc66f14e4d290d2aa2c4fb7 GIT binary patch literal 3078 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 daA9XffENG& literal 0 HcmV?d00001 diff --git a/forestry_resources/assets/forestry/textures/unsorted/tile]-88.png b/forestry_resources/assets/forestry/textures/unsorted/tile]-88.png new file mode 100755 index 0000000000000000000000000000000000000000..c886dcda6cb762cc9b1a414961c7ffce8be44def GIT binary patch literal 3074 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 literal 0 HcmV?d00001 diff --git a/forestry_resources/changelog/2.0.0.0 b/forestry_resources/changelog/2.0.0.0 new file mode 100755 index 000000000..621ebed92 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.0 @@ -0,0 +1,31 @@ + +# 2.0.0.0 + +- Added: Multiblock farms with hatches, valves and gearboxes. Can be configured via circuit boards. +- Added: Added grafter item with 5 uses. +- Added: Alveary Hygroregulator to control humidity. +- Added: Stairs for Forestry woods. +- Added: Seperate tabs for Forestry mod items. +- Added: BC gate triggers for low soil and liquid on multiblock farms. Low soil will accept an item as a parameter. +- Added: Rubber plantation for multiblock farms when IC2 is installed. Works similar to an orchard. +- Added: 5x5 variant of multiblock farms. (Hi CPW!) +- Removed: Bonus to sapling drop rate on leaves. Use your grafter! +- Changed: New textures for apatite, apatite ore, fertilizer. Apatite ore now drops between 0 and 5 gems per ore block, works with fortune. +- Changed: Soldering iron can now switch between different layouts for the electrical engine, managed farms and manual farms. The layout determines the effect of an electron tube. +- Changed: Bonemeal now works on fruit leaves. +- Changed: Removed generational data from drones. Should improve stacking behaviour significantly. +- Changed: Refactored alveary to use single block id. Will update existing apiaries. +- Changed: Alvearies and farms will now keep their inventory even if broken. Only breaking the master block will eject items. +- Changed: Alvearies and farms can be owned like any other machine. +- Changed: New textures for copper and tin ore. +- Changed: Ore gen slightly. Apatite does not spawn below Y=60 anymore. Copper needs at least Y = 32, tin Y = 16. +- Changed: Ash cannot be used to create fertilizer anymore. It can be mixed with existing fertilizer to double it though. +- Bugfix: Fixed a bug that caused fruits to only drop a single time. +- Bugfix: Fixed some derpy backpack behaviour. (Thanks CovertJaguar!) +- Bugfix: Fixed a few soldering iron issues when removing chipsets. +- Bugfix: Fixed some stacking issues with bees. (Thanks Direwolf!) +- Bugfix: Fixed imprinter. + +- API: Full API to add entirely new farm logic to multiblock farms via circuits or just single crops to existing farms. + +- Localization: Added/Updated PR and CN. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.1 b/forestry_resources/changelog/2.0.0.1 new file mode 100755 index 000000000..f2725efd7 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.1 @@ -0,0 +1,16 @@ + +# 2.0.0.1 + +- Added: 4x4 farm. +- Added: Config option to disable specific structure schemata. +- Added: Missing config option for fertilizer value in gamemodes. +- Changed: Fertilizer lasts longer in farms on easy gamemode. +- Changed: Back side of engines is now solid. +- Changed: Farm hatches now output into pipes and inventories below them. +- Changed: Managed arboretum now uses all the available space. +- Bugfix: Fixed an issue that caused BC's emerald pipes to crash. +- Bugfix: Infernal farm now actually harvests crops and doesn't just sit there looking pretty. +- Bugfix: Alveary swarmer and hygroregulator properly drop inventory contents when broken. +- Bugfix: Fixed an issue which can cause a crash in the treealyzer gui due to old sapling genetics. +- Bugfix: Fixed infernal farm not starting up without liquid in the tank. +- Bugfix: Fixed a Java 7 incompatibility. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.10 b/forestry_resources/changelog/2.0.0.10 new file mode 100755 index 000000000..b20ab1ae4 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.10 @@ -0,0 +1,11 @@ + +# 2.0.0.10 + +- Added: Ops can now "virtualize" trade stations with the '/mail virtualize ' command. A virtual trade station does not require resources. +- Added: Genetic saplings as "treeSapling" to ore dictionary. Can now be crafted into IC2 plantballs. +- Changed: Made more trees support more fruit families. +- Changed: Increased output rate of farm hatches slightly. +- Changed: Added bituminous peat as a vanilla fuel source. +- Bugfix: Backpacks now force close the gui if they are dropped for any reason at all. Unified handling for all items with an inventory. +- Bugfix: Different types of circuit boards should not accidently stack anymore. +- Bugfix: Fixed genetic saplings not being recognized as valid vanilla fuel. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.11 b/forestry_resources/changelog/2.0.0.11 new file mode 100755 index 000000000..bf2d46312 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.11 @@ -0,0 +1,9 @@ + +# 2.0.0.11 + +- Added: Alternate carpenter recipe for letters using six wood pulp. +- Added: Alternate carpenter recipe for stamps which omits the honey drops, but requires seed oil. +- Changed: Reduced fertilizer consumption on peat farms 10 -> 5. +- Bugfix: Fixed two potential NPEs on farms. +- Bugfix: Fixed a potential crash when opening letter gui. +- Bugfix: Fixed habitat locator not working. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.2 b/forestry_resources/changelog/2.0.0.2 new file mode 100755 index 000000000..371c0fe3c --- /dev/null +++ b/forestry_resources/changelog/2.0.0.2 @@ -0,0 +1,12 @@ + +# 2.0.0.2 + +- Added: Low fertilizer triggers for BC gates on farm hatches. +- Changed: Tied seed oil output for cherries, walnuts and chestnut to seed oil from wheat, with cherries giving 3x, walnuts 10x and chestnut 12x as much. +- Changed: Reduced ripening time on chestnuts and walnuts. +- Bugfix: Rubber plantation will now tap resin spots on the lowest wood block as well. +- Bugfix: Fixed orchard infighting over which fruits are harvestable and which are not. +- Bugfix: Neutered orchards ability to eat servers. +- Bugfix: Fixed rare stackoverflow crash on multiblock structures. +- Bugfix: Fixed an issue which caused extracting from alvearies to break. +- Bugfix: Fixed fruit colours incorrectly synching to client. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.3 b/forestry_resources/changelog/2.0.0.3 new file mode 100755 index 000000000..0d2dbf385 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.3 @@ -0,0 +1,15 @@ + +# 2.0.0.3 + +- Changed: Alvearies and apiaries now accept the full stack of drones when piping into them. +- Changed: Orchards now require 10 fertilizer per operation instead of 5. Arboretums 30 instead of 40. +- Changed: Harvest phase does not consume fertilizer anymore, however actually collecting the crop will, leading to a uniform per crop cost instead of giving an advantage to tree-like crops. +- Bugfix: Fixed soldering iron eating tubes if a circuit board was inserted first. +- Bugfix: Fixed sapling placement sounds again. +- Bugfix: Fixed sipiri tree not actually being breedable. +- Bugfix: Fixed piping bees into alvearies. +- Bugfix: Moving an apiary via frames or gravigun should now also reset the biome. (RichardG) +- Bugfix: Fixed peat-fired engines not ejecting waste into pipes. +- Bugfix: Fixed stairs not removing associated tile entity when broken. +- Bugfix: Fixed stair placement consuming two stairs instead of one. +- Localization: Several updates to ES-variants, CN and others. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.4 b/forestry_resources/changelog/2.0.0.4 new file mode 100755 index 000000000..c0769489d --- /dev/null +++ b/forestry_resources/changelog/2.0.0.4 @@ -0,0 +1,24 @@ + +# 2.0.0.4 + +- Added: Another Forestry update? Don't be sad, have a cocoa plantation! +- Added: Disabling the crafting recipes for the old farms will now unlock uncrafting recipes to turn planters and harvesters into 30 new farmblocks. Craft one harvester or planter with a single brick-like block. They block chosen will determine the type of the resulting farmblocks. +- Added: Facades for BC pipes in all types of logs and planks now available. +- Added: Support for IC2 rubber trees in the arboretum as well. (Requires an IC2 update.) +- Added: Config option to switch farms to using a square layout instead of a diamond shaped one. Server side config controls it. +- Changed: Tweaked apatite world gen slightly. +- Changed: Removed the requirement of humus from the multifarm arboretum. Plain dirt is now required. The arboretum will mix it with fertilizer and will plant it out as humus. +- Bugfix: Fixed apiaries not displaying exact temperature and humidity. +- Bugfix: Wenge and baobab should now be breedable. +- Bugfix: Fixed potential NPE on alvearies in SMP. +- Bugfix: Fixed duplication bug in farms when collecting windfall. +- Bugfix: Fixed support stems on kapok and meranti stems replacing other blocks. +- Bugfix: Liquid pipes should now connect to a farm valve even if the farm validates after the pipe was placed. +- Bugfix: Fixed steadfast drones generating in stacks of ten. +- Bugfix: ExtraBiomesXL saplings now work in the fermenter. +- Bugfix: Fixed an issue which would cause an invalid farm block to drop when breaking a farmblock on the metal band level. +- Bugfix: Hatches do not eject into sandstone pipes anymore. +- Bugfix: Removed orphaned debug output. +- Bugfix: Made fruits with random drops instead of ripening useable in orchards. (Apples) +- API: Mods can now send an IMC with the key "add-farmable-sapling" and format "farmArboreal@saplingID.saplingDamage" or "farmArboreal@saplingID.saplingDamage.windfallID.windfallDamage" to Forestry to add a generic sapling. Will accept damage -1 as wildcard. +- API: Same as above for "add-farmable-crop" and format "farmCereal@seedID.seedDamage.cropBlockID.cropMatureMeta". diff --git a/forestry_resources/changelog/2.0.0.5 b/forestry_resources/changelog/2.0.0.5 new file mode 100755 index 000000000..af7708a0a --- /dev/null +++ b/forestry_resources/changelog/2.0.0.5 @@ -0,0 +1,4 @@ + +# 2.0.0.5 + +- Bugfix: Fixed dirt not being accepted when piped into a farm set to arboretum. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.6 b/forestry_resources/changelog/2.0.0.6 new file mode 100755 index 000000000..0a2a10456 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.6 @@ -0,0 +1,10 @@ + +# 2.0.0.6 + +- Added: Managed and manual mushroom farm. (Apatine Electron Tube) +- Added: Some basic craftguide integration for carpenter, thermionic fabricator, squeezer and centrifuge. +- Added: FarmCraftory support for crops and vegetables. Corn is handled in the wheat farm, everything else in the vegetable farm. +- Bugfix: Fixed potential rare client crashes on Beealyzer, Habitat locator and Treealyzer. +- Bugfix: Fermenter will respect NBT data now. +- Bugfix: Fixed slight issues with sand replacement in MF arboretums. +- Localization: Updates to it_IT by Frantisek-Markov, to zh_CN by crafteverywhere. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.7 b/forestry_resources/changelog/2.0.0.7 new file mode 100755 index 000000000..0702d1fd8 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.7 @@ -0,0 +1,4 @@ + +# 2.0.0.7 + +- Bugfix: Fixed wrong mushrooms being planted in mushroom farms. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.8 b/forestry_resources/changelog/2.0.0.8 new file mode 100755 index 000000000..8d76865c1 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.8 @@ -0,0 +1,14 @@ + +# 2.0.0.8 + +- Added: Farm Control. Will disable farm sides according to sides with redstone signal. A redstone signal from top or bottom will shut down the whole farm. +- Added: Craftguide now displays recipes for farm blocks, still, fermenter, bottler. Better use of CraftGuide API. (RichardG) +- Added: Bare-bones '/mail trades' command. +- Changed: Crafting of old farms is now disabled by default on new installations. +- Changed: Farms should now handle their storage more intelligently. +- Changed: Forestry now auto-ops its fake player. Can be disabled in config. Login of fake player can also be changed in config. +- Changed: When opening a backpack gui, inventory slots with backpacks in them cannot be manipulated anymore in any way. Behaviour of letters has been changed to match. +- Bugfix: Capped modification by drought in farms at 2500 %. +- Bugfix: Energy modifier in game modes should now affect farm gearboxes. +- API: Changed IFarmListener around a bit for better functionality. Made StructureFarmLogic retrievable. +- Removed: Automatic display of changelog with version notice. You need to type '/forestry version' if you want to see the changelog now. \ No newline at end of file diff --git a/forestry_resources/changelog/2.0.0.9 b/forestry_resources/changelog/2.0.0.9 new file mode 100755 index 000000000..25940dab9 --- /dev/null +++ b/forestry_resources/changelog/2.0.0.9 @@ -0,0 +1,7 @@ + +# 2.0.0.9 + +- Changed: Limited iteration of arboretum and mushroom farms to +/- 5 from the tree trunk horizontally. +- Bugfix: Fixed an issue which caused arboretums to sometimes "forget" patches. +- Bugfix: Removed debug log message. +- Localization: Update to zh_CN by crafteverywhere. \ No newline at end of file diff --git a/forestry_resources/changelog/2.1.0.0 b/forestry_resources/changelog/2.1.0.0 new file mode 100755 index 000000000..fef68282c --- /dev/null +++ b/forestry_resources/changelog/2.1.0.0 @@ -0,0 +1,5 @@ + +# 2.1.0.0 + +- Added: Blue Mahoe, White Poplar and Lemon trees. Pine logs. +- Changed: Decreased chance for swarmer queens to die off by a factor of 10. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.0.0 b/forestry_resources/changelog/2.2.0.0 new file mode 100755 index 000000000..2f32a1fa6 --- /dev/null +++ b/forestry_resources/changelog/2.2.0.0 @@ -0,0 +1,25 @@ + +#2.2.0.0 + +- Added: 5 new bee species. +- Added: 8 new tree species. +- Added: Bee house as a low level alternative to the apiary. +- Added: Clockwork engine. Wind it up for early game energy. +- Added: Vanilla hopper support to all machines and engines. +- Changed: Trunk size on trees can now be inherited. That 3x3 cherry tree is now possible! +- Changed: Internal changes to several machines to improve performance and some interaction with other mods. +- Changed: Raintank is now an unpowered machine. +- Changed: Bottler now uses the liquid dictionary to dynamically populate its recipe list. +- Changed: Seed oil output has been rebalanced, reducing it further on easily obtainable seeds. +- Changed: Several changes to the default traits of several tree species. +- Changed: Sapling yield in the fermenter has changed. The amount of biomass produced from a single sapling is now determined by the sappiness trait on it. Saplings without genetic information are treated as though they have lowest sappiness. +- Changed: Adapted to new vanilla bonemeal behaviour for saplings. +- Changed: Added squeezable lemons and plums. (Sprites for both by Xizzzy.) +- Changed: Apple juice is now fruit juice. +- Changed: Increased the guaranteed drop from apatite by 1. Reduced the minimum world height required for apatite to spawn to 56. +- Changed: Reduced power requirements for farms a bit. +- Changed: Reduced fertilizer requirements on some of the more basic farms, including arboretum. +- Changed: Changed humus degradation behaviour. Now only degrades over time instead of on-growth of a tree. +- Changed: Drastically increased the potential generations artificial princesses ("swarmer princesses") can reproduce before genetic fatigue sets in. +- Changed: All work and no play makes the queen a dull girl: Forcing a queen to produce way too fast or trying too hard to mutate her may result in undesireable consequences. (Note: Only applies to outside factors, not to factors inherent in the queen's genetic makeup.) +- Changed: Minor improvements to treealyzer and to sapling tooltips. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.0.1 b/forestry_resources/changelog/2.2.0.1 new file mode 100755 index 000000000..a802a8f5d --- /dev/null +++ b/forestry_resources/changelog/2.2.0.1 @@ -0,0 +1,11 @@ + +#2.2.0.1 + +- Added: Sapling rate and yield to sapling tooltips. Extended tooltips on bees and saplings now hidden unless shift is pressed. +- Added: Papayas and dates can now be squeezed for fruit juice and/or mulch. +- Bugfix: Vanilla hoppers will now sort liquid cans through farm hatches. +- Bugfix: Biofuel now replaced by whatever the liquid dictionary returns. +- Bugfix: Fixed a crash when placing alveary hygroregulators. +- Bugfix: Fixed registration of analyzer recipes. +- Bugfix: Fixed mahoe having an incorrect sappiness allele. +- Bugfix: Fixed treealyzer not rating sapling rate, yield and maturity correctly. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.0.2 b/forestry_resources/changelog/2.2.0.2 new file mode 100755 index 000000000..1398a000d --- /dev/null +++ b/forestry_resources/changelog/2.2.0.2 @@ -0,0 +1,10 @@ + +#2.2.0.2 + +- Changed: Slight boost to output on clockwork engines. +- Changed: Biofuel is now ethanol. +- Changed: Ethanol burns at 4 MJ/t in a combustion engine for 60.000 ticks. (Biofuel was 5 MJ/t for 40.000 ticks.) +- Changed: Bio Generator produces 32 EU/t for 4000 ticks per bucket of ethanol. (Biofuel was 32 EU/t for 2000 ticks.) +- Changed: Honey is now worth 2 MJ/t in a biogas engine at 10.000 ticks. (1 MJ/t for 10.000 ticks previously.) +- Bugfix: Fixed still consuming filled cans when running out of empty cans. +- Bugfix: Fixed a crashbug in the treealyzer when a tree with different amounts of tolerances on primary and secondary allele had been bred. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.2.0 b/forestry_resources/changelog/2.2.2.0 new file mode 100755 index 000000000..2c8096406 --- /dev/null +++ b/forestry_resources/changelog/2.2.2.0 @@ -0,0 +1,9 @@ + +#2.2.2.0 + +- Upgraded: Minecraft 1.5.2. (May work on 1.5.1, unsupported.) +- Added: OP game mode. +- Changed: Sprite for royal jelly by niel. +- Changed: Handling grafters differently to re-enable normal leaf drops. A grafter may give an additional sapling now at the usual drop rate. +- Changed: Boosted proven grafter to 150 uses. +- Bugfix: Fixed an issue which caused planting in arboretums to become irregular. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.2.1 b/forestry_resources/changelog/2.2.2.1 new file mode 100755 index 000000000..eed91266b --- /dev/null +++ b/forestry_resources/changelog/2.2.2.1 @@ -0,0 +1,11 @@ + +# 2.2.2.1 + +- Added: Use the new mail order catalogue to browse trade stations on your server. Click 'Use' and open a new letter to have the address filled in. Crafted using a stamp and a book. +- Changed: Increased the default yield on some tree species. Made high yield attainable. +- Changed: Three letters of any state or size can now be converted to a piece of paper. Use to recycle at will. +- Bugfix: Bee houses now drop their contents when broken. +- Bugfix: Fixed title display in trade station gui. +- Bugfix: Fixed letter gui being cut off at the bottom. +- Bugfix: Fixed the arborist potentially selling an invalid wood plank. +- Bugfix: Fixed recipient type being changeable on sent letters. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.2.2 b/forestry_resources/changelog/2.2.2.2 new file mode 100755 index 000000000..9482840f2 --- /dev/null +++ b/forestry_resources/changelog/2.2.2.2 @@ -0,0 +1,8 @@ + +# 2.2.2.2 + +- Added: Nether quartz to miner's backpack. +- Added: To builder's backpack: All remaining stairs, slabs, planks, fences, quartz blocks, emerald block, stone walls, candles. +- Added: To forester's backpack: Remaining logs. +- Bugfix: Fixed a crash when no matching/active trade stations where found. +- Bugfix: Fixed a crash when placing a vanilla hopper below a carpenter. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.4.0 b/forestry_resources/changelog/2.2.4.0 new file mode 100755 index 000000000..264e8849c --- /dev/null +++ b/forestry_resources/changelog/2.2.4.0 @@ -0,0 +1,11 @@ + +#2.2.4.0 + +- Added: Alveary sieve to filter out pollen collected by bees. Requires woven silk as sieve material. Sieve material is destroyed and needs to be replaced when removing any pollen from the sieve. +- Added: Fertile pollen. Contains the same genetic information as saplings and can be applied directly to leaves. +- Added: Butterflies as collectible items. Forestry trees now occasionally spawn butterflies. The type of butterfly spawned depends on several factors, including biome. Butterflies do not yet serve a purpose. They are however pretty. +- Added: Flutterlyzer to take a look at the genetic traits of butterflies. You cannot breed butterflies yet though, so this serves only informational purposes. +- Changed: Rewrote certain mutations to be compatible with biome mods. (Rural, Heroic.) (RichardG) +- Changed: Fixed some textures to reduce seams on render models. +- Bugfix: Stairs can now be placed upside down. +- Bugfix: Fixed a carpenter dupe bug. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.4.1 b/forestry_resources/changelog/2.2.4.1 new file mode 100755 index 000000000..ff1168c7a --- /dev/null +++ b/forestry_resources/changelog/2.2.4.1 @@ -0,0 +1,8 @@ + +# 2.2.4.1 + +- Added: Lepidopterist's chest and backpack. +- Added: More butterflies. +- Changed: Butterflies now pollinate tree leaves. +- Bugfix: Butterflies are less interested in drowning themselves. +- Bugfix: Removed some orphaned debug output. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.4.2 b/forestry_resources/changelog/2.2.4.2 new file mode 100755 index 000000000..9eb517bb3 --- /dev/null +++ b/forestry_resources/changelog/2.2.4.2 @@ -0,0 +1,7 @@ + +#2.2.4.2 + +- Bugfix: Fixed a crash when bees try to pollinate. +- Bugfix: Fixed butterfly rendering inside item frames. + +- Updated: Localizations by crafteverywhere, VeryBigBro and mariogrip. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.4.3 b/forestry_resources/changelog/2.2.4.3 new file mode 100755 index 000000000..e6b9ba17e --- /dev/null +++ b/forestry_resources/changelog/2.2.4.3 @@ -0,0 +1,9 @@ + +#2.2.4.3 + +- Added: More butterflies. +- Updated: IC2 API. +- Changed: Only the most common butterfly species are shown in creative menu. +- Changed: Butterflies now have a minimum cooldown period between pollinations and egg laying. +- Changed: Butterflies will flee from players. Sneak to creep close enough for the scoop. +- Bugfix: Fixed the alveary sometimes dropping a seemingly invalid block when broken. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.6.0 b/forestry_resources/changelog/2.2.6.0 new file mode 100755 index 000000000..844f9c629 --- /dev/null +++ b/forestry_resources/changelog/2.2.6.0 @@ -0,0 +1,11 @@ + +#2.2.6.0 + +- Added: Escritoire to analyze butterflies, bees and saplings. If you are successful in your research, you have a chance to get hints on future mutations or other loot. +- Added: Research notes can be right clicked to memorize them. Memorizing a research note will enter the information into your apiarist's chests and other databases. +- Added: More butterflies. (3 courtesy of MysteriousAges) +- Changed: Stationary analyzer now accepts butterflies. +- Bugfix: Fixed an issue were adding other mods could cause miner backpacks to not pick up certain mod ores. (Thanks to AlgorithmX2!) +- Bugfix: Fixed rendering and network synch in stationary analyzer. +- Bugfix: Fixed an issue loading older carpenters. +- Bugfix: Fixed planks puchased from a villager placing as a different type. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.6.1 b/forestry_resources/changelog/2.2.6.1 new file mode 100755 index 000000000..508b9cfd9 --- /dev/null +++ b/forestry_resources/changelog/2.2.6.1 @@ -0,0 +1,8 @@ + +#2.2.6.1 + +- Added: Worktable. Remembers the last eight recipes used. Right-click on a memorized recipe to lock it. +- Added: More butterflies. +- Bugfix: Fixed a crash when shift-clicking out of an escritoire. +- Bugfix: Fixed fermenter manager adding broken recipes when a certain API function was used. +- Bugfix: Added additional check to prevent an ExtraBees crash. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.6.2 b/forestry_resources/changelog/2.2.6.2 new file mode 100755 index 000000000..1d40bfc23 --- /dev/null +++ b/forestry_resources/changelog/2.2.6.2 @@ -0,0 +1,7 @@ + +#2.2.6.2 + +- Bugfix: Fixed handling of container items (buckets) in the worktable. +- Bugfix: Fixed handling of crafting equivalency (ore dictionary) in the worktable. +- Bugfix: Fixed a crash when the server could not keep up with client clicks in the worktable. +- Bugfix: Fixed a text issue which could occur on tabs. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.6.3 b/forestry_resources/changelog/2.2.6.3 new file mode 100755 index 000000000..a25e28ea9 --- /dev/null +++ b/forestry_resources/changelog/2.2.6.3 @@ -0,0 +1,10 @@ + +#2.2.6.3 + +- Added: More butterflies. +- Changed: Worktable now handles damageable crafting tools (minium stone). +- Changed: Fruit pods can now be bonemealed. (Binnie) +- Changed: Catching butterflies is now actually recorded. +- Bugfix: Ensured that broken fruit leaves don't hang the game. +- Bugfix: Fixed shift-clicking into internal inventory of the worktable. +- Bugfix: Fixed papaya and date pods not dropping fruits. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.8.2 b/forestry_resources/changelog/2.2.8.2 new file mode 100755 index 000000000..d322b1a2d --- /dev/null +++ b/forestry_resources/changelog/2.2.8.2 @@ -0,0 +1,14 @@ + +#2.2.8.2 + +- Changed: Bees requiring hellish biome should now accept all types of nether biomes. +- Bugfix: Fixed leaves only dropping fruits in orchards or on natural despawn. +- Bugfix: Fixed bottler not accepting any liquid container. +- Bugfix: Fixed an issue with naturally nocturnal bees. +- Bugfix: Fixed engines not outputting to BuildCraft's new wooden conductive pipes. +- Bugfix: Fixed a crash in the apiarist's pipe gui. +- Bugfix: Fixed a crash on cyclic recipes in the worktable. +- Bugfix: Fixed slightly incorrect size on the carpenter gui. +- Bugfix: Fixed an issue which caused stacks in fabricator inventory to be eaten entirely, regardless of actually needed resources. +- Bugfix: Possibly fixed framerate issues with spectacles on SMP. +- Bugfix: Fixed an issue which caused OP mode to handle fertilizer in MultiFarms incorrectly. diff --git a/forestry_resources/changelog/2.2.8.3 b/forestry_resources/changelog/2.2.8.3 new file mode 100755 index 000000000..73bd02482 --- /dev/null +++ b/forestry_resources/changelog/2.2.8.3 @@ -0,0 +1,17 @@ + +#2.2.8.3 + +- Changed: Fertilizer can now be used as bonemeal. +- Changed: Memorizing research notes now also discovers the resulting species. +- Changed: Changed power perdition in machines to conform to new BC defaults and increased the minimum power required for input to make sure even low-energy engines can overcome the power loss. +- Changed: Species are now discovered when analyzing a specimen in tree-/bee-/flutterlyzer. (Binnie) +- Changed: Still is now meta sensitive. (Binnie) +- Changed: Worktable will now always craft the Forestry bronze recipe, unless it has been disabled in config. +- Changed: Logs now rotate according to side they are placed on, not according to view of the player. +- Bugfix: Fixed stalled biogas engines not losing heat. +- Bugfix: Fixed an issue which caused crafting to be impossible in fabricator and worktable if there was a valid itemstack without sufficient stacksize, blocking other valid itemstacks. +- Bugfix: Fixed leaves not destroying snow when despawning. +- Bugfix: Fixed an issue which may have caused items registered multiple times in the ore dictionary to not be recognized as crafting equivalents. +- Bugfix: Putting a stack of circuit boards into electric engines or multifarms will not eat the whole stack anymore. +- Bugfix: Fixed an issue which caused bio generators to disconnect from wires on save/reload. +- Localizations: Several updates to localizations by contributors. \ No newline at end of file diff --git a/forestry_resources/changelog/2.2.8.4 b/forestry_resources/changelog/2.2.8.4 new file mode 100755 index 000000000..b444dce47 --- /dev/null +++ b/forestry_resources/changelog/2.2.8.4 @@ -0,0 +1,9 @@ + +#2.2.8.4 + +- Changed: Bee Houses now triple the pollination speed of bees compared to apiaries and alvearies. +- Changed: Made arboretums pick up cocoa beans. +- Changed: Removed GregTech nag, since it doesn't interfere currently. +- Bugfix: Some fixes to pick block. +- Bugfix: Fixed bronze recipe not displaying in CraftGuide. +- Bugfix: Added a null check to prevent a crash with corrupt saplings. \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.0 b/forestry_resources/changelog/2.3.0.0 new file mode 100755 index 000000000..3b3e23b4e --- /dev/null +++ b/forestry_resources/changelog/2.3.0.0 @@ -0,0 +1,6 @@ + +#2.3.0.0 + +- Updated: Minecraft 1.6.2. +- Updated: BC API to 4.0.1. +- Changed: Swarmer bees are gone - in a way. There are now queens of "Ignoble Stock" and "Pristine Stock". Pristine Stock: As before, but cannot be "infected" through mating with other drones. They make up ~ 20 % of the bee population. "Ignoble Stock": These have a low chance to die off. The mortality chance can be reduced via frames. They will never die off in bee houses. Amount of generations lived does not affect the chance to die off anymore. \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.1 b/forestry_resources/changelog/2.3.0.1 new file mode 100755 index 000000000..a81c48149 --- /dev/null +++ b/forestry_resources/changelog/2.3.0.1 @@ -0,0 +1,10 @@ + +#2.3.0.1 + +- Bugfix: Fixed issue which caused items ejected into BuildCraft pipes to disappear. +- Bugfix: Fixed a stacking issue which could occur after analyzing bees, saplings and/or butterflies. +- Bugfix: Fixed hopper interaction on the fermenter. +- Bugfix: Fixed crafting results slots in carpenter and fabricator not showing products. +- Bugfix: Fixed a rainmaker crash. +- Bugfix: Fixed stairs rendering incorrectly when held in hand. +- Localizations: Several updates by contributors. (See https://github.com/SirSengir/Forestry-Localization/commits/master for details.) \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.2 b/forestry_resources/changelog/2.3.0.2 new file mode 100755 index 000000000..15234fa78 --- /dev/null +++ b/forestry_resources/changelog/2.3.0.2 @@ -0,0 +1,3 @@ + +#2.3.0.2 +- Bugfix: Adding correct handling of Village MapGenStructure stuff to make Forestry not crash on 1.6.4 \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.3 b/forestry_resources/changelog/2.3.0.3 new file mode 100755 index 000000000..7340b0911 --- /dev/null +++ b/forestry_resources/changelog/2.3.0.3 @@ -0,0 +1,5 @@ + +#2.3.0.3 +- Bugfix: Correcting lockups that occur when Peat-Fired engines attempt to dump ash into a nearby pipe. +- Bugfix: Ignoble bees do not die off if their generation count is too low. +- Bugfix: Analyzer block properly accepts liquid Honey from fluid pipes. \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.4 b/forestry_resources/changelog/2.3.0.4 new file mode 100755 index 000000000..1e823c38a --- /dev/null +++ b/forestry_resources/changelog/2.3.0.4 @@ -0,0 +1,14 @@ + +#2.3.0.4 +- Change: Cut fuel values in 1/4 to align with Railcraft, IndustrialCraft standards. (From CovertJaguar) Config values available. +- Change: Making Hive spawning depend directly on Biome's temperature/humidity rather than relying on cached values. Should allow hives to spawn correctly with other biome mods such as Highlands. +- Bugfix: Adding null checks to avoid an NPE in EntityBeeFX +- Bugfix: Breaking a Farm block causes a block update. This should prevent floating levers and torches. +- Bugfix: Adding null checks in Letter code to avoid an NPE if the item is spam-right-clicked. +- Bugfix: Frames are no longer enchantable to prevent misleading enchantments on frames. (They were never checked anyway.) +- Bugfix: Multifarm Hatch should now respect ISidedInventory +- Bugfix: Preventing NPEs while listening for OreDictionary registrations that come "too soon" +- Bugfix: TileHatch should now respect ISidedInventory when outputting items to an adjacent inventory. +- Added: Squeezer recipes for Natura barley & cotton seeds -> Seed oil at same rate as wheat seeds. +- Added: Squeezer recipes for Natura berries (Overworld & Nether varieties) -> Fruit Juice at 1/25th rate as Apples +- API: Adding methods for converting from Minecraft raw temperature/rainfall into EnumTemperature & EnumHumidity \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.5 b/forestry_resources/changelog/2.3.0.5 new file mode 100755 index 000000000..155bfe8cc --- /dev/null +++ b/forestry_resources/changelog/2.3.0.5 @@ -0,0 +1,9 @@ + +#2.3.0.5 +- Bugfix: Typo in config string (CovertJaguar) +- Bugfix: Changing missing config value defaults to -1 to prevent random interactions (CovertJaguar) +- Bugfix: Prevents farm blocks from "flashing" before settling on their correct texture (CovertJaguar) +- Bugfix: Fixed issue with GUI Rendering prorgess bars in the wrong order (CovertJaguar) +- Bugfix: Changing handling of container inventories on some devices (CovertJaguar) +- Change: Fixing up particle rendering system to use distance culling and *nix dev paths (Player) +- Change: Fixed egregious oversight where feature was missing for this time of year. >.> \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.6 b/forestry_resources/changelog/2.3.0.6 new file mode 100755 index 000000000..630a32aa1 --- /dev/null +++ b/forestry_resources/changelog/2.3.0.6 @@ -0,0 +1,9 @@ + +#2.3.0.6 +- Change: Plugin Loader errors are now silent. +- Bugfix: Removing references to BuildCraft's SlotOutput +- Bugfix: Biogas Engine fuel usage +- Change: Apiarist's Pipe updated for revision of BC pipes +- Change: Fixing power cycles for all machines +- Change: Engines no longer show negative temperature values. +- Bugfix: BuildCraft gate triggers have unique names, and should not crash. \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.0.7 b/forestry_resources/changelog/2.3.0.7 new file mode 100755 index 000000000..ab14e9aae --- /dev/null +++ b/forestry_resources/changelog/2.3.0.7 @@ -0,0 +1,13 @@ + +#2.3.0.7 +- New: Clicking on the book in a Worktable will reset the grid. (CovertJaguar) +- New: Candles can now be dyed in-world. +- Change: Habitat Locator is being removed; it's broken, probably won't be fixed soon, and buggers up other icons. +- Change: Added probe button to Escritoire to give the user more control. (CovertJaguar) +- Change: Fixing derpy progress arrow in squeezer drawing over top of tank contents. +- Change: Beekeeping Mode's lifespan modifier now being correctly observed. +- Bugfix: Fixed derpy Escritoire network sync. (CovertJaguar) +- Bugfix: Fix Fermenter wasting excess production. (Player) +- Bugfix: Threaded version checker. (CovertJaguar) +- Bugfix: Various improvements to the Worktable (CovertJaguar) +- Bugfix: Improve Carpenter and Fermenter interactions with BC Gates by removing ISpecialInventory. (CovertJaguar) diff --git a/forestry_resources/changelog/2.3.1.0 b/forestry_resources/changelog/2.3.1.0 new file mode 100755 index 000000000..e3265dea9 --- /dev/null +++ b/forestry_resources/changelog/2.3.1.0 @@ -0,0 +1,11 @@ + +#2.3.1.0 +* Added: Loot chest spawns in Villager homes. You may find (somewhat) useful Forestry items in them! +* Bugfix: Apiarist Backpacks now properly save their contents when flipping pages preventing dupes/missing items. +* Bugfix: Languages other than en_US should now work properly. +* Bugfix: Worktable should now orient correctly (CovertJaguar) +* Bugfix: All Items are now registered with FML, you must install this version or newer before upgrading your world to 1.7. (CovertJaguar) +* Change: Working around Forge problem that prevents the crafting of Forestry's wooden slabs & stairs. +* Change: Railcraft integration for Ethanol has been moved into Railcraft configs. (CovertJaguar) +* API: Adding package-info to API to use the new protection in Forge +* API: Exposing 2 villager IDs and the naturalist chest gen hook key via IForestryConstants. \ No newline at end of file diff --git a/forestry_resources/changelog/2.3.1.1 b/forestry_resources/changelog/2.3.1.1 new file mode 100755 index 000000000..d0ed0f600 --- /dev/null +++ b/forestry_resources/changelog/2.3.1.1 @@ -0,0 +1,14 @@ + +#2.3.1.1 +Bugfix: Merry Bee snow effect no longer has the pink 'HAY U R MISSING TAXTURE!!!1!!1' thing. (CovertJaguar) +Bugfix: Player inventory updates when clicking with bucket. (CovertJaguar) +Bugfix: Backpacks should obey inventory restrictions. (CovertJaguar) +Bugfix: Short Mead no longer crashes. (CovertJaguar) +Bugfix: Tipsy Bee is not breedable on Jan 1st (CovertJaguar) +Bugfix: Merry Bees Snow Effect now works and leaves snow on the ground. (CovertJaguar) +Change: Drones do not carry Pristine/Ignoble traits. This should make the jerks stack better. +Change: Beealyzer now displays "Pristine/Ignoble Stock" for bees rather than "Natural/Artificial origin". In addition, stock type is not shown for drones. +Change: Attempt to reduce the number of Chunk Renderers. (CovertJaguar) +Change: Added Dropper & Dispenser to builder's backpack by default (CovertJaguar) +Change: Sandstone items added to backpacks (CovertJaguar) +Change: Silk Touch no longer works on Humus, Bog Earth or Peat. \ No newline at end of file diff --git a/forestry_resources/changelog/2.4.0.0 b/forestry_resources/changelog/2.4.0.0 new file mode 100755 index 000000000..63683c627 --- /dev/null +++ b/forestry_resources/changelog/2.4.0.0 @@ -0,0 +1,4 @@ +Bugfix: IC2 item crates are correctly being added if the item exists. +Bugfix: Naturalist's game should no longer produce AIOOB errors. +Port to Minecraft 1.7 + diff --git a/forestry_resources/config/forestry/colour.properties b/forestry_resources/config/forestry/colour.properties new file mode 100755 index 000000000..e8eda2cf5 --- /dev/null +++ b/forestry_resources/config/forestry/colour.properties @@ -0,0 +1,46 @@ +# Add a file of this format in your texture packs zip as +# /config/forestry/colour.properties to configure font colours. +# A file at that location inside the zip of the active texture pack +# will take precedence over the default. +# +# Hex format without leading 0x + +gui.title=404040 +gui.screen=ffffff +gui.table.header=ababab +gui.table.row=ababab +gui.book=000000 + +gui.beealyzer.binomial=14d50b +gui.beealyzer.recessive=3687ec +gui.beealyzer.dominant=ec3661 + +gui.mail.lettertext=cfa738 +gui.mail.text=6689dc + +ledger.error.background=ff3535 +ledger.error.header=e1c92f +ledger.error.text=000000 + +ledger.hint.background=ea38ff +ledger.hint.header=e1c92f +ledger.hint.text=000000 + +ledger.owner.header=e1c92f +ledger.owner.subheader=aaafb8 +ledger.owner.text=000000 + +ledger.climate.background=35a4ff +ledger.climate.header=e1c92f +ledger.climate.subheader=aaafb8 +ledger.climate.text=000000 + +ledger.power.background=d46c1f +ledger.power.header=e1c92f +ledger.power.subheader=aaafb8 +ledger.power.text=000000 + +ledger.farm.background=2ca22c +ledger.farm.header=e1c92f +ledger.farm.subheader=aaafb8 +ledger.farm.text=000000 diff --git a/forestry_resources/config/forestry/gamemodes/HARD.conf b/forestry_resources/config/forestry/gamemodes/HARD.conf new file mode 100755 index 000000000..b3bf54171 --- /dev/null +++ b/forestry_resources/config/forestry/gamemodes/HARD.conf @@ -0,0 +1,95 @@ +# Forestry +# @VERSION@ (@BUILD_NUMBER@) +# +# Config files: +# base.conf - Contains Forge configuration for block and item ids +# common.conf - Contains all options common to Forestry +# apiculture.conf - Contains all options for bee breeding +# backpacks.conf - Contains custom configurations for backpacks +# pipes.conf - Configures item id for the apiarist's pipe +# gamemodes/ - Configures available gamemodes + +##################### +# ENERGY +##################### +# modifies the energy required to activate machines, as well as the max amount of energy stored and accepted. +energy.demand.modifier=4.0 +# set to false to disable the clockwork engine. +energy.engine.clockwork=true + + +##################### +# FUEL +##################### +# modifies the energy provided by ethanol in a Bio Generator. +fuel.ethanol.generator=0.5 +# modifies the energy provided by ethanol in Buildcraft Combustion Engines. +fuel.ethanol.combustion=0.5 +# modifies the energy provided by Biomass in a Bio Generator. +fuel.biomass.generator=0.5 +# modifies the energy provided by Biomass in Biogas Engines. +fuel.biomass.biogas=0.5 + + +##################### +# FARMS +##################### +# modifies the time fertilizer lasts in a farm. +farms.fertilizer.value=500 + + +##################### +# FERMENTER +##################### +# modifies the amount of cycles a fertilizer can keep a fermenter going. +fermenter.cycles.fertilizer=100 +# modifies the amount of cycles compost can keep a fermenter going. +fermenter.cycles.compost=150 +# modifies the amount of biomass per cycle a fermenter will produce using fertilizer. +fermenter.value.fertilizer=56 +# modifies the amount of biomass per cycle a fermenter will produce using compost. +fermenter.value.compost=48 +# modifies the amount of biomass a sapling will yield in a fermenter. +fermenter.yield.sapling=50 +# modifies the amount of biomass a piece of cactus will yield in a fermenter. +fermenter.yield.cactus=10 +# modifies the amount of biomass a piece of wheat will yield in a fermenter. +fermenter.yield.wheat=10 +# modifies the amount of biomass a mushroom will yield in a fermenter. +fermenter.yield.mushroom=10 +# modifies the amount of biomass a piece of sugar cane will yield in a fermenter. +fermenter.yield.cane=10 + + +##################### +# RECIPE +##################### +# amount of fertilizer yielded by the recipe using apatite. +recipe.output.fertilizer.apatite=5 +# amount of fertilizer yielded by the recipe using ash. +recipe.output.fertilizer.ash=0 +# amount of bog earth yielded by the recipe using buckets. +recipe.output.bogearth.bucket=4 +# amount of bog earth yielded by the recipes using cans, cells or capsules. +recipe.output.bogearth.can=5 +# amount yielded by the recipe for tin cans. +recipe.output.can=8 +# amount yielded by the recipe for wax capsules. +recipe.output.capsule=2 +# amount yielded by the recipe for refractory capsules. +recipe.output.refractory=2 +# amount of compost yielded by the recipe using wheat. +recipe.output.compost.wheat=1 +# amount of compost yielded by the recipe using ash. +recipe.output.compost.ash=1 +# amount of humus yielded by the recipe using fertilizer. +recipe.output.humus.fertilizer=8 +# amount of humus yielded by the recipe using compost. +recipe.output.humus.compost=8 + + +##################### +# SQUEEZER +##################### +# modifies the amount of seed oil squeezed from a single seed. +squeezer.liquid.seed=3 diff --git a/forestry_resources/config/forestry/gamemodes/NORMAL.conf b/forestry_resources/config/forestry/gamemodes/NORMAL.conf new file mode 100755 index 000000000..b1a5f8f78 --- /dev/null +++ b/forestry_resources/config/forestry/gamemodes/NORMAL.conf @@ -0,0 +1,96 @@ +# Forestry +# @VERSION@ (@BUILD_NUMBER@) +# +# Config files: +# base.conf - Contains Forge configuration for block and item ids +# common.conf - Contains all options common to Forestry +# apiculture.conf - Contains all options for bee breeding +# backpacks.conf - Contains custom configurations for backpacks +# pipes.conf - Configures item id for the apiarist's pipe +# gamemodes/ - Configures available gamemodes + +##################### +# ENERGY +##################### +# modifies the energy required to activate machines, as well as the max amount of energy stored and accepted. +energy.demand.modifier=1.5 +# set to false to disable the clockwork engine. +energy.engine.clockwork=true + + +##################### +# FUEL +##################### +# modifies the energy provided by ethanol in a Bio Generator. +fuel.ethanol.generator=0.75 +# modifies the energy provided by ethanol in Buildcraft Combustion Engines. +fuel.ethanol.combustion=0.75 +# modifies the energy provided by Biomass in a Bio Generator. +fuel.biomass.generator=0.75 +# modifies the energy provided by Biomass in Biogas Engines. +fuel.biomass.biogas=0.75 + + +##################### +# FARMS +##################### +# modifies the time fertilizer lasts in a farm. +farms.fertilizer.value=1000 + + +##################### +# FERMENTER +##################### +# modifies the amount of cycles a fertilizer can keep a fermenter going. +fermenter.cycles.fertilizer=150 +# modifies the amount of cycles compost can keep a fermenter going. +fermenter.cycles.compost=200 +# modifies the amount of biomass per cycle a fermenter will produce using fertilizer. +fermenter.value.fertilizer=56 +# modifies the amount of biomass per cycle a fermenter will produce using compost. +fermenter.value.compost=48 +# modifies the amount of biomass a sapling will yield in a fermenter. +fermenter.yield.sapling=100 +# modifies the amount of biomass a piece of cactus will yield in a fermenter. +fermenter.yield.cactus=25 +# modifies the amount of biomass a piece of wheat will yield in a fermenter. +fermenter.yield.wheat=25 +# modifies the amount of biomass a mushroom will yield in a fermenter. +fermenter.yield.mushroom=25 +# modifies the amount of biomass a piece of sugar cane will yield in a fermenter. +fermenter.yield.cane=25 + + +##################### +# RECIPE +##################### +# amount of fertilizer yielded by the recipe using apatite. +recipe.output.fertilizer.apatite=6 +# amount of fertilizer yielded by the recipe using ash. +recipe.output.fertilizer.ash=10 +# amount of bog earth yielded by the recipe using buckets. +recipe.output.bogearth.bucket=4 +# amount of bog earth yielded by the recipes using cans, cells or capsules. +recipe.output.bogearth.can=6 +# amount yielded by the recipe for tin cans. +recipe.output.can=10 +# amount yielded by the recipe for wax capsules. +recipe.output.capsule=3 +# amount yielded by the recipe for refractory capsules. +recipe.output.refractory=3 +# amount of compost yielded by the recipe using wheat. +recipe.output.compost.wheat=2 +# amount of compost yielded by the recipe using ash. +recipe.output.compost.ash=1 +# amount of humus yielded by the recipe using fertilizer. +recipe.output.humus.fertilizer=8 +# amount of humus yielded by the recipe using compost. +recipe.output.humus.compost=8 + + +##################### +# SQUEEZER +##################### +# modifies the amount of seed oil squeezed from a single seed. +squeezer.liquid.seed=5 + diff --git a/forestry_resources/config/forestry/gamemodes/OP.conf b/forestry_resources/config/forestry/gamemodes/OP.conf new file mode 100755 index 000000000..4e3261c68 --- /dev/null +++ b/forestry_resources/config/forestry/gamemodes/OP.conf @@ -0,0 +1,99 @@ +# Forestry +# @VERSION@ (@BUILD_NUMBER@) +# +# Config files: +# base.conf - Contains Forge configuration for block and item ids +# common.conf - Contains all options common to Forestry +# apiculture.conf - Contains all options for bee breeding +# backpacks.conf - Contains custom configurations for backpacks +# pipes.conf - Configures item id for the apiarist's pipe +# gamemodes/ - Configures available gamemodes + +##################### +# ENERGY +##################### +# modifies the energy required to activate machines, as well as the max amount of energy stored and accepted. +energy.demand.modifier=1.0 +# set to false to disable the clockwork engine. +energy.engine.clockwork=true + + +##################### +# FUEL +##################### +# modifies the energy provided by ethanol in a Bio Generator. +fuel.ethanol.generator=4.0 +# modifies the energy provided by ethanol in Buildcraft Combustion Engines. +fuel.ethanol.combustion=4.0 +# modifies the energy provided by Biomass in a Bio Generator. +fuel.biomass.generator=4.0 +# modifies the energy provided by Biomass in Biogas Engines. +fuel.biomass.biogas=4.0 + + +##################### +# FARMS +##################### +# modifies the time fertilizer lasts in a farm. +farms.fertilizer.value=-1 + + +##################### +# FERMENTER +##################### +# modifies the amount of cycles fertilizer can keep a fermenter going. +fermenter.cycles.fertilizer=800 +# modifies the amount of cycles compost can keep a fermenter going. +fermenter.cycles.compost=1000 +# modifies the amount of biomass per cycle a fermenter will produce using fertilizer. +fermenter.value.fertilizer=224 +# modifies the amount of biomass per cycle a fermenter will produce using compost. +fermenter.value.compost=192 +# modifies the base amount of biomass a sapling will yield in a fermenter, affected by sappiness trait. (max: 2000) +fermenter.yield.sapling=2000 +# modifies the amount of biomass a piece of cactus will yield in a fermenter. (max: 400) +fermenter.yield.cactus=400 +# modifies the amount of biomass a piece of wheat will yield in a fermenter. (max: 400) +fermenter.yield.wheat=400 +# modifies the amount of biomass a piece of sugar cane will yield in a fermenter. (max: 400) +fermenter.yield.cane=400 +# modifies the amount of biomass a mushroom will yield in a fermenter. (max: 400) +fermenter.yield.mushroom=400 + + +##################### +# RECIPE +##################### +# amount of fertilizer yielded by the recipe using apatite. +recipe.output.fertilizer.apatite=16 +# amount of fertilizer yielded by the recipe using ash. +recipe.output.fertilizer.ash=32 +# amount of compost yielded by the recipe using wheat. +recipe.output.compost.wheat=8 +# amount of compost yielded by the recipe using ash. +recipe.output.compost.ash=2 +# amount of humus yielded by the recipe using fertilizer. +recipe.output.humus.fertilizer=8 +# amount of humus yielded by the recipe using compost. +recipe.output.humus.compost=8 +# amount of bog earth yielded by the recipe using buckets. +recipe.output.bogearth.bucket=6 +# amount of bog earth yielded by the recipes using cans, cells or capsules. +recipe.output.bogearth.can=8 +# amount yielded by the recipe for tin cans. +recipe.output.can=24 +# amount yielded by the recipe for wax capsules. +recipe.output.capsule=8 +# amount yielded by the recipe for refractory capsules. +recipe.output.refractory=8 + + +##################### +# SQUEEZER +##################### +# modifies the amount of seed oil squeezed from a single seed. other sources are based off this. (max: 80) +squeezer.liquid.seed=80 +# modifies the amount of juice squeezed from a single apple. other sources are based off this. (max: 1600) +squeezer.liquid.apple=1600 +# modifies the chance of mulch per squeezed apple. (max: 160) +squeezer.mulch.apple=160 diff --git a/forestry_resources/config/forestry/hints.properties b/forestry_resources/config/forestry/hints.properties new file mode 100755 index 000000000..6ac981417 --- /dev/null +++ b/forestry_resources/config/forestry/hints.properties @@ -0,0 +1,21 @@ +alveary=accesscontrol;accessrules;accesspipe; +analyzer=nopowerrequired;accesscontrol;accessrules;accesspipe;pipette;flowerjungle;flowernether;apiaristsuit;honeyfood +apiarist.chest= +apiary=accesscontrol;accessrules;accesspipe;beebiomes;beebreeding;beejubilance;beeflowers;nopowerrequired;flowerjungle;flowernether;apiaristsuit;honeyfood +beealyzer= +bottler=powerrequired;accesscontrol;accessrules;accesspipe;pipette +carpenter=powerrequired;accesscontrol;accessrules;accesspipe;pipette;crating +centrifuge=powerrequired;accesscontrol;accessrules;accesspipe +engine.bronze=accesscontrol;accessrules;accesspipe;energyunit;energybuffer;pipette;enginebronzefuels;enginebronzeheatloss;enginebronzeoutput;enginebronzewaste +engine.copper=accesscontrol;accessrules;accesspipe;energyunit;energybuffer;forcedcooldown;cooldownloss;enginecopperfuels;usesofash;enginecopperwaste;manualpeat;peatharvest +engine.tin=accesscontrol;accessrules;accesspipe;energyunit;energybuffer;forcedcooldown;cooldownloss;enginetinbatteries;enginetinchoke +farm=accesscontrol;accessrules;accesspipe;farmland;gearbox;valve;fertilizer;hatch;circuitboard;manualfarms;farmgui +fermenter=powerrequired;accesscontrol;accessrules;accesspipe;pipette;shortmead +generator=accesscontrol;accessrules;accesspipe;energyunit;pipette;generatorfuels +habitatlocator= +letter=postage +mailbox=nopowerrequired;accesscontrol;accessrules;accesspipe;postage +moistener=nopowerrequired;accesscontrol;accessrules;accesspipe;pipette;moistenerproducts +raintank=powerraintank;accesscontrol;accessrules;accesspipe +squeezer=powerrequired;accesscontrol;accessrules;accesspipe;pipette +still=powerrequired;accesscontrol;accessrules;accesspipe;pipette \ No newline at end of file diff --git a/forestry_resources/lang/forestry/apiculture/en_US.properties b/forestry_resources/lang/forestry/apiculture/en_US.properties new file mode 100755 index 000000000..624a0f8ff --- /dev/null +++ b/forestry_resources/lang/forestry/apiculture/en_US.properties @@ -0,0 +1,163 @@ + +apiculture.effect.aggressive=Aggress. +apiculture.effect.beatific=Beatific +apiculture.effect.creeper=Creeper +apiculture.effect.exploration=Explorer +apiculture.effect.glacial=Freezing +apiculture.effect.heroic=Heroic +apiculture.effect.ignition=Flammable +apiculture.effect.misasmic=Poison +apiculture.effect.misanthrope=Ends +apiculture.effect.radioactive=Radioact. +apiculture.effect.drunkard=Drunkard +apiculture.effect.snowing=Snow +apiculture.effect.resurrection=Resurrection +apiculture.effect.reanimation=Reanimation +apiculture.effect.repulsion=Repulsion +bees.hybrid.adj.add= +bees.hyphen.adj.add= +bees.drone=Drone +bees.drone.adj.add= +bees.larvae=Larvae +bees.larvae.adj.add= +bees.princess=Princess +bees.princess.adj.add= +bees.queen=Queen +bees.queen.adj.add= +bees.stock.pristine=Pristine Stock +bees.stock.ignoble=Ignoble Stock +death.bee.end=%1$s was ended by an unfriendly sting. +death.bee.end.player=%1$s was ended by an unfriendly sting while fighting %2$s. +death.bee.radioactive=%1$s walked into Chernobyl without his helmet on. +death.bee.radioactive.player=%1$s walked into Chernobyl without his helmet on. %2$s watched and cackled. +death.bee.aggressive=%1$s encountered a swarm of bees. That had to sting. +death.bee.aggressive.player=%1$s encountered a swarm of bees. %2$s stole his apiarist's suit. +genus.bees.common=Common +genus.bees.noble=Noble +genus.bees.industrious=Industrious +genus.bees.heroic=Heroic +genus.bees.infernal=Infernal +genus.bees.austere=Austere +genus.bees.end=End +genus.bees.vengeful=Vengeful +genus.bees.tropical=Tropical +genus.bees.frozen=Frozen +genus.bees.reddened=Reddened +genus.bees.festive=Festive +genus.bees.agrarian=Agrarian +genus.bees.boggy=Boggy +genus.bees.monastic=Monastic +bees.species.forest=Forest +bees.species.meadows=Meadows +bees.species.common=Common +bees.species.cultivated=Cultivated +bees.species.noble=Noble +bees.species.majestic=Majestic +bees.species.imperial=Imperial +bees.species.diligent=Diligent +bees.species.unweary=Unweary +bees.species.industrious=Industrious +bees.species.steadfast=Steadfast +bees.species.valiant=Valiant +bees.species.heroic=Heroic +bees.species.sinister=Sinister +bees.species.fiendish=Fiendish +bees.species.demonic=Demonic +bees.species.modest=Modest +bees.species.frugal=Frugal +bees.species.austere=Austere +bees.species.tropical=Tropical +bees.species.exotic=Exotic +bees.species.edenic=Edenic +bees.species.ender=Ender +bees.species.wintry=Wintry +bees.species.icy=Icy +bees.species.glacial=Glacial +bees.species.vindictive=Vindictive +bees.species.vengeful=Vengeful +bees.species.avenging=Avenging +bees.species.darkened=Darkened +bees.species.reddened=Reddened +bees.species.omega=Omega +bees.species.leporine=Leporine +bees.species.tricky=Tricky +bees.species.rural=Rural +bees.species.marshy=Marshy +bees.species.merry=Merry +bees.species.tipsy=Tipsy +bees.species.monastic=Monastic +bees.species.secluded=Secluded +bees.species.hermitic=Hermitic +bees.species.spectral=Spectral +bees.species.phantasmal=Phantasmal +beemode.easy.desc=Simplifies beebreeding by drastically increasing mutation rate and removing the chance for genetic fatigue. +beemode.normal.desc=Recommended mode for the normal player. +beemode.hard.desc=Reducing mutation rate slightly while increasing lifespan of individual queens by 50 %. +beemode.hardcore.desc=Halves mutation rate, increases lifespan of individual queens by 500 % and reduces fertility by 20 %. +beemode.insane.desc=Cuts mutation rate to 20 %, increases lifespan tenfold and reduces fertility by 40 %. +description.speciesForest=One of the most common pests in forests; Mostly docile.|Beekeeping 101 +description.speciesMeadows=Infests mostly plains in temperate climates; Mostly docile.|Beekeeping 101 +description.speciesCommon=Considered the beginner apiarist's badge of participation.|Beekeeping 101 +description.speciesCultivated=Fast working bee; Thinks anything but opera is beneath it.|Beekeeping 101 +description.speciesNoble="There is no more noble occupation in the world than to breed another bee."|Binnie, Apiarist +description.speciesMajestic="Off with their heads!"|Queen of Hearts +description.speciesImperial=Highly sought after bee; Specialises in the production of precious royal jelly.|Beekeeping 101 +description.speciesDiligent=Mostly noted as a stepping stone for the industrious line of bees.|Beekeeping 101 +description.speciesUnweary=Unweary. Then they die.|Beekeeping 101 +description.speciesIndustrious=Highly sought after bee; Specialises in the production of exquisite pollen.|Beekeeping 101 +description.speciesSteadfast=Considered extinct until some were found by adventurers in a deep dungeon.|Apiarist's Grimoire +description.speciesValiant=A rare subspecies rarely seen cohabiting in mundane hives.|Apiarist's Grimoire +description.speciesHeroic=Elaborate legends have surrounded this species. Will defend its hive to its death against any hostiles.|Apiarist's Grimoire +description.speciesSinister=Not many bee species are able to survive in the nether. And even those are severly affected by their hellish environment.|Beekeeping 101 +description.speciesFiendish=Experienced nether apiarist's have been reporting severe attacks by their bees. Caution is advised.|Beekeeping 101 +description.speciesDemonic=Born in the fires of the nether and being a descendant of generations of nether bees has caused this species to turn into a true demon.|Beekeeping 101 +description.speciesModest=Hot and arid climates have forced this species to adapt to a degree which will not allow it to survive in significantly friendlier climates.|Beekeeping 101 +description.speciesFrugal=Generations of bees baked in the sun to produce this species.|Beekeeping 101 +description.speciesAustere=Dangerous and volatile; Beekeepers are advised to stay in full suit whenever near.|Beekeeping 101 +description.speciesTropical="My travels along the jungle river allowed me to catch many of these poisonous specimen. Unfortunately I had lost my only austere branch to crocodiles a while back."|Beekeeping 101 +description.speciesExotic="The fever shook me and my apiarist's suit was drenched with cold sweat, but with trembling hands I finally managed to pull one of these from my apiary."|Beekeeping 101 +description.speciesEdenic="I furiously scribbled in my notebook, drawing sketches of the images I felt seeping into my brain while I was watching the insects perform their strange little dance."|Beekeeping 101 +description.speciesWintry=Common, but winter-hardened bee tribe; Cultivation in warmer climates is a challenge.|Beekeeping 101 +description.speciesIcy=Temperatures inside hives inhabited by this species will drop until ice shards form.|Beekeeping 101 +description.speciesGlacial="Winter is coming!"|E. Stark, beekeeper +description.speciesVindictive="It ate my face! It ate my face!"|K.M. +description.speciesVengeful="Veni, vidi, vici!"|Apinus Julius Caesar +description.speciesAvenging="The walls of my house began to crumble and I heard the roof creaking over my head, but I cared not! I felt the stabs of a thousand little insects on my glove as I grabbed the new queen."|Anonymous +description.speciesDarkened=Attracted by the power of alchemically bound matter, this species was a powerful source of energy.|Beekeeper's Lexicon +description.speciesReddened=Requiring massive amounts of alchemically bound matter, these little fellows could flood a world in energy.|Beekeeper's Lexicon +description.speciesOmega="I am Alpha and Omega, the beginning and the end, the first and the last."|Pahimar, beekeeper +description.speciesLeporine="I swear! It was tiny, had wings and I definitely saw fluffy little rabbit ears! ... No! I am not drunk!"|"Sir" Sengir, madman +description.speciesMerry="Hohoho!"|Merry bee +description.speciesTipsy="Dance my pretties! Dance!"|Tipsy Witch of the East +description.speciesTricky="Trick or Tricky Treat!"|Tricky Bee +description.speciesRural="Rain in May promises much hay."|M. Ages, Rural Beekeeper +description.speciesMarshy="Seriously? Mushrooms? Get out of here!"|Beekeeping 101 +description.speciesMonastic="I remained austere and said to him: 'Not only a princess, but also a whole pile of emeralds for a measly drone? That's extortion!'|Beekeeping 101 +description.speciesSecluded="Crossbreeding with the desert kind was a mistake. My bees withdrew more and more from the outside world."|Beekeeping 101 +description.speciesHermitic="My dear colleague! I noticed the bees you sent me refuse to wash and are growing full beards. Care to explain?"|Binnie, Apiarist +description.speciesEnded="I found one of these seemingly hermitical insects in a villager's apiary. It was torpid, obviously ripped from its world and longing for a fragment from it."|Beekeeping 101 +description.speciesSpectral="I was unsure whether it was alive as it lay there in the palm of my hand, glimmering and pulsating, oozing a coldness I never felt before. Then I heard the pile of bones behind me rattle..."|Beekeeping 101 +description.speciesPhantasmal="Whatever you do, do not, I repeat, DO NOT drop the dragon e..."|"Sir" Sengir, Last Words +tile.alveary.0=Alveary +tile.alveary.2=Swarmer +tile.alveary.3=Alveary Fan +tile.alveary.4=Alveary Heater +tile.alveary.5=Alveary Hygroregulator +tile.alveary.6=Alveary Stabiliser +tile.alveary.7=Alveary Sieve +tile.beehives.1=Forest Hive +tile.beehives.2=Meadows Hive +tile.beehives.3=Modest Hive +tile.beehives.4=Tropical Hive +tile.beehives.5=Ender Hive +tile.beehives.6=Wintry Hive +tile.beehives.7=Marshy Hive +tile.candle.stump=Unlit Candle +tile.candle.dyed.stump=Unlit Dyed Candle +tile.candle.lit=Lit Candle +tile.candle.dyed.lit=Lit Dyed Candle +tile.stump.0=Candle Stump +tile.for.apiculture.0=Apiary +tile.for.apiculture.1=Apiarist's Chest +tile.for.apiculture.2=Bee House + diff --git a/forestry_resources/lang/forestry/arboriculture/en_US.properties b/forestry_resources/lang/forestry/arboriculture/en_US.properties new file mode 100755 index 000000000..182813f18 --- /dev/null +++ b/forestry_resources/lang/forestry/arboriculture/en_US.properties @@ -0,0 +1,69 @@ +gui.maturity=Matures +gui.treealyzer=Treealyzer +gui.treealyzer.help=Supply sapling and provide honey or honeydew as catalyst. +gui.treealyzer.overview=Analytics available +gui.saplings=Saplings +gui.yield=Yield +gui.sappiness=Sappiness +gui.height=Height +gui.fruits=Fruits +gui.supports=Supports +gui.family=Family +gui.girth=Girth +gui.native=Soil +gui.tolerated=Tolerates +gui.growth=Growth +description.treeOak=Common tree species whose apple-bearing properties are the subject of much song and dance.|Codex Lignum +description.treeBirch=Widespread birch tree, which on average is of smaller height.|Codex Lignum +description.treeLime=Tall, deciduous tree. It has been reclassified recently as being in the Malvaceae family.|Codex Lignum +description.treeWalnut=Tall, deciduous tree with large trunk. Naturally occuring walnut trees carry fruits which require some time to ripe.|Codex Lignum +description.treeChestnut=Tall, deciduous tree with large trunk. Naturally occuring chestnut trees carry fruits which require some time to ripe.|Codex Lignum +description.treeSipiri=Tall, evergreen trees with valuable timber. Wood and bark are pleasantly scented. Will only thrive in tropical climes.|Codex Lignum +description.treeWillow=Large, deciduous tree. White willows are fast-growing. Have only been observed to occur in damp climates.|Codex Lignum +description.treeCherry=Small tree. In its natural form it will bear cherries which will need to undergo a ripening period.|Codex Lignum +family.pomes=Pomes +family.prunes=Prunes +family.nuts=Nuts +family.jungle=Jungle +fruits.apple=Apple +fruits.cherry=Cherry +fruits.chestnut=Chestnut +fruits.walnut=Walnut +fruits.cocoa=Cocoa +fruits.none=None +fruits.plum=Plum +fruits.lemon=Lemon +fruits.dates=Dates +fruits.papaya=Papaya +item.grafter=Grafter +item.grafterProven=Proven Grafter +tile.log=Wood +tile.planks=Wood Planks +tile.slab=Wood Slab +tile.fences=Fence +tile.for.stairs=Stairs +wood.0=Larch +wood.1=Teak +wood.2=Acacia +wood.3=Lime +wood.4=Chestnut +wood.5=Wenge +wood.6=Baobab +wood.7=Sequoia +wood.8=Kapok +wood.9=Ebony +wood.10=Mahogany +wood.11=Balsa +wood.12=Willow +wood.13=Walnut +wood.14=Greenheart +wood.15=Cherry +wood.16=Mahoe +wood.17=Poplar +wood.18=Palm +wood.19=Papaya +wood.20=Pine +wood.21=Plum +wood.22=Maple +wood.23=Citrus +tile.for.arboriculture.0=Arborist's Chest \ No newline at end of file diff --git a/forestry_resources/lang/forestry/core/en_US.properties b/forestry_resources/lang/forestry/core/en_US.properties new file mode 100755 index 000000000..37fad6af1 --- /dev/null +++ b/forestry_resources/lang/forestry/core/en_US.properties @@ -0,0 +1,540 @@ +# Master language file + +yes=Yes +no=No +beverage.effect.alcoholic=Alcoholic +beverage.effect.antidote=Antidote +chat.accesslocked=is the owner of this machine and has locked access. +chat.memorizednote=You memorize the note and dispose of the crumpled scrap of paper. +chat.cannotmemorizeagain=You already memorized this information. +circuit.dampener.1=Fire Dampener +circuit.electric.choke.1=Electric Choke +circuit.electric.efficiency.1=Electric Efficiency +circuit.electric.boost.1=Electric Boost I +circuit.electric.boost.2=Electric Boost II +circuit.usage.engineTin=In Electrical Engines +death.engine.clockwork=%1$s was stabbed by a loose spring. +death.engine.clockwork.player=%1$s was stabbed by a loose spring. %2$s was the negligent watchmaker. +errors.unknown.desc=Unknown error +errors.unknown.help=Congratulations, you found a glitch. +errors.ok.desc=No error +errors.ok.help=Everything is fine and dandy. +errors.invalidBiome.desc=Hostile environment +errors.invalidBiome.help=Machine or inhabitants cannot work in this biome. +errors.isRaining.desc=Rain +errors.isRaining.help=Operation is only possible when it is not raining. +errors.notRaining.desc=No rain +errors.notRaining.help=Operation is only possible when it is raining. +errors.noFuel.desc=No fuel +errors.noFuel.help=Replenish this machine's fuel supplies. +errors.noHeat.desc=Not warmed up +errors.noHeat.help=Refill the heating tank. +errors.noDisposal.desc=Waste not disposable +errors.noDisposal.help=Insufficient space to dispose of waste products. +errors.noResource.desc=Missing resources +errors.noResource.help=More resources need to be supplied for operation. +errors.notGloomy.desc=Not dark enough +errors.notGloomy.help=A lower light level is required for operation. +errors.notLucid.desc=Not bright enough +errors.notLucid.help=A higher light level is required for operation +errors.notDay.desc=Not daytime +errors.notDay.help=Operation is only possible during the day. +errors.notNight.desc=Not nighttime +errors.notNight.help=Operation is only possible during the night. +errors.noFlower.desc=No flowers +errors.noFlower.help=Hive members are not finding the right flowers. +errors.noQueen.desc=No queen +errors.noQueen.help=Supply this hive with a queen or a princess and a drone. +errors.noDrone.desc=No drone +errors.noDrone.help=Mating requires a drone present. +errors.noSky.desc=Sky obstructed +errors.noSky.help=Clear the area above the machine. +errors.noSpace.desc=No inventory space +errors.noSpace.help=Empty this machine's inventory. +errors.noRecipe.desc=No recipe +errors.noRecipe.help=No matching recipe was found for the supplied resources. +errors.noEnergyNet.desc=No electricity +errors.noEnergyNet.help=Your world is barren of any electricity. (Install IndustrialCraft\u00b2.) +errors.noSpecimen.desc=Nothing to analyze +errors.noSpecimen.help=Supply specimen to analyze. +errors.forcedCooldown.desc=Forced Cooldown +errors.forcedCooldown.help=Engine has overheated and is forced into cooldown. +errors.noHoney.desc=Honey required +errors.noHoney.help=This gadget requires honey drops or honeydew for operation. +errors.notPostpaid.desc=Stamps Needed +errors.notPostpaid.help=Apply more stamps to pay the postal service. +errors.noRecipient.desc=No Recipient +errors.noRecipient.help=You need to address your letter to a recipient to send it. +errors.notAlphaNumeric.desc=Not Alphanumeric +errors.notAlphaNumeric.help=Given string must consist of letters and numbers only. +errors.notUnique.desc=Not Unique +errors.notUnique.help=Given string must be unique in this world. Choose a different one. +errors.noStamps.desc=No Stamps +errors.noStamps.help=A trade station requires stamps to pay postage. This one has run out of them. +errors.wrongStacksize.desc=Too Many Items +errors.wrongStacksize.help=Only single items can be used here. +errors.noCircuitBoard.desc=Board Missing +errors.noCircuitBoard.help=Insert a circuit board to solder the selected tubes onto it. +errors.circuitMismatch.desc=Layout Mismatch +errors.circuitMismatch.help=Amount of tubes does not match size of circuit board. +flowers.cacti=Cacti +flowers.end=End +flowers.jungle=Jungle +flowers.mushroom=Mushroom +flowers.nether=Nether +flowers.vanilla=Flowers +flowers.wheat=Wheat +flowers.gourd=Gourds +fluid.bioethanol=Ethanol +fluid.biomass=Biomass +fluid.milk=Milk +fluid.seedoil=Seed Oil +fluid.juice=Fruit Juice +fluid.honey=Honey +fluid.mead=Short Mead +fluid.glass=Liquid Glass +fluid.ice=Crushed Ice +gui.climate=Climate +gui.empty=Empty +gui.temptol=Temp.Tol +gui.temperature=Temperature +gui.humidity=Humidity +gui.humidtol=Humid.Tol. +gui.unknown=Unknown genome +gui.hybrid=Hybrid +gui.worker=Worker +gui.life=Life +gui.beealyzer=Beealyzer +gui.beealyzer.help=Supply bee and provide honey or honeydew as a pacifier. +gui.beealyzer.overview=Analytics available +gui.beealyzer.produce=Possible Produce +gui.beealyzer.specialty=Possible Specialty +gui.beealyzer.mutations=Possible Mutations +gui.beealyzer.behaviour=Behaviour +gui.beealyzer.natural=Natural Origin +gui.beealyzer.artificial=Artificial Origin +gui.beealyzer.generations=Generations in Captivity +gui.alyzer.authority=Authority +gui.alyzer.classification=Classification +gui.alyzer.nodescription=Encyclopedia Minecraftia could not provide an entry for this specimen. +gui.alyzer.extinct=Extinct +gui.general=General +gui.environment=Environment +gui.produce=Produce +gui.evolution=Evolution +gui.active=Active +gui.inactive=Inactive +gui.species=Species +gui.lifespan=Lifespan +gui.speed=Speed +gui.size=Size +gui.metabolism=Metabolism +gui.pollination=Pollin. +gui.flowers=Flowers +gui.fertility=Fertility +gui.area=Area +gui.effect=Effect +gui.nocturnal=Nocturnal +gui.diurnal=Diurnal +gui.flyer=Flyer +gui.cave=Cave +gui.fireresist=Fireproof +gui.derelict=Derelict +gui.owner=Owner +gui.hellish=Hellish +gui.hot=Hot +gui.warm=Warm +gui.normal=Normal +gui.cold=Cold +gui.icy=Icy +gui.arid=Arid +gui.damp=Damp +gui.energy=Energy +gui.currentOutput=Current Output +gui.stored=Stored +gui.heat=Heat +gui.habitatlocator=Habitat Locator +gui.closetosearch=close to search +gui.didyouknow=Did you know +gui.maxspeed=Maximum +gui.fastest=Fastest +gui.faster=Faster +gui.fast=Fast +gui.normal=Normal +gui.slow=Slow +gui.slower=Slower +gui.slowest=Slowest +gui.longestlife=Longest +gui.longerlife=Longer +gui.longlife=Long +gui.elongatedlife=Elongated +gui.normallife=Normal +gui.shortenedlife=Shortened +gui.shortlife=Short +gui.shorterlife=Shorter +gui.shortestlife=Shortest +gui.speciescount=Species +gui.queens=Queens +gui.princesses=Princ. +gui.drones=Drones +gui.slots=Slots +gui.access=Access +gui.rule.shared=Shared +gui.rule.restricted=Restricted +gui.rule.private=Private +gui.page=Page +gui.maxenergy=Maximum Energy +gui.maxenergyreceive=Maximum Input +gui.noeffect=No effect +gui.mail.from=From +gui.mail.to=To +gui.blank=Blank +gui.mail.nametrader=Name your trade station +gui.mail.pleasesend=Please send +gui.mail.foreveryattached=for every attached +gui.mail.nothingtotrade=Trade station has nothing to trade. +gui.mail.notrader=No trade station of that name available. +gui.addressee.player=Player +gui.addressee.trader=Trader Station +gui.pipe.filter.closed=Closed +gui.pipe.filter.anything=Anything +gui.pipe.filter.item=Items +gui.pipe.filter.bee=Any Bees +gui.pipe.filter.drone=Drones +gui.pipe.filter.princess=Princesses +gui.pipe.filter.queen=Queen +gui.pipe.filter.pure_breed=Pure-Bred Bees +gui.pipe.filter.nocturnal=Nocturnal Bees +gui.pipe.filter.pure_nocturnal=Pure Nocturnal Bees +gui.pipe.filter.flyer=Strong Flyers +gui.pipe.filter.pure_flyer=Pure Flyers +gui.pipe.filter.cave=Cave-Dwellers +gui.pipe.filter.pure_cave=Pure Cave-Dwellers +gui.emptysocket=Empty Socket +gui.smallest=Smallest +gui.smaller=Smaller +gui.small=Small +gui.average=Average +gui.large=Large +gui.larger=Larger +gui.largest=Largest +gui.gigantic=Gigantic +gui.plains=Plains +gui.desert=Desert +gui.beach=Beach +gui.water=Water +gui.nether=Nether +gui.crop=Crop +gui.lowest=Lowest +gui.lower=Lower +gui.low=Low +gui.normal=Normal +gui.triple=Triple +gui.high=High +gui.higher=Higher +gui.highest=Highest +gui.fecundated=Mated +gui.tooltip.tmi=Hold shift for details +gui.worktable.clear=Click to clear Grid +gui.escritoire.probe=Examine Specimens +hints.beebiomes.tag=Choose your biome! +hints.beebiomes.desc=Bees only work in biomes that suit their species. Use your beealyzer and habitat locator to find out in which. +hints.beebreeding.tag=Breed your bees! +hints.beebreeding.desc=Crossbreeding drones and princesses of different species may net you offspring with a new species. +hints.beejubilance.tag=Make your bee happy! +hints.beejubilance.desc=Only jubilant bees will produce their specialty. Make sure to have them in their preferred climate. +hints.enginebronzefuels.tag=Use all the fuels! +hints.enginebronzefuels.desc=You can use a wide variety of fuels for your biogas engine: Biomass, seed oil, honey, milk and even water! +hints.enginebronzeheatloss.tag=Careful with water! +hints.enginebronzeheatloss.desc=Though you can use water in a biogas engine, it is terribly inefficient and will constantly consume lava. +hints.enginebronzeoutput.tag=Choose your fuel! +hints.enginebronzeoutput.desc=Different fuels will net you different energy outputs in a biogas engine. Outputs range from 1 MJ/t to 5 MJ/t. +hints.pipette.tag=Empty tanks with the pipette +hints.pipette.desc=If you are stuck with remaining liquid in a machine's tank, you can click the tank with a pipette to empty it. +hints.enginecopperfuels.tag=Use all the fuels! +hints.enginecopperfuels.desc=Peat-fired engines can use untreated peat, but they can also use bituminous peat to double their energy output. +hints.usesofash.tag=Use your ash! +hints.usesofash.desc=Ash can be used to create fertilizer and is required to refine bituminous peat. +hints.shortmead.tag=Get your energy drink! +hints.shortmead.desc=Your fermenter can not only create biomass, you can also use honeydew and liquid honey to make some short mead. +hints.generatorfuels.tag=Use all the fuels! +hints.generatorfuels.desc=Bio generators accept both biomass and biofuel. They are at their most efficient with biofuel. +hints.moistenerproducts.tag=Want some mossy cobble? +hints.moistenerproducts.desc=Given the correct ingredients, your moistener can also create mossy cobblestone or mossy stone bricks. +hints.enginetinbatteries.tag=Charge those batteries! +hints.enginetinbatteries.desc=You can use batteries to run your electrical engines without needing to wire them up. +hints.energyunit.tag=Say Minecraft Joule! +hints.energyunit.desc=An engine's energy output is measured in MJ/t, which stands for "Minecraft Joule per tick". Each second has 20 ticks. +hints.crating.tag=Crate your Surplus! +hints.crating.desc=Main task of carpenters is the compression of your surplus resources. Many bulk blocks and items can be packaged into crates. +hints.enginebronzewaste.tag=Fuel is conserved. +hints.enginebronzewaste.desc=Contrary to peat-fired engines disabled biogas engines will not waste the biomass currently in the system. +hints.enginecopperwaste.tag=Beware wasting energy! +hints.enginecopperwaste.desc=Disabled peat-fired engines continue to burn peat already removed from the stash without generating energy from it. +hints.energybuffer.tag=Buffering Energy! +hints.energybuffer.desc=Engines are capable of buffering a lesser amount of energy if it cannot be transmitted to the target. +hints.forcedcooldown.tag=Beware Overheating! +hints.forcedcooldown.desc=Engines can overheat if the energy they produce is not consumed. Reaching melting point will force them into cooldown. +hints.cooldownloss.tag=Cooldown means energy loss! +hints.cooldownloss.desc=Engines going into forced cooldown will also lose a significant chunk of their stored energy. +hints.beeflowers.tag=Bees need flowers +hints.beeflowers.desc=Any bee will need some type of flower in the vicinity. Some rather mundane flowers, others very exotic ones. +hints.nopowerrequired.tag=No power required +hints.nopowerrequired.desc=Machines of this type do not require any power to operate. +hints.accesscontrol.tag=Access Control +hints.accesscontrol.desc=A machine's owner can set it to three different types of access: Shared, restricted or private. +hints.accessrules.tag=Access rules +hints.accessrules.desc="Shared" access allows anyone to break the machine or interact with it. "Restricted" still allows interaction for anyone. +hints.accesspipe.tag=Restricted Pipe Access +hints.accesspipe.desc=A machine set to private will disallow any interaction with tubes or pipes. +hints.flowerjungle.tag=What's a jungle flower? +hints.flowerjungle.desc=Jungle flowers are ferns or vines. +hints.flowernether.tag=What's a nether flower? +hints.flowernether.desc=Netherwart are the nether flowers. +hints.apiaristsuit.tag=Bee Suits! +hints.apiaristsuit.desc=A full apiarist's suit will protect you from all negative bee effects. +hints.honeyfood.tag=Grab foodstuff! +hints.honeyfood.desc=Many different kinds of foods can be made from honey and other bee products. +hints.powerrequired.tag=Requires Energy! +hints.powerrequired.desc=This machine requires energy from an engine to function. Attach an engine and start it, to allow production. +hints.powerraintank.tag=Bottling Requires Energy! +hints.powerraintank.desc=Even an unpowered raintank will collect rain. However to bottle the water, energy from an engine is required. +hints.manualpeat.tag=No Bog Needed! +hints.manualpeat.desc=Peat can be farmed in automatic peat bogs, but when you start out, you might want to try harvesting a bit of peat by hand. +hints.peatharvest.tag=Harvest Peat! +hints.peatharvest.desc=Bog earth directly adjacent to water will mature to peat. Use a shovel to harvest it. +hints.enginetinchoke.tag=Regulate Output +hints.enginetinchoke.desc=Electrical engines can be outfitted with circuit boards to choke their power output to 1 MJ/t and also reduce their energy demand. +hints.postage.tag=Pay the Ferryman +hints.postage.desc=Sending letters costs stamps. To a base fee of 1n, every attachment adds another 1n of cost. +item.beverage.meadShort=Short Mead +item.beverage.meadCurative=Curative Mead +item.circuitboard.basic=Basic Circuit Board +item.circuitboard.enhanced=Enhanced Circuit Board +item.circuitboard.refined=Refined Circuit Board +item.circuitboard.intricate=Intricate Circuit Board +item.comb.honey=Honey Comb +item.comb.cocoa=Cocoa Comb +item.comb.simmering=Simmering Comb +item.comb.stringy=Stringy Comb +item.comb.frozen=Frozen Comb +item.comb.dripping=Dripping Comb +item.comb.silky=Silky Comb +item.comb.parched=Parched Comb +item.comb.mysterious=Mysterious Comb +item.comb.irradiated=Irradiated Comb +item.comb.powdery=Powdery Comb +item.comb.reddened=Reddened Comb +item.comb.darkened=Darkened Comb +item.comb.omega=Omega Comb +item.comb.wheaten=Wheaten Comb +item.comb.mossy=Mossy Comb +item.comb.mellow=Mellow Comb +item.crated.adj=Crated +item.crated.unknown=Crate with unknown content +item.dissipationCharge=Dissipation Charge +item.honeyDrop.charged=Charged Drop +item.honeyDrop.honey=Honey Drop +item.honeyDrop.omega=Omega Drop +item.pollen.normal=Pollen +item.pollen.crystalline=Crystalline Pollen +item.propolis.normal=Propolis +item.propolis.sticky=Sticky Propolis +item.propolis.pulsating=Pulsating Propolis +item.propolis.silky=Silky Propolis +item.thermionicTubes.ex-0=Copper Electron Tube +item.thermionicTubes.ex-1=Tin Electron Tube +item.thermionicTubes.ex-2=Bronze Electron Tube +item.thermionicTubes.ex-3=Iron Electron Tube +item.thermionicTubes.ex-4=Golden Electron Tube +item.thermionicTubes.ex-5=Diamantine Electron Tube +item.thermionicTubes.ex-6=Obsidian Electron Tube +item.thermionicTubes.ex-7=Blazing Electron Tube +item.thermionicTubes.ex-8=Rubberised Electron Tube +item.thermionicTubes.ex-9=Emerald Electron Tube +item.thermionicTubes.ex-10=Apatine Electron Tube +item.thermionicTubes.ex-11=Lapis Electron Tube +item.pulsatingDust=Pulsating Dust +item.pulsatingMesh=Pulsating Mesh +item.silkWisp=Silk Wisp +item.wovenSilk=Woven Silk +item.fertilizerBio=Compost +item.fertilizerCompound=Fertilizer +item.apatite=Apatite +item.ingotCopper=Copper Ingot +item.ingotTin=Tin Ingot +item.ingotBronze=Bronze Ingot +item.pipette=Pipette +item.wrench=Wrench +item.gearBronze=Bronze Gear +item.bucketBiomass=Biomass Bucket +item.sturdyMachine=Sturdy Casing +item.vialCatalyst=Catalyst +item.bucketBiofuel=Ethanol Bucket +item.peat=Peat +item.ash=Ash +item.gearCopper=Copper Gear +item.waterCan=Water Can +item.canEmpty=Can +item.biomassCan=Biomass Can +item.biofuelCan=Ethanol Can +item.gearTin=Tin Gear +item.hardenedMachine=Hardened Casing +item.iodineCapsule=Iodine Capsule +item.carton=Carton +item.crate=Crate +item.oakStick=Impregnated Stick +item.woodPulp=Wood Pulp +item.kitPickaxe=Pickaxe Kit +item.bronzePickaxe=Survivalist's Pickaxe +item.brokenBronzePickaxe=Broken Pickaxe +item.kitShovel=Shovel Kit +item.bronzeShovel=Survivalist's Shovel +item.brokenBronzeShovel=Broken Shovel +item.tent=Survivalist's Tent +item.mouldyWheat=Mouldy Wheat +item.decayingWheat=Decaying Wheat +item.mulch=Mulch +item.scoop=Scoop +item.beeswax=Beeswax +item.royalJelly=Royal Jelly +item.honeydew=Honeydew +item.waxCapsule=Wax Capsule +item.honeyedSlice=Honeyed Slice +item.ambrosia=Ambrosia +item.canOil=Oil Can +item.canFuel=Fuel Can +item.canLava=Lava Can +item.canSeedOil=Seed Oil Can +item.canHoney=Honey Can +item.canJuice=Juice Can +item.canIce=Ice Can +item.honeyPot=Honey Pot +item.waxCapsuleWater=Water Capsule +item.waxCapsuleBiomass=Biomass Capsule +item.waxCapsuleBiofuel=Ethanol Capsule +item.bituminousPeat=Bituminous Peat +item.waxCapsuleOil=Oil Capsule +item.waxCapsuleFuel=Fuel Capsule +item.waxCapsuleSeedOil=Seed Oil Capsule +item.waxCapsuleHoney=Honey Capsule +item.waxCapsuleJuice=Juice Capsule +item.waxCapsuleIce=Ice Capsule +item.phosphor=Phosphor +item.refractoryWax=Refractory Wax +item.refractoryEmpty=Refractory Capsule +item.refractoryLava=Lava Capsule +item.refractoryWater=Water Capsule +item.refractoryBiomass=Biomass Capsule +item.refractoryBiofuel=Ethanol Capsule +item.refractoryOil=Oil Capsule +item.refractoryFuel=Fuel Capsule +item.refractorySeedOil=Seed Oil Capsule +item.refractoryHoney=Honey Capsule +item.refractoryJuice=Juice Capsule +item.refractoryIce=Ice Capsule +item.beealyzer=Beealyzer +item.apiaristHelmet=Apiarist's Hat +item.apiaristChest=Apiarist's Shirt +item.apiaristLegs=Apiarist's Pants +item.apiaristBoots=Apiarist's Shoes +item.naturalistHelmet=Spectacles +item.biomeFinder=Habitat Locator +item.infuser=Infuser +item.imprinter=Imprinter +item.solderingIron=Soldering Iron +item.letters=Letter +item.stamps=Stamp +item.scentedPaneling=Scented Paneling +item.impregnatedCasing=Impregnated Casing +item.frameUntreated=Untreated Frame +item.frameImpregnated=Impregnated Frame +item.frameProven=Proven Frame +item.iceShard=Ice Shard +item.waxCast=Wax Cast +item.treealyzer=Treealyzer +item.fruit.cherry=Cherry +item.fruit.walnut=Walnut +item.fruit.chestnut=Chestnut +item.fruit.lemon=Lemon +item.fruit.plum=Plum +item.fruit.papaya=Papaya +item.fruit.dates=Date +itemGroup.forestry=Forestry +itemGroup.arboriculture=Arboriculture +itemGroup.apiculture=Apiculture +itemGroup.lepidopterology=Lepidopterology +layout.engine.tin=Electric Engine +storage.backpack.apiarist=Apiarist's Backpack +storage.backpack.adventurer=Adventurer's Backpack +storage.backpack.builder=Builder's Backpack +storage.backpack.digger=Digger's Backpack +storage.backpack.forester=Forester's Backpack +storage.backpack.hunter=Hunter's Backpack +storage.backpack.miner=Miner's Backpack +storage.backpack.t2adj=Woven +tile.for.engine.0=Electrical Engine +tile.for.engine.1=Peat-fired Engine +tile.for.engine.2=Biogas Engine +tile.for.engine.3=Bio Generator +tile.for.engine.4=Clockwork Engine +tile.for.factory.0=Bottler +tile.for.factory.1=Carpenter +tile.for.factory.2=Centrifuge +tile.for.factory.3=Fermenter +tile.for.factory.4=Moistener +tile.for.factory.5=Squeezer +tile.for.factory.6=Still +tile.for.factory.7=Rainmaker +tile.for.factory2.0=Thermionic Fabricator +tile.for.factory2.1=Raintank +tile.for.factory2.2=Worktable +tile.for.core.0=Analyzer +tile.for.core.1=Escritoire +tile.for.mail.0=Mailbox +tile.for.mail.1=Trade Station +tile.for.mail.2=Stamp Collector +tile.beehives.1=Forest Hive +tile.beehives.2=Meadows Hive +tile.beehives.3=Desert Hive +tile.beehives.4=Jungle Hive +tile.beehives.5=End Hive +tile.beehives.6=Snow Hive +tile.beehives.7=Swamp Hive +tile.resources.0=Apatite Ore +tile.resources.1=Copper Ore +tile.resources.2=Tin Ore +tile.soil.0=Humus +tile.soil.1=Bog Earth +tile.stained.0=White Stained Glass +tile.stained.1=Orange Stained Glass +tile.stained.2=Magenta Stained Glass +tile.stained.3=Light Blue Stained Glass +tile.stained.4=Yellow Stained Glass +tile.stained.5=Lime Stained Glass +tile.stained.6=Pink Stained Glass +tile.stained.7=Gray Stained Glass +tile.stained.8=Light Gray Stained Glass +tile.stained.9=Cyan Stained Glass +tile.stained.10=Purple Stained Glass +tile.stained.11=Blue Stained Glass +tile.stained.12=Brown Stained Glass +tile.stained.13=Green Stained Glass +tile.stained.14=Red Stained Glass +tile.stained.15=Black Stained Glass +trigger.hasMail=Has Mail +trigger.hasWork=Has Work +trigger.lowFuel=Fuel +trigger.lowGermlings=Germlings +trigger.lowResources=Resources +trigger.lowSoil=Soil +trigger.missingDrone=Missing Drone +trigger.missingQueen=Missing Queen or Princess +trigger.noFrames=No Frames +trigger.lowPaper=Paper +trigger.lowLiquid=Liquid +trigger.lowFertilizer=Fertilizer +trigger.lowInput=Input +trigger.lowStamps=Stamps +trigger.mailBuffer=Buffer +usage.engine.tin=In Electrical Engines diff --git a/forestry_resources/lang/forestry/farming/en_US.properties b/forestry_resources/lang/forestry/farming/en_US.properties new file mode 100755 index 000000000..c9fbc72ff --- /dev/null +++ b/forestry_resources/lang/forestry/farming/en_US.properties @@ -0,0 +1,55 @@ +circuit.managedArboreal=Arboretum +circuit.managedPeat=Peat Bog +circuit.managedCereal=Crop Farm +circuit.managedVegetable=Vegetable Farm +circuit.managedInfernal=Infernal Farm +circuit.managedShroom=Shroom Farm +circuit.manualOrchard=Orchard +circuit.manualPeat=Peat Bog +circuit.manualCereal=Crop Farm +circuit.manualVegetable=Vegetable Farm +circuit.manualSucculent=Succulent Farm +circuit.manualPoales=Reed Farm +circuit.manualRubber=Rubber Plantation +circuit.manualGourd=Gourd Farm +circuit.manualCocoa=Cocoa Plantation +circuit.manualShroom=Shroom Farm +errors.noFertilizer.desc=No Fertilizer +errors.noFertilizer.help=Farms require fertilizer for function. Compost is insufficient. +errors.noFarmland.desc=No Farmland +errors.noFarmland.help=Smooth sandstone, bricks or stone bricks create a platform the farm will build on. +errors.noLiquid.desc=No Water +errors.noLiquid.help=Depending on rainfall, temperature and humidity farms need to be supplied with varying amounts of water. +gui.hydration=Hydration Required +gui.hydr.heat=By Heat +gui.hydr.humid=By Humidity +gui.hydr.rainfall=By Rainfall +gui.hydr.overall=Overall +hints.farmland.tag=Lay out your farmland! +hints.farmland.desc=Smooth sandstone, bricks or stone bricks create a platform the farm will build on. +hints.gearbox.tag=Supply power! +hints.gearbox.desc=Use gearboxes to attach engines or power lines to your farm. +hints.valve.tag=Supply water! +hints.valve.desc=Almost all farms require water. Use valve blocks for automation. +hints.fertilizer.tag=Fertilizer needed! +hints.fertilizer.desc=All farms need fertilizer to work. Compost or mulch will not suffice. +hints.hatch.tag=Batten down the hatches! +hints.hatch.desc=Hatches are a pipe or tube's best friend. Use them to automate transport. +hints.circuitboard.tag=Program your farms! +hints.circuitboard.desc=Use a soldering iron to turn your tree farm into any kind of farm you like. +hints.manualfarms.tag=Manual farms! +hints.manualfarms.desc=Apart from the managed farms there are manual farms which will only maintain the farm, but not build it. +hints.farmgui.tag=Soil goes left, seeds go right! +hints.farmgui.desc=Soil goes into the left slots, seeds or saplings into the right slots of the reservoir on the top right part. +layout.farms.managed=Managed Farms +layout.farms.manual=Manual Farms +tile.ffarm.0=Farm Block +tile.ffarm.2=Farm Gearbox +tile.ffarm.3=Farm Hatch +tile.ffarm.4=Farm Valve +tile.ffarm.5=Farm Control +trigger.lowSoil=Soil +trigger.lowLiquid=Water Tank +trigger.lowFertilizer=Fertilizer +usage.farms.managed=Managed Farm +usage.farms.manual=Manual Farm \ No newline at end of file diff --git a/forestry_resources/lang/forestry/lepidopterology/en_US.properties b/forestry_resources/lang/forestry/lepidopterology/en_US.properties new file mode 100755 index 000000000..5aab512d0 --- /dev/null +++ b/forestry_resources/lang/forestry/lepidopterology/en_US.properties @@ -0,0 +1,8 @@ +gui.flutterlyzer.help=Supply butterfly and provide honey or honeydew as a pacifier. +gui.loot.butterfly=Possible Butterfly Loot +gui.loot.caterpillar=Possible Caterpillar Loot +item.butterfly=Butterfly +item.moth=Moth +item.flutterlyzer=Flutterlyzer +storage.backpack.lepidopterist=Lepidopterist's Backpack +tile.for.lepidopterology.0=Lepidopterist's Chest \ No newline at end of file diff --git a/forestry_resources/lang/forestry/mail/en_US.properties b/forestry_resources/lang/forestry/mail/en_US.properties new file mode 100755 index 000000000..47a2a1ad8 --- /dev/null +++ b/forestry_resources/lang/forestry/mail/en_US.properties @@ -0,0 +1,23 @@ +chat.mail.no_mailbox=Recipient has no mailbox. +chat.mail.not_mailable=Letter is not sendable. +chat.mail.not_postpaid=Letter is not sufficiently stamped. +chat.mail.mailbox_full=Recipient's mailbox is full. +chat.mail.already_mailed=Cannot resend letter. +chat.mail.response_not_mailable=Trade station cannot send the response letter. You need to have a mailbox to deliver to. +chat.mail.insufficient_offer=Trade station demands more. +chat.mail.insufficient_trade_good=Trade station has run out of supplies. +chat.mail.insufficient_buffer=Trade station is full. +chat.mail.insufficient_paper=Trade station ran out of paper. +chat.mail.insufficient_stamps=Trade station ran out of stamps. +chat.mail.ok=Trade is available. +chat.mail.wrongstacksize=Can only write one letter at a time. +gui.mail.catalogue.close=Close +gui.mail.catalogue.trade=Trade +gui.mail.filter.all=All +gui.mail.filter.online=Online +gui.mail.filter.offline=Offline +gui.mail.willtrade=%s will trade +gui.mail.address.copy=Use +gui.mail.tradefor=for +gui.mail.notrades=No trades available. +item.catalogue=Catalogue \ No newline at end of file diff --git a/forestry_resources/lang/forestry/pipes/en_US.properties b/forestry_resources/lang/forestry/pipes/en_US.properties new file mode 100755 index 000000000..c7f569f8a --- /dev/null +++ b/forestry_resources/lang/forestry/pipes/en_US.properties @@ -0,0 +1,2 @@ + +item.PipeItemsPropolis=Apiarist's Pipe \ No newline at end of file diff --git a/forestry_resources/mcmod.info b/forestry_resources/mcmod.info new file mode 100755 index 000000000..b27a0f933 --- /dev/null +++ b/forestry_resources/mcmod.info @@ -0,0 +1,18 @@ +[ +{ + "modid": "Forestry", + "name": "Forestry for Minecraft", + "description": "Trees, bees and more.", + "credits": "mistaqur, Binnie", + "logoFile": "/gfx/forestry/logo.png", + "version": "${version}", + "mcversion": "${mcversion}", + "url": "http://forestry.sengir.net/", + "updateUrl": "http://forestry.sengir.net/wiki/index.php?n=Main.Downloads", + "authors": [ "SirSengir" ], + "screenshots": [ "/gfx/forestry/screenshots/screen1.jpg", "/gfx/forestry/screenshots/screen2.jpg" ], + "dependencies": [ + "mod_MinecraftForge" + ] +} +] diff --git a/forestry_techne/Bee.java b/forestry_techne/Bee.java new file mode 100755 index 000000000..4a74d28f7 --- /dev/null +++ b/forestry_techne/Bee.java @@ -0,0 +1,131 @@ +// Date: 30.05.2013 09:02:55 +// Template version 1.1 +// Java generated by Techne +// Keep in mind that you still need to fill in some blanks +// - ZeuX + + + + + + +package net.minecraft.src; + +public class ModelBee extends ModelBase +{ + //fields + ModelRenderer Snout; + ModelRenderer TorsoWing; + ModelRenderer Rump; + ModelRenderer Tail; + ModelRenderer TailEnd; + ModelRenderer Bridge; + ModelRenderer EyeRight; + ModelRenderer EyeLeft; + ModelRenderer WingLeft; + ModelRenderer WingRight; + ModelRenderer crown; + + public ModelBee() + { + textureWidth = 64; + textureHeight = 32; + + Snout = new ModelRenderer(this, 18, 11); + Snout.addBox(0F, 0F, 0F, 1, 2, 1); + Snout.setRotationPoint(0F, 1F, -2F); + Snout.setTextureSize(64, 32); + Snout.mirror = true; + setRotation(Snout, 0F, 0F, 0F); + TorsoWing = new ModelRenderer(this, 28, 14); + TorsoWing.addBox(0F, 0F, 0F, 3, 3, 1); + TorsoWing.setRotationPoint(-1F, 0F, -1F); + TorsoWing.setTextureSize(64, 32); + TorsoWing.mirror = true; + setRotation(TorsoWing, 0F, 0F, 0F); + Rump = new ModelRenderer(this, 10, 14); + Rump.addBox(-1F, -1F, 0F, 3, 3, 3); + Rump.setRotationPoint(0F, 1F, 1F); + Rump.setTextureSize(64, 32); + Rump.mirror = true; + setRotation(Rump, 0F, 0F, 0F); + Tail = new ModelRenderer(this, 4, 14); + Tail.addBox(0F, 0F, 0F, 2, 2, 1); + Tail.setRotationPoint(-0.5F, 0.5333334F, 4F); + Tail.setTextureSize(64, 32); + Tail.mirror = true; + setRotation(Tail, 0F, 0F, 0F); + TailEnd = new ModelRenderer(this, 0, 14); + TailEnd.addBox(0F, 0F, 0F, 1, 1, 1); + TailEnd.setRotationPoint(0F, 1F, 5F); + TailEnd.setTextureSize(64, 32); + TailEnd.mirror = true; + setRotation(TailEnd, 0F, 0F, 0F); + Bridge = new ModelRenderer(this, 22, 14); + Bridge.addBox(0F, 0F, 0F, 2, 2, 1); + Bridge.setRotationPoint(-0.5F, 0.5F, 0F); + Bridge.setTextureSize(64, 32); + Bridge.mirror = true; + setRotation(Bridge, 0F, 0F, 0F); + EyeRight = new ModelRenderer(this, 22, 9); + EyeRight.addBox(0F, 0F, 0F, 1, 1, 1); + EyeRight.setRotationPoint(-1F, 0F, -2F); + EyeRight.setTextureSize(64, 32); + EyeRight.mirror = true; + setRotation(EyeRight, 0F, 0F, 0F); + EyeLeft = new ModelRenderer(this, 18, 9); + EyeLeft.addBox(0F, 0F, 0F, 1, 1, 1); + EyeLeft.setRotationPoint(1F, 0F, -2F); + EyeLeft.setTextureSize(64, 32); + EyeLeft.mirror = true; + setRotation(EyeLeft, 0F, 0F, 0F); + WingLeft = new ModelRenderer(this, 0, 0); + WingLeft.addBox(0F, 0F, 0F, 3, 1, 6); + WingLeft.setRotationPoint(1F, -0.1F, -0.5F); + WingLeft.setTextureSize(64, 32); + WingLeft.mirror = true; + setRotation(WingLeft, 0F, 0F, 0F); + WingRight = new ModelRenderer(this, 0, 7); + WingRight.addBox(-3F, 0F, 0F, 3, 1, 6); + WingRight.setRotationPoint(0F, -0.1F, -0.5F); + WingRight.setTextureSize(64, 32); + WingRight.mirror = true; + setRotation(WingRight, 0F, 0F, 0F); + crown = new ModelRenderer(this, 0, 17); + crown.addBox(0F, 0F, 0F, 2, 1, 2); + crown.setRotationPoint(-0.5F, -1.5F, -1.5F); + crown.setTextureSize(64, 32); + crown.mirror = true; + setRotation(crown, 0F, 0F, 0F); + } + + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) + { + super.render(entity, f, f1, f2, f3, f4, f5); + setRotationAngles(f, f1, f2, f3, f4, f5); + Snout.render(f5); + TorsoWing.render(f5); + Rump.render(f5); + Tail.render(f5); + TailEnd.render(f5); + Bridge.render(f5); + EyeRight.render(f5); + EyeLeft.render(f5); + WingLeft.render(f5); + WingRight.render(f5); + crown.render(f5); + } + + private void setRotation(ModelRenderer model, float x, float y, float z) + { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } + + public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5) + { + super.setRotationAngles(f, f1, f2, f3, f4, f5); + } + +} diff --git a/forestry_techne/Bee1.tcn b/forestry_techne/Bee1.tcn new file mode 100755 index 0000000000000000000000000000000000000000..addeebffd97d71f1dbeb31f1048f7ee20e09b34d GIT binary patch literal 885 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 aR%Qlr6HkCQD=3*TFahBKAbp($!~+2DPC+~X literal 0 HcmV?d00001 diff --git a/forestry_techne/Butterfly1.tcn b/forestry_techne/Butterfly1.tcn new file mode 100755 index 0000000000000000000000000000000000000000..bf74ab432085b7fc15f98b02e9ba35d5a4a1dcaa GIT binary patch literal 709 zcmWIWW@Zs#U|`^2;0Rvj)bPTijFX9h!H<)Hfs;XnAvZrIHAk-^H;0Qs0jP+9fssLi z;l=ra!{NT?7}4psVHfje8;I1--%{^j({8a$K}s(^*J&%r|XLXrL?DHgkJYv-(+T6XgB+PhLKqGrxnyYlCv?Of9U=W4eSf3-QTG;>q3%-*+i?uZ6=RG1!DZZS7mJ#FjZuUE|9MED#YK+zGTTxEX2FY`w~|y77Yi14cEE z{pG8=txBuCSxQ%i&6~h?rCQ}p=hK(v9#7Iw{i{AD6Th?kn0wK)xl@d7zNkNM?B4jk z`tii-Z)XqQyZFL4@=#6Z`+~e_(OKvj>*N(=FKy1ikrLo ziP>y-lV*YI(XaSs{o)thd|}Qjmdu=0XV2VvdP927+p}AGgqQID{`IXP>U#U(=E>EJ z{XFyDT{B@V<$QU-?ZAI0mEX!+UT*Va&plSu!Q#8*qUq1oG2z=+e2@?DW@OT3z@4hV bDG5%Hl*R(QS=k`zkdYx8$Or)@Rt5$Drm!|8 literal 0 HcmV?d00001 diff --git a/forestry_techne/Butterfly2-2.tcn b/forestry_techne/Butterfly2-2.tcn new file mode 100755 index 0000000000000000000000000000000000000000..3ac95170d256a1cb3f17595542028c38eab9dbd2 GIT binary patch literal 1332 zcmWIWW@Zs#U|`^2sHxrLbYjBHWIZMZ1|2>I22KVQhTQy=)EvEv+#D_j1)w4Z21W)6 zh9(8eeP@HuF{0CNr(evQZ6MP2Uj41C!1abkrvMf4mAO||UD_1t8{)gW_<@6sU`J2p z>3Ma>0>me6d%2|Rol=+3(?8F**B02_w5;H~XvO}PFT%6?Pe{3LIRE~-izYQ;A4?A& ziVygEWCeFhlAA@0fx!I2jzIgY%K>gZc{^vU^Zc$fbDp?i%F;joL^5UMDvv%0v0rb& zJ}qVIZO?0F{$J1Oym`K)rMqWJss_86qTBgJpJE+1GM>v?%8|QKE&4*mUeVV_f@kdT z6Pgih@8Od#%JS@#V#2O6nWJSsO$W+Lbk(IF)-I^5^1f_(y?V3h@5z^W1J8dAdZgoT ztl@lHK!0Pa^{4E`X`XYcWC zk^Qb(E3$v5(YA+u>3)*h5%-r(Y5eRyY03d-V}Yx)g?n~YJlLt}rM22D_q6#FX=PQu zHQQO`-z@B6U&s2FIWfVat+;6-58KPs?u78JIq4c-A2>}~*MERF%i@w5UvBKj{LRlI z`VGB%`Gdtz|;W#zVd#sFx-V*n?-ke`gfJ&X(tAS?<@cuu7yC8a~60+7BevL9R^{>_VcGRGn@m? zaPRjJR1`|sH1EN~B88Z(NB7@b*AU%uGviqLBR3TX@yicIdYC`C%AI>>ud;)o);Vmc zy%fu0@dW;NF{#C^v(|EN+5RAU=OXa~LMv|REs|$m!|dm~RlC@w?qREozC&_R%Nmv~ zOncH_`vlDrCK-F0mH};hQ5=FmUcj*FBivT2*H3*}zryqo|mB8YR?9>$C%?e643`{_H2uR1UfOr5C Ct_gtv literal 0 HcmV?d00001 diff --git a/forestry_techne/Butterfly2.png b/forestry_techne/Butterfly2.png new file mode 100755 index 0000000000000000000000000000000000000000..4494c7c2654a560cf6a2b15a2a7ea4d565008593 GIT binary patch literal 396 zcmV;70dxL|P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0U=35K~!i%?Uy|c z!Y~YlZLWaC#KOYF2*+V7Ql-uvm?#qi7eIomAaM?so`5r$CU`(JslWs&CH~ab{ZZ@c z`8943BxFFm*JjMoMFp~aF3dZaTwgwO!0{vMT}^Z(FzYMl<(X(hP|ORzND(0tV6vXz z;c_5cwZ*^Qu7F#F*=WXR;zlGu7t`Ssj05sT9?tGRB)9;5Lsq3f8U&*kU=QwGWpjm^ ztqZib;9I$(7r+vz+Ag9W1FQp1O|>g?M1J9gL@z*Na)hh|v;w?m>rYSzaEun~04PoA z&61u2ehvECOc$mF`S7)-E*@>mNBF8gBYSuZKSF^JeF8cg)Y+gPoelO39RxWhiweLo qSyTXy$)W;qOqS$lgNmZ048R?Am}dXGds-F%0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0gp*UK~!i%?Uu1l z!!Qtr&wT|L8R`o436M~;vQ#`r7^2P$Oq7MCosgn*VC5C6E|HkJz`|M~xjRCVe5TIHD!_y%omx;S2pfaF;)YrT1W1Rph16H3a zz1u$4d4M9CZ`MU9(EiB32_8OP06ja4^8&C5G&izqkWUjp8KEhR=)W>TZlKO*fb*Dr zl+xEJJ^inKUY@Cp-$L)N;!RM`1r}vMY0jn5mWKIbeuarqF}eW7)vJz9bLiq?yAr@C z0U<(6k_*b|bA-q+O*3+wU0?_>oxVU6rL8F2>*&tgSOekgc zrEizdmo<4VkhKZXa1s=H^6sDA{ImYzk;jBNo@+|jH*T`<*7x21bk@P^`fZKt!)oST zd|gKodALRfemjrO>J*%HHj;l=-1{wjjMkXhtRTl=F<*7Y+bJrGwc46 z8R>?thpt8~Gu|w~{nIqDV6wn5CewgfH||+&eJ8ewwcyt(+e7B_CaX&PDb;+|skh*{ zRq*{?AO5VoTKlQ?^-0Bqoo_XIZV7&@J#W}MMQ4fFjrh$|Jo0>{^gH4%RX46Kna03< z%cJJVySF>+rA#9(+Pr;dA^RiaiHlBl{*{*RvCW}*NehZmmzbu%oCb%XsRD@r$JM?UreCfoe+ih~P<6VEw_*hdK zH_!LB=v9ll<^wMk#VwU4Z_@hcdG6jegPibK)m1sISJMlQS$Hl!{+exT)PiT6m-v#e z*>%k9W=U^XeEntOWqZZ6!)%*xC8YgKKYg?I^0`+BXFi=@YQH=GS7fh+_4zijz)fPy zm#}TAYPjY;t$UZd3@hJawLT`fS2D#y7McF1ulYu==FZ(at$mK!r2X?5=VVMeXSiqQ zJ&)d~Wu(WxKC-Z8Of#I~%!0ZAWh0GShc?H}36rJh1(wg-Yj~3loL& zd}ROYWpHm3m$(teC#$zCtn}Ni6^~zKc`Z$jzMHMFy5gMWZ~wAC4i7EczTRy*qaa`% zWybCJjooSA^hIyXTeMD?qSfs;XnAvZrIHAk-^H;0Qs0jP+9fssLi zL5Hhx@1MwXjOg^+nfLQ=83-J|ul}~a&gw2PirE}e5u`G~@avzHNSSv(+YW8~ z>)Ta1F=$21+|qp;v^P$eFT|EEnWz)QytMOf`toaYoi{T1$!~H0vCMlDTetn1qc$f6 zd1~_ItlS+f%71N7d~v6WMP~o(BcA4pi4qmtrcR!Eh3R+lb)l1MPhJ+i=v}2*FiGDi zAyB-t|HfX~@7aspq@$MIm0ixfzIRS%>f7F+b8Zjcou2xb+pKBFgyK7nCTcV9Tx-jB zxAl8}^#0n`r8^hTTrx#$i{9mVZJ&q^Ph6-A<9^AAcsR`FlwAARMYWftSB z#SelFUhnIk+0T;x-uareQhtWO=EClof@kJ@SYWw3=l0A-^Yn@jf8T6+o8D$&eWz_& zz$Ver zp7Hm5x;D?=SBA&yPSdn)+jdJXUYnbD`+Vzhqz?+dtmjQQT1t(BAK~mBU@MdL$ RByUEBXdq)XFb^;=006u=WlaD8 literal 0 HcmV?d00001 diff --git a/pipes_common/forestry/pipes/EnumFilterType.java b/pipes_common/forestry/pipes/EnumFilterType.java new file mode 100755 index 000000000..1b6bee5f7 --- /dev/null +++ b/pipes_common/forestry/pipes/EnumFilterType.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes; + +import java.util.Locale; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.Icon; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import forestry.core.config.ForestryItem; +import forestry.core.render.TextureManager; + +public enum EnumFilterType { + + CLOSED, ANYTHING, ITEM, BEE, DRONE, PRINCESS, QUEEN, PURE_BREED, NOCTURNAL, PURE_NOCTURNAL, FLYER, PURE_FLYER, CAVE, PURE_CAVE, NATURAL; + + public static EnumFilterType getType(ItemStack stack) { + if (ForestryItem.beeDroneGE.isItemEqual(stack)) + return DRONE; + if (ForestryItem.beePrincessGE.isItemEqual(stack)) + return PRINCESS; + if (ForestryItem.beeQueenGE.isItemEqual(stack)) + return QUEEN; + + return ITEM; + } + + @SideOnly(Side.CLIENT) + public Icon getIcon() { + return TextureManager.getInstance().getDefault("analyzer/" + this.toString().toLowerCase(Locale.ENGLISH)); + } +} diff --git a/pipes_common/forestry/pipes/GuiHandlerPipes.java b/pipes_common/forestry/pipes/GuiHandlerPipes.java new file mode 100755 index 000000000..9bf221fe2 --- /dev/null +++ b/pipes_common/forestry/pipes/GuiHandlerPipes.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import buildcraft.transport.Pipe; +import buildcraft.transport.TileGenericPipe; +import cpw.mods.fml.common.network.IGuiHandler; +import forestry.core.network.GuiId; +import forestry.pipes.gui.ContainerPropolisPipe; +import forestry.pipes.gui.GuiPropolisPipe; +import forestry.plugins.PluginApiculture; + +public class GuiHandlerPipes implements IGuiHandler { + + private Pipe getPipe(World world, int x, int y, int z) { + TileEntity tile = world.getBlockTileEntity(x, y, z); + if (tile == null) + return null; + + if (!(tile instanceof TileGenericPipe)) + return null; + + return ((TileGenericPipe) tile).pipe; + } + + @Override + public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + case PropolisPipeGUI: + return new GuiPropolisPipe(player, (PipeItemsPropolis)getPipe(world, x, y, z)); + default: + return null; + + } + } + + @Override + public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) { + + if (id >= GuiId.values().length) + return null; + + switch (GuiId.values()[id]) { + case PropolisPipeGUI: + PluginApiculture.beeInterface.getBreedingTracker(world, player.username).synchToPlayer(player); + return new ContainerPropolisPipe(player.inventory, (PipeItemsPropolis)getPipe(world, x, y, z)); + default: + return null; + + } + } + +} diff --git a/pipes_common/forestry/pipes/PipeIconProvider.java b/pipes_common/forestry/pipes/PipeIconProvider.java new file mode 100755 index 000000000..f1679d0b4 --- /dev/null +++ b/pipes_common/forestry/pipes/PipeIconProvider.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes; + +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.util.Icon; +import buildcraft.api.core.IIconProvider; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import forestry.core.render.TextureManager; + +public class PipeIconProvider implements IIconProvider { + + private static Icon[] icons; + + @Override + @SideOnly(Side.CLIENT) + public Icon getIcon(int iconIndex) { + return icons[iconIndex]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister iconRegister) { + icons = new Icon[7]; + icons[0] = TextureManager.getInstance().registerTex(iconRegister, "pipes/pipe_prop.empty"); + icons[1] = TextureManager.getInstance().registerTex(iconRegister, "pipes/pipe_prop.black"); + icons[2] = TextureManager.getInstance().registerTex(iconRegister, "pipes/pipe_prop.white"); + icons[3] = TextureManager.getInstance().registerTex(iconRegister, "pipes/pipe_prop.red"); + icons[4] = TextureManager.getInstance().registerTex(iconRegister, "pipes/pipe_prop.blue"); + icons[5] = TextureManager.getInstance().registerTex(iconRegister, "pipes/pipe_prop.green"); + icons[6] = TextureManager.getInstance().registerTex(iconRegister, "pipes/pipe_prop.yellow"); + } + +} diff --git a/pipes_common/forestry/pipes/PipeItemsPropolis.java b/pipes_common/forestry/pipes/PipeItemsPropolis.java new file mode 100755 index 000000000..0506565d4 --- /dev/null +++ b/pipes_common/forestry/pipes/PipeItemsPropolis.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes; + +import java.util.ArrayList; +import java.util.LinkedList; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.ForgeDirection; +import buildcraft.api.core.IIconProvider; +import buildcraft.api.core.Position; +import buildcraft.transport.BlockGenericPipe; +import buildcraft.transport.IPipeTransportItemsHook; +import buildcraft.transport.Pipe; +import buildcraft.transport.PipeTransportItems; +import buildcraft.transport.TransportConstants; +import buildcraft.transport.TravelingItem; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import forestry.api.apiculture.IBee; +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.IAllele; +import forestry.core.network.GuiId; +import forestry.core.proxy.Proxies; +import forestry.plugins.PluginApiculture; + +public class PipeItemsPropolis extends Pipe implements IPipeTransportItemsHook { + + public final PipeLogicPropolis pipeLogic; + + public PipeItemsPropolis(int itemID) { + super(new PipeTransportItems(), itemID); + pipeLogic = new PipeLogicPropolis(this); + transport.allowBouncing = true; + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + pipeLogic.readFromNBT(nbt); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + pipeLogic.writeToNBT(nbt); + } + IIconProvider provider; + + @SideOnly(Side.CLIENT) + @Override + public IIconProvider getIconProvider() { + if (provider == null) + provider = new PipeIconProvider(); + + return provider; + } + + @Override + public int getIconIndex(ForgeDirection direction) { + if (direction == ForgeDirection.UNKNOWN) + return 0; + + return direction.ordinal() + 1; + } + + @Override + public boolean blockActivated(EntityPlayer player) { + if (!Proxies.common.isSimulating(getWorld())) + return true; + + if (player.getCurrentEquippedItem() != null && player.getCurrentEquippedItem().itemID < Block.blocksList.length) + if (Block.blocksList[player.getCurrentEquippedItem().itemID] instanceof BlockGenericPipe) + return false; + + player.openGui(ForestryAPI.instance, GuiId.PropolisPipeGUI.ordinal(), player.worldObj, container.xCoord, container.yCoord, container.zCoord); + + return true; + } + + @Override + public LinkedList filterPossibleMovements(LinkedList possibleOrientations, Position pos, TravelingItem item) { + + LinkedList filteredOrientations = new LinkedList(); + LinkedList typedOrientations = new LinkedList(); + LinkedList defaultOrientations = new LinkedList(); + + // We need a bee! + EnumFilterType type = EnumFilterType.getType(item.getItemStack()); + IBee bee = null; + + if (type != EnumFilterType.ITEM) + bee = PluginApiculture.beeInterface.getMember(item.getItemStack()); + + // Filtered outputs + for (ForgeDirection dir : possibleOrientations) { + + // Continue if this direction is closed. + if (pipeLogic.isClosed(dir)) + continue; + + if (pipeLogic.isIndiscriminate(dir)) { + defaultOrientations.add(dir); + continue; + } + + // We need to match the type for this orientation's filter + if (!pipeLogic.matchType(dir, type, bee)) + continue; + + // Passing the type filter is enough for non-bee items. + if (type == EnumFilterType.ITEM) { + filteredOrientations.add(dir); + continue; + } + + ArrayList filters = pipeLogic.getGenomeFilters(dir); + // If we have no genome filters, this is only a typed route. + if (filters.size() <= 0) { + typedOrientations.add(dir); + continue; + } + + // Bees need to match one of the genome filters + for (IAllele[] pattern : filters) { + if (pipeLogic.matchAllele(pattern[0], bee.getIdent()) && pipeLogic.matchAllele(pattern[1], bee.getGenome().getSecondary().getUID())) + filteredOrientations.add(dir); + } + } + + if (filteredOrientations.size() > 0) + return filteredOrientations; + else if (typedOrientations.size() > 0) + return typedOrientations; + else + return defaultOrientations; + + } + + @Override + public void entityEntered(TravelingItem item, ForgeDirection orientation) { + // A bit of speed to perhaps prevent bees from popping out of the pipe. + try { + item.setSpeed(TransportConstants.PIPE_NORMAL_SPEED * 20F); + } catch (Throwable error) { + } + } + + @Override + public void readjustSpeed(TravelingItem item) { + transport.defaultReajustSpeed(item); + } +} diff --git a/pipes_common/forestry/pipes/PipeLogicPropolis.java b/pipes_common/forestry/pipes/PipeLogicPropolis.java new file mode 100755 index 000000000..460a24b6d --- /dev/null +++ b/pipes_common/forestry/pipes/PipeLogicPropolis.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.ForgeDirection; +import buildcraft.transport.BlockGenericPipe; +import buildcraft.transport.Pipe; +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.IBee; +import forestry.api.core.ForestryAPI; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleSpecies; +import forestry.core.network.GuiId; +import forestry.core.network.PacketCoordinates; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketNBT; +import forestry.core.network.PacketPayload; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; + +public class PipeLogicPropolis { + + private Pipe pipe; + + private EnumFilterType[] typeFilter = new EnumFilterType[6]; + private IAllele[][][] genomeFilter = new IAllele[6][3][2]; + + public PipeLogicPropolis(Pipe pipe) { + this.pipe = pipe; + for (int i = 0; i < typeFilter.length; i++) + typeFilter[i] = EnumFilterType.CLOSED; + } + + public void readFromNBT(NBTTagCompound nbttagcompound) { + for (int i = 0; i < typeFilter.length; i++) + typeFilter[i] = EnumFilterType.values()[nbttagcompound.getByte("TypeFilter" + i)]; + + for (int i = 0; i < 6; i++) + for (int j = 0; j < 3; j++) { + if (nbttagcompound.hasKey("GenomeFilterS" + i + "-" + j + "-" + 0)) + genomeFilter[i][j][0] = AlleleManager.alleleRegistry.getAllele(nbttagcompound.getString("GenomeFilterS" + i + "-" + j + "-" + 0)); + if (nbttagcompound.hasKey("GenomeFilterS" + i + "-" + j + "-" + 1)) + genomeFilter[i][j][1] = AlleleManager.alleleRegistry.getAllele(nbttagcompound.getString("GenomeFilterS" + i + "-" + j + "-" + 1)); + } + } + + public void writeToNBT(NBTTagCompound nbttagcompound) { + for (int i = 0; i < typeFilter.length; i++) + nbttagcompound.setByte("TypeFilter" + i, (byte) typeFilter[i].ordinal()); + + for (int i = 0; i < 6; i++) + for (int j = 0; j < 3; j++) { + if (genomeFilter[i][j][0] != null) + nbttagcompound.setString("GenomeFilterS" + i + "-" + j + "-" + 0, genomeFilter[i][j][0].getUID()); + if (genomeFilter[i][j][1] != null) + nbttagcompound.setString("GenomeFilterS" + i + "-" + j + "-" + 1, genomeFilter[i][j][1].getUID()); + } + } + + public boolean isClosed(ForgeDirection orientation) { + return typeFilter[orientation.ordinal()] == EnumFilterType.CLOSED; + } + + public boolean isIndiscriminate(ForgeDirection orientation) { + return typeFilter[orientation.ordinal()] == EnumFilterType.ANYTHING; + } + + public boolean matchType(ForgeDirection orientation, EnumFilterType type, IBee bee) { + EnumFilterType filter = typeFilter[orientation.ordinal()]; + if (filter == EnumFilterType.BEE) + return type != EnumFilterType.ITEM && type != EnumFilterType.CLOSED && type != EnumFilterType.CLOSED; + + // Special bee filtering + if (bee != null) { + if (filter == EnumFilterType.PURE_BREED) + return bee.isPureBred(EnumBeeChromosome.SPECIES.ordinal()); + if (filter == EnumFilterType.NOCTURNAL) + return bee.getGenome().getNocturnal(); + if (filter == EnumFilterType.PURE_NOCTURNAL) + return bee.getGenome().getNocturnal() && bee.isPureBred(EnumBeeChromosome.NOCTURNAL.ordinal()); + if (filter == EnumFilterType.FLYER) + return bee.getGenome().getTolerantFlyer(); + if (filter == EnumFilterType.PURE_FLYER) + return bee.getGenome().getTolerantFlyer() && bee.isPureBred(EnumBeeChromosome.TOLERANT_FLYER.ordinal()); + if (filter == EnumFilterType.CAVE) + return bee.getGenome().getCaveDwelling(); + if (filter == EnumFilterType.PURE_CAVE) + return bee.getGenome().getCaveDwelling() && bee.isPureBred(EnumBeeChromosome.CAVE_DWELLING.ordinal()); + if (filter == EnumFilterType.NATURAL) + return bee.isNatural(); + } + + // Compare the remaining + return filter == type; + } + + public boolean matchAllele(IAllele filter, String ident) { + if (filter == null) + return true; + else + return filter.getUID().equals(ident); + } + + public ArrayList getGenomeFilters(ForgeDirection orientation) { + ArrayList filters = new ArrayList(); + + for (int i = 0; i < 3; i++) + if (genomeFilter[orientation.ordinal()][i] != null + && (genomeFilter[orientation.ordinal()][i][0] != null || genomeFilter[orientation.ordinal()][i][1] != null)) + filters.add(genomeFilter[orientation.ordinal()][i]); + + return filters; + } + + public EnumFilterType getTypeFilter(ForgeDirection orientation) { + return typeFilter[orientation.ordinal()]; + } + + public void setTypeFilter(ForgeDirection orientation, EnumFilterType type) { + typeFilter[orientation.ordinal()] = type; + if (!Proxies.common.isSimulating(pipe.getWorld())) + sendTypeFilterChange(orientation, type); + } + + public IAlleleSpecies getSpeciesFilter(ForgeDirection orientation, int pattern, int allele) { + + if (genomeFilter[orientation.ordinal()] == null) + return null; + + if (genomeFilter[orientation.ordinal()].length <= pattern) + return null; + + if (genomeFilter[orientation.ordinal()][pattern] == null) + return null; + + if (genomeFilter[orientation.ordinal()][pattern].length <= allele) + return null; + + return (IAlleleSpecies) genomeFilter[orientation.ordinal()][pattern][allele]; + } + + public void setSpeciesFilter(ForgeDirection orientation, int pattern, int allele, IAllele species) { + genomeFilter[orientation.ordinal()][pattern][allele] = species; + if (!Proxies.common.isSimulating(pipe.getWorld())) + sendGenomeFilterChange(orientation, pattern, allele, species); + } + + // Server side + public void sendFilterSet(EntityPlayer player) { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + this.writeToNBT(nbttagcompound); + Proxies.net.sendToPlayer(new PacketNBT(PacketIds.PROP_SEND_FILTER_SET, nbttagcompound), player); + } + + public void handleTypeFilterChange(PacketPayload payload) { + typeFilter[payload.intPayload[0]] = EnumFilterType.values()[payload.intPayload[1]]; + } + + public void handleGenomeFilterChange(PacketPayload payload) { + if (!payload.stringPayload[0].equals("NULL")) + genomeFilter[payload.intPayload[0]][payload.intPayload[1]][payload.intPayload[2]] = AlleleManager.alleleRegistry + .getAllele(payload.stringPayload[0]); + else + genomeFilter[payload.intPayload[0]][payload.intPayload[1]][payload.intPayload[2]] = null; + } + + // Client side + public void requestFilterSet() { + Proxies.net.sendToServer(new PacketCoordinates(PacketIds.PROP_REQUEST_FILTER_SET, pipe.container.xCoord, pipe.container.yCoord, pipe.container.zCoord)); + } + + public void sendTypeFilterChange(ForgeDirection orientation, EnumFilterType filter) { + PacketPayload payload = new PacketPayload(2, 0, 0); + payload.intPayload[0] = orientation.ordinal(); + payload.intPayload[1] = filter.ordinal(); + Proxies.net.sendToServer(new PacketUpdate(PacketIds.PROP_SEND_FILTER_CHANGE_TYPE, pipe.container.xCoord, pipe.container.yCoord, pipe.container.zCoord, payload)); + } + + public void sendGenomeFilterChange(ForgeDirection orientation, int pattern, int allele, IAllele species) { + PacketPayload payload = new PacketPayload(3, 0, 1); + payload.intPayload[0] = orientation.ordinal(); + payload.intPayload[1] = pattern; + payload.intPayload[2] = allele; + if (species != null) + payload.stringPayload[0] = species.getUID(); + else + payload.stringPayload[0] = "NULL"; + + Proxies.net.sendToServer(new PacketUpdate(PacketIds.PROP_SEND_FILTER_CHANGE_GENOME, pipe.container.xCoord, pipe.container.yCoord, pipe.container.zCoord, payload)); + } + + public void handleFilterSet(PacketNBT packet) { + this.readFromNBT(packet.getTagCompound()); + } +} diff --git a/pipes_common/forestry/pipes/gui/ContainerPropolisPipe.java b/pipes_common/forestry/pipes/gui/ContainerPropolisPipe.java new file mode 100755 index 000000000..7a7a94467 --- /dev/null +++ b/pipes_common/forestry/pipes/gui/ContainerPropolisPipe.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) SpaceToad, 2011 + * http://www.mod-buildcraft.com + * + * BuildCraft is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://www.mod-buildcraft.com/MMPL-1.0.txt + */ + +package forestry.pipes.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import buildcraft.transport.Pipe; +import forestry.core.gui.ContainerForestry; +import forestry.core.utils.InventoryAdapter; +import forestry.pipes.PipeItemsPropolis; +import forestry.pipes.PipeLogicPropolis; + +public class ContainerPropolisPipe extends ContainerForestry { + + IInventory playerIInventory; + public PipeLogicPropolis pipeLogic; + + public ContainerPropolisPipe(IInventory playerInventory, PipeItemsPropolis pipe) { + super(new InventoryAdapter(0, "Empty")); + this.playerIInventory = playerInventory; + this.pipeLogic = (PipeLogicPropolis) pipe.pipeLogic; + + for (int l = 0; l < 3; l++) + for (int k1 = 0; k1 < 9; k1++) + addSlot(new Slot(playerInventory, k1 + l * 9 + 9, 8 + k1 * 18, 140 + l * 18)); + + for (int i1 = 0; i1 < 9; i1++) + addSlot(new Slot(playerInventory, i1, 8 + i1 * 18, 198)); + } + + @Override + public boolean canInteractWith(EntityPlayer entityplayer) { + return true; + } + +} diff --git a/pipes_common/forestry/pipes/gui/GuiPropolisPipe.java b/pipes_common/forestry/pipes/gui/GuiPropolisPipe.java new file mode 100755 index 000000000..c79ca7b69 --- /dev/null +++ b/pipes_common/forestry/pipes/gui/GuiPropolisPipe.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes.gui; + +import java.util.Iterator; +import java.util.Locale; +import java.util.Map.Entry; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.Icon; +import net.minecraftforge.common.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import buildcraft.transport.Pipe; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IAlleleSpecies; +import forestry.apiculture.items.ItemBeeGE; +import forestry.core.config.Config; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.genetics.ItemGE; +import forestry.core.gui.widgets.Widget; +import forestry.core.gui.GuiForestry; +import forestry.core.proxy.Proxies; +import forestry.core.render.SpriteSheet; +import forestry.core.utils.StringUtil; +import forestry.pipes.EnumFilterType; +import forestry.pipes.PipeItemsPropolis; +import forestry.pipes.PipeLogicPropolis; +import forestry.plugins.PluginApiculture; + +/** + * GuiScreen for propolis pipes. + * + * @author SirSengir + */ +public class GuiPropolisPipe extends GuiForestry { + + class TypeFilterSlot extends Widget { + + ForgeDirection orientation; + PipeLogicPropolis logic; + + public TypeFilterSlot(int x, int y, ForgeDirection orientation, PipeLogicPropolis logic) { + super(widgetManager, x, y); + this.orientation = orientation; + this.logic = logic; + } + + public EnumFilterType getType() { + return logic.getTypeFilter(orientation); + } + + @Override + public void draw(int startX, int startY) { + EnumFilterType type = logic.getTypeFilter(orientation); + Icon icon = null; + if (type != null) + icon = type.getIcon(); + if(icon == null) + return; + + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0F); + Proxies.common.bindTexture(SpriteSheet.ITEMS); + drawTexturedModelRectFromIcon(startX + xPos, startY + yPos, icon, 16, 16); + + } + + @Override + protected String getLegacyTooltip(EntityPlayer player) { + EnumFilterType type = logic.getTypeFilter(orientation); + return StringUtil.localize("gui.pipe.filter." + type.toString().toLowerCase(Locale.ENGLISH)); + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + EnumFilterType change; + if (mouseButton == 1) + change = EnumFilterType.CLOSED; + else if (getType().ordinal() < EnumFilterType.values().length - 1) + change = EnumFilterType.values()[getType().ordinal() + 1]; + else + change = EnumFilterType.CLOSED; + pipeLogic.setTypeFilter(orientation, change); + + } + + } + + class SpeciesFilterSlot extends Widget { + + IApiaristTracker tracker; + ForgeDirection orientation; + PipeLogicPropolis logic; + int pattern; + int allele; + + public SpeciesFilterSlot(IApiaristTracker tracker, int x, int y, ForgeDirection orientation, int pattern, int allele, PipeLogicPropolis logic) { + super(widgetManager, x, y); + this.tracker = tracker; + this.orientation = orientation; + this.pattern = pattern; + this.allele = allele; + this.logic = logic; + } + + public IAlleleSpecies getSpecies() { + return logic.getSpeciesFilter(orientation, pattern, allele); + } + + public boolean isDefined() { + IAlleleSpecies species = logic.getSpeciesFilter(orientation, pattern, allele); + return species != null; + } + + @Override + public void draw(int startX, int startY) { + if (!isDefined()) + return; + + IAlleleSpecies species = logic.getSpeciesFilter(orientation, pattern, allele); + GL11.glDisable(GL11.GL_LIGHTING); + + for (int i = 0; i < 3; ++i) { + + Icon icon = ((ItemBeeGE) ForestryItem.beeDroneGE.item()).getIconFromSpecies((IAlleleBeeSpecies) species, i); + int color = ((ItemGE) ForestryItem.beeDroneGE.item()).getColourFromSpecies(species, i); + + float colorR = (color >> 16 & 255) / 255.0F; + float colorG = (color >> 8 & 255) / 255.0F; + float colorB = (color & 255) / 255.0F; + + GL11.glColor4f(colorR, colorG, colorB, 1.0F); + // drawTexturedModalRect(startX + xPos, startY + yPos, iconIndex % 16 * 16, iconIndex / 16 * 16, 16, 16); + manager.gui.drawTexturedModelRectFromIcon(startX + xPos, startY + yPos, icon, 16, 16); + + } + GL11.glEnable(GL11.GL_LIGHTING); + + } + + @Override + protected String getLegacyTooltip(EntityPlayer player) { + IAlleleSpecies species = logic.getSpeciesFilter(orientation, pattern, allele); + if (species != null) + return species.getName(); + else + return null; + } + + @Override + public void handleMouseClick(int mouseX, int mouseY, int mouseButton) { + IAlleleSpecies change = null; + if (mouseButton == 1) + change = null; + else if (getSpecies() == null) { + + Iterator it = AlleleManager.alleleRegistry.getRegisteredAlleles().entrySet().iterator(); + while (it.hasNext()) { + Entry entry = (Entry) it.next(); + if (!(entry.getValue() instanceof IAlleleBeeSpecies)) + continue; + + change = (IAlleleBeeSpecies) entry.getValue(); + break; + } + + } else { + + Iterator it = AlleleManager.alleleRegistry.getRegisteredAlleles().entrySet().iterator(); + while (it.hasNext()) { + Entry entry = (Entry) it.next(); + if (!(entry.getValue() instanceof IAlleleBeeSpecies)) + continue; + + IAlleleBeeSpecies species = (IAlleleBeeSpecies) entry.getValue(); + if (!species.getUID().equals(getSpecies().getUID())) + continue; + + while (it.hasNext()) { + Entry entry2 = (Entry) it.next(); + if (!(entry2.getValue() instanceof IAlleleBeeSpecies)) + continue; + + IAlleleBeeSpecies next = (IAlleleBeeSpecies) entry2.getValue(); + if (!Config.isDebug && next.isSecret() && !tracker.isDiscovered(next)) + continue; + + change = next; + break; + } + + break; + } + } + pipeLogic.setSpeciesFilter(orientation, pattern, allele, change); + } + } + + PipeLogicPropolis pipeLogic; + + public GuiPropolisPipe(EntityPlayer player, PipeItemsPropolis pipe) { + super(Defaults.TEXTURE_PATH_GUI + "/analyzer.png", new ContainerPropolisPipe(player.inventory, pipe)); + + pipeLogic = pipe.pipeLogic; + // Request filter set update if on client + if (!Proxies.common.isSimulating(pipe.getWorld())) + pipeLogic.requestFilterSet(); + + xSize = 175; + ySize = 225; + + for (int i = 0; i < 6; i++) + widgetManager.add(new TypeFilterSlot(8, 18 + i * 18, ForgeDirection.values()[i], pipeLogic)); + + IApiaristTracker tracker = PluginApiculture.beeInterface.getBreedingTracker(player.worldObj, player.username); + for (int i = 0; i < 6; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + widgetManager.add(new SpeciesFilterSlot(tracker, 44 + j * 45 + k * 18, 18 + i * 18, ForgeDirection.values()[i], j, k, pipeLogic)); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + super.drawGuiContainerForegroundLayer(mouseX, mouseY); + fontRenderer.drawString("Apiarist's Pipe", 56, 6, 0x303030); + } +} diff --git a/pipes_common/forestry/pipes/network/PacketHandlerPipes.java b/pipes_common/forestry/pipes/network/PacketHandlerPipes.java new file mode 100755 index 000000000..dd86d8e7b --- /dev/null +++ b/pipes_common/forestry/pipes/network/PacketHandlerPipes.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes.network; + +import java.io.DataInputStream; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.network.INetworkManager; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import buildcraft.transport.Pipe; +import buildcraft.transport.TileGenericPipe; +import cpw.mods.fml.common.network.Player; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.network.PacketCoordinates; +import forestry.core.network.PacketIds; +import forestry.core.network.PacketNBT; +import forestry.core.network.PacketUpdate; +import forestry.core.proxy.Proxies; +import forestry.pipes.PipeItemsPropolis; +import forestry.pipes.PipeLogicPropolis; +import forestry.pipes.gui.ContainerPropolisPipe; + +public class PacketHandlerPipes implements IPacketHandler { + + private Pipe getPipe(World world, int x, int y, int z) { + TileEntity tile = world.getBlockTileEntity(x, y, z); + if (tile == null) + return null; + + if (!(tile instanceof TileGenericPipe)) + return null; + + return ((TileGenericPipe) tile).pipe; + } + + @Override + public void onPacketData(INetworkManager network, int packetID, DataInputStream data, Player player) { + + try { + + PacketUpdate packetU; + + switch (packetID) { + + // CLIENT + case PacketIds.PROP_SEND_FILTER_SET: + PacketNBT packetN = new PacketNBT(); + packetN.readData(data); + onFilterSet(packetN); + break; + + // SERVER + case PacketIds.PROP_REQUEST_FILTER_SET: + PacketCoordinates packetC = new PacketCoordinates(); + packetC.readData(data); + onRequestFilterSet((EntityPlayer) player, packetC); + break; + case PacketIds.PROP_SEND_FILTER_CHANGE_TYPE: + packetU = new PacketUpdate(); + packetU.readData(data); + onTypeFilterChange((EntityPlayer) player, packetU); + break; + case PacketIds.PROP_SEND_FILTER_CHANGE_GENOME: + packetU = new PacketUpdate(); + packetU.readData(data); + onGenomeFilterChange((EntityPlayer) player, packetU); + break; + + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + private void onFilterSet(PacketNBT packet) { + Container container = Proxies.common.getClientInstance().thePlayer.openContainer; + + if (container instanceof ContainerPropolisPipe) { + PipeLogicPropolis pipeLogic = ((ContainerPropolisPipe) container).pipeLogic; + pipeLogic.handleFilterSet(packet); + } + } + + private void onTypeFilterChange(EntityPlayer player, PacketUpdate packet) { + + Pipe pipe = getPipe(player.worldObj, packet.posX, packet.posY, packet.posZ); + if (pipe == null) + return; + + if (pipe instanceof PipeItemsPropolis) + ((PipeItemsPropolis) pipe).pipeLogic.handleTypeFilterChange(packet.payload); + + } + + private void onGenomeFilterChange(EntityPlayer player, PacketUpdate packet) { + + Pipe pipe = getPipe(player.worldObj, packet.posX, packet.posY, packet.posZ); + if (pipe == null) + return; + + if (pipe instanceof PipeItemsPropolis) + ((PipeItemsPropolis) pipe).pipeLogic.handleGenomeFilterChange(packet.payload); + } + + private void onRequestFilterSet(EntityPlayer player, PacketCoordinates packet) { + + Pipe pipe = getPipe(player.worldObj, packet.posX, packet.posY, packet.posZ); + if (pipe == null) + return; + + if (pipe instanceof PipeItemsPropolis) + ((PipeItemsPropolis) pipe).pipeLogic.sendFilterSet(player); + } + +} diff --git a/pipes_common/forestry/pipes/proxy/ClientProxyPipes.java b/pipes_common/forestry/pipes/proxy/ClientProxyPipes.java new file mode 100755 index 000000000..ef8557afc --- /dev/null +++ b/pipes_common/forestry/pipes/proxy/ClientProxyPipes.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes.proxy; + +import net.minecraftforge.client.IItemRenderer; +import net.minecraftforge.client.MinecraftForgeClient; +import buildcraft.core.utils.Localization; +import buildcraft.transport.TransportProxyClient; +import forestry.plugins.PluginPropolisPipe; + +public class ClientProxyPipes extends ProxyPipes { + + @Override + public void registerCustomItemRenderer(int itemID, IItemRenderer basemod) { + MinecraftForgeClient.registerItemRenderer(itemID, basemod); + } + + @Override + public void initPropolisPipe() { + super.initPropolisPipe(); + registerCustomItemRenderer(PluginPropolisPipe.pipeItemsPropolis.itemID, TransportProxyClient.pipeItemRenderer); + } + + @Override + public void addLocalizations() { + Localization.addLocalization("/lang/forestry/pipes/", "en_US"); + } + +} diff --git a/pipes_common/forestry/pipes/proxy/ProxyPipes.java b/pipes_common/forestry/pipes/proxy/ProxyPipes.java new file mode 100755 index 000000000..c68f7a7ab --- /dev/null +++ b/pipes_common/forestry/pipes/proxy/ProxyPipes.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.pipes.proxy; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.client.IItemRenderer; +import buildcraft.BuildCraftTransport; +import buildcraft.transport.BlockGenericPipe; +import buildcraft.transport.Pipe; +import cpw.mods.fml.common.registry.GameRegistry; +import forestry.pipes.PipeItemsPropolis; +import forestry.plugins.PluginPropolisPipe; + +public class ProxyPipes { + + public void registerCustomItemRenderer(int itemID, IItemRenderer basemod) { + } + + public void initPropolisPipe() { + PluginPropolisPipe.pipeItemsPropolis = createPipe(PluginPropolisPipe.propolisPipeItemId, PipeItemsPropolis.class, "Apiarist's Pipe"); + } + + public Item createPipe(int id, Class clas, String description) { + + Item pipe = BlockGenericPipe.registerPipe(id, clas); + pipe.setUnlocalizedName(clas.getSimpleName()); + + return pipe; + } + + public void registerCraftingPropolis(ItemStack resource) { + GameRegistry.addRecipe(new ItemStack(PluginPropolisPipe.pipeItemsPropolis), + new Object[] { "#X#", Character.valueOf('#'), resource, Character.valueOf('X'), BuildCraftTransport.pipeItemsDiamond }); + + } + + public void addLocalizations() { + } +} diff --git a/pipes_common/forestry/plugins/PluginPropolisPipe.java b/pipes_common/forestry/plugins/PluginPropolisPipe.java new file mode 100755 index 000000000..ed3c759f9 --- /dev/null +++ b/pipes_common/forestry/plugins/PluginPropolisPipe.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright 2011-2014 by SirSengir + * + * This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. + * + * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/. + ******************************************************************************/ +package forestry.plugins; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.network.IGuiHandler; +import forestry.api.core.PluginInfo; +import forestry.core.config.Configuration; +import forestry.core.config.Defaults; +import forestry.core.config.ForestryItem; +import forestry.core.interfaces.IPacketHandler; +import forestry.core.proxy.Proxies; +import forestry.pipes.GuiHandlerPipes; +import forestry.pipes.network.PacketHandlerPipes; +import forestry.pipes.proxy.ProxyPipes; + +@PluginInfo(pluginID = "Pipes", name = "Pipes", author = "SirSengir", url = Defaults.URL, description = "Adds the apiarist's pipe for beekeeping if apiculture is enabled and BuildCraft 3 is present.") +public class PluginPropolisPipe extends NativePlugin { + + public static ProxyPipes proxy; + + static String CONFIG_CATEGORY = "pipes"; + public static Configuration config; + public static int propolisPipeItemId; + + public static String textureBees = Defaults.TEXTURE_PATH_GUI + "/analyzer_icons.png"; + /** + * Pipe used to sort bees from Forestry. + */ + public static Item pipeItemsPropolis; + + @Override + public boolean isAvailable() { + return Proxies.common.isModLoaded("BuildCraft|Transport"); + } + + @Override + public void preInit() { + + config = new Configuration(); + + propolisPipeItemId = Integer.parseInt(PluginPropolisPipe.config.get("propolisPipe", CONFIG_CATEGORY, 14000).Value); + + config.save(); + + } + + @Override + public void doInit() { + } + + @Override + public void postInit() { + String proxyClass = "forestry.pipes.proxy.ProxyPipes"; + if (FMLCommonHandler.instance().getSide().isClient()) + proxyClass = "forestry.pipes.proxy.ClientProxyPipes"; + + proxy = (ProxyPipes) Proxies.common.instantiateIfModLoaded("BuildCraft|Transport", proxyClass); + + if (proxy == null) + return; + + proxy.initPropolisPipe(); + proxy.registerCraftingPropolis(ForestryItem.propolis.getItemStack()); + proxy.addLocalizations(); + + } + + @Override + public IGuiHandler getGuiHandler() { + return new GuiHandlerPipes(); + } + + @Override + public IPacketHandler getPacketHandler() { + return new PacketHandlerPipes(); + } + + @Override + protected void registerItems() { + } + + @Override + protected void registerBackpackItems() { + } + + @Override + protected void registerCrates() { + } + + @Override + protected void registerRecipes() { + } + +}