From 2cc9d3a53aa43f757276a89ac80c4ab434abcbcd Mon Sep 17 00:00:00 2001 From: WayofTime Date: Mon, 11 May 2015 13:12:56 -0400 Subject: [PATCH] Added the Forestry API --- build.properties | 4 +- .../forestry/api/apiculture/BeeManager.java | 49 ++++ .../api/apiculture/EnumBeeChromosome.java | 102 ++++++++ .../forestry/api/apiculture/EnumBeeType.java | 24 ++ .../api/apiculture/FlowerManager.java | 39 ++++ .../api/apiculture/IAlleleBeeEffect.java | 36 +++ .../api/apiculture/IAlleleBeeSpecies.java | 69 ++++++ .../apiculture/IAlleleBeeSpeciesCustom.java | 40 ++++ .../api/apiculture/IAlvearyComponent.java | 32 +++ .../api/apiculture/IApiaristTracker.java | 57 +++++ .../api/apiculture/IArmorApiarist.java | 29 +++ .../java/forestry/api/apiculture/IBee.java | 88 +++++++ .../forestry/api/apiculture/IBeeFactory.java | 39 ++++ .../forestry/api/apiculture/IBeeGenome.java | 48 ++++ .../forestry/api/apiculture/IBeeHousing.java | 27 +++ .../api/apiculture/IBeeIconProvider.java | 14 ++ .../forestry/api/apiculture/IBeeListener.java | 46 ++++ .../forestry/api/apiculture/IBeeModifier.java | 71 ++++++ .../forestry/api/apiculture/IBeeMutation.java | 29 +++ .../api/apiculture/IBeeMutationCustom.java | 12 + .../api/apiculture/IBeeMutationFactory.java | 23 ++ .../forestry/api/apiculture/IBeeRoot.java | 128 ++++++++++ .../api/apiculture/IBeekeepingLogic.java | 27 +++ .../api/apiculture/IBeekeepingMode.java | 70 ++++++ .../forestry/api/apiculture/IHiveDrop.java | 38 +++ .../forestry/api/apiculture/IHiveFrame.java | 27 +++ .../api/apiculture/IJubilanceFactory.java | 16 ++ .../api/apiculture/IJubilanceProvider.java | 15 ++ .../api/apiculture/hives/HiveManager.java | 13 ++ .../apiculture/hives/IHiveDescription.java | 48 ++++ .../api/apiculture/hives/IHiveGen.java | 29 +++ .../api/apiculture/hives/IHiveGenHelper.java | 23 ++ .../api/apiculture/hives/IHiveRegistry.java | 33 +++ .../api/apiculture/hives/package-info.java | 8 + .../forestry/api/apiculture/package-info.java | 8 + .../api/arboriculture/EnumGermlingType.java | 23 ++ .../arboriculture/EnumGrowthConditions.java | 10 + .../api/arboriculture/EnumTreeChromosome.java | 96 ++++++++ .../api/arboriculture/IAlleleFruit.java | 17 ++ .../api/arboriculture/IAlleleGrowth.java | 17 ++ .../api/arboriculture/IAlleleLeafEffect.java | 20 ++ .../api/arboriculture/IAlleleTreeSpecies.java | 69 ++++++ .../api/arboriculture/IArboristTracker.java | 12 + .../api/arboriculture/IFruitProvider.java | 74 ++++++ .../api/arboriculture/IGrowthProvider.java | 38 +++ .../api/arboriculture/ILeafTickHandler.java | 12 + .../api/arboriculture/IToolGrafter.java | 24 ++ .../forestry/api/arboriculture/ITree.java | 100 ++++++++ .../api/arboriculture/ITreeGenome.java | 46 ++++ .../api/arboriculture/ITreeModifier.java | 45 ++++ .../api/arboriculture/ITreeMutation.java | 34 +++ .../forestry/api/arboriculture/ITreeRoot.java | 113 +++++++++ .../api/arboriculture/ITreekeepingMode.java | 22 ++ .../api/arboriculture/package-info.java | 8 + .../forestry/api/circuits/ChipsetManager.java | 13 ++ .../java/forestry/api/circuits/ICircuit.java | 32 +++ .../forestry/api/circuits/ICircuitBoard.java | 32 +++ .../forestry/api/circuits/ICircuitLayout.java | 16 ++ .../api/circuits/ICircuitLibrary.java | 10 + .../api/circuits/ICircuitRegistry.java | 37 +++ .../forestry/api/circuits/ISolderManager.java | 14 ++ .../forestry/api/circuits/package-info.java | 8 + .../java/forestry/api/core/BiomeHelper.java | 36 +++ .../java/forestry/api/core/EnumHumidity.java | 43 ++++ .../forestry/api/core/EnumTemperature.java | 71 ++++++ .../forestry/api/core/ErrorStateRegistry.java | 77 +++++++ .../java/forestry/api/core/ForestryAPI.java | 52 +++++ .../java/forestry/api/core/ForestryEvent.java | 60 +++++ .../forestry/api/core/IArmorNaturalist.java | 25 ++ .../java/forestry/api/core/IErrorState.java | 41 ++++ .../forestry/api/core/IForestryConstants.java | 24 ++ src/api/java/forestry/api/core/IGameMode.java | 41 ++++ .../java/forestry/api/core/IIconProvider.java | 25 ++ .../java/forestry/api/core/INBTTagable.java | 14 ++ .../forestry/api/core/IStructureLogic.java | 20 ++ .../forestry/api/core/ITextureManager.java | 21 ++ .../forestry/api/core/ITileStructure.java | 63 +++++ .../java/forestry/api/core/IToolPipette.java | 54 +++++ .../java/forestry/api/core/IToolScoop.java | 13 ++ src/api/java/forestry/api/core/Tabs.java | 19 ++ .../java/forestry/api/core/package-info.java | 8 + .../java/forestry/api/farming/Farmables.java | 20 ++ src/api/java/forestry/api/farming/ICrop.java | 21 ++ .../forestry/api/farming/IFarmComponent.java | 17 ++ .../forestry/api/farming/IFarmHousing.java | 74 ++++++ .../forestry/api/farming/IFarmInterface.java | 20 ++ .../forestry/api/farming/IFarmListener.java | 77 +++++++ .../java/forestry/api/farming/IFarmLogic.java | 43 ++++ .../java/forestry/api/farming/IFarmable.java | 60 +++++ .../forestry/api/farming/package-info.java | 8 + .../forestry/api/food/BeverageManager.java | 13 ++ .../forestry/api/food/IBeverageEffect.java | 17 ++ .../forestry/api/food/IInfuserManager.java | 24 ++ .../forestry/api/food/IIngredientManager.java | 16 ++ .../java/forestry/api/food/package-info.java | 8 + .../forestry/api/fuels/EngineBronzeFuel.java | 34 +++ .../forestry/api/fuels/EngineCopperFuel.java | 31 +++ .../forestry/api/fuels/FermenterFuel.java | 29 +++ .../java/forestry/api/fuels/FuelManager.java | 40 ++++ .../forestry/api/fuels/GeneratorFuel.java | 31 +++ .../forestry/api/fuels/MoistenerFuel.java | 34 +++ .../forestry/api/fuels/RainSubstrate.java | 40 ++++ .../java/forestry/api/fuels/package-info.java | 8 + .../forestry/api/genetics/AlleleManager.java | 36 +++ .../forestry/api/genetics/EnumTolerance.java | 16 ++ .../java/forestry/api/genetics/IAllele.java | 39 ++++ .../forestry/api/genetics/IAlleleArea.java | 15 ++ .../forestry/api/genetics/IAlleleBoolean.java | 16 ++ .../forestry/api/genetics/IAlleleEffect.java | 26 +++ .../forestry/api/genetics/IAlleleFactory.java | 80 +++++++ .../forestry/api/genetics/IAlleleFloat.java | 15 ++ .../forestry/api/genetics/IAlleleFlowers.java | 16 ++ .../forestry/api/genetics/IAlleleHandler.java | 41 ++++ .../forestry/api/genetics/IAlleleInteger.java | 15 ++ .../api/genetics/IAllelePlantType.java | 16 ++ .../api/genetics/IAlleleRegistry.java | 218 ++++++++++++++++++ .../forestry/api/genetics/IAlleleSpecies.java | 115 +++++++++ .../api/genetics/IAlleleSpeciesCustom.java | 23 ++ .../api/genetics/IAlleleTolerance.java | 15 ++ .../api/genetics/IBreedingTracker.java | 93 ++++++++ .../forestry/api/genetics/IChromosome.java | 25 ++ .../api/genetics/IChromosomeType.java | 24 ++ .../api/genetics/IClassification.java | 107 +++++++++ .../forestry/api/genetics/IClimateHelper.java | 53 +++++ .../forestry/api/genetics/IEffectData.java | 27 +++ .../java/forestry/api/genetics/IFlower.java | 20 ++ .../api/genetics/IFlowerGrowthRule.java | 15 ++ .../api/genetics/IFlowerProvider.java | 43 ++++ .../api/genetics/IFlowerRegistry.java | 43 ++++ .../forestry/api/genetics/IFruitBearer.java | 50 ++++ .../forestry/api/genetics/IFruitFamily.java | 32 +++ .../java/forestry/api/genetics/IGenome.java | 30 +++ .../java/forestry/api/genetics/IHousing.java | 57 +++++ .../forestry/api/genetics/IIndividual.java | 53 +++++ .../api/genetics/IIndividualLiving.java | 45 ++++ .../forestry/api/genetics/ILegacyHandler.java | 17 ++ .../java/forestry/api/genetics/IMutation.java | 68 ++++++ .../api/genetics/IMutationCondition.java | 23 ++ .../api/genetics/IMutationCustom.java | 47 ++++ .../forestry/api/genetics/IPollinatable.java | 48 ++++ .../forestry/api/genetics/ISpeciesRoot.java | 163 +++++++++++++ .../forestry/api/genetics/package-info.java | 8 + .../EnumButterflyChromosome.java | 98 ++++++++ .../api/lepidopterology/EnumFlutterType.java | 15 ++ .../IAlleleButterflyEffect.java | 21 ++ .../IAlleleButterflySpecies.java | 59 +++++ .../api/lepidopterology/IButterfly.java | 77 +++++++ .../api/lepidopterology/IButterflyGenome.java | 42 ++++ .../lepidopterology/IButterflyMutation.java | 14 ++ .../lepidopterology/IButterflyNursery.java | 21 ++ .../api/lepidopterology/IButterflyRoot.java | 74 ++++++ .../api/lepidopterology/IEntityButterfly.java | 29 +++ .../ILepidopteristTracker.java | 14 ++ .../api/lepidopterology/package-info.java | 8 + .../java/forestry/api/mail/EnumAddressee.java | 26 +++ .../java/forestry/api/mail/EnumPostage.java | 20 ++ src/api/java/forestry/api/mail/ILetter.java | 59 +++++ .../forestry/api/mail/ILetterHandler.java | 13 ++ .../java/forestry/api/mail/IMailAddress.java | 23 ++ .../java/forestry/api/mail/IPostOffice.java | 30 +++ .../java/forestry/api/mail/IPostRegistry.java | 58 +++++ .../forestry/api/mail/IPostalCarrier.java | 48 ++++ .../java/forestry/api/mail/IPostalState.java | 14 ++ src/api/java/forestry/api/mail/IStamps.java | 14 ++ .../java/forestry/api/mail/ITradeStation.java | 24 ++ .../java/forestry/api/mail/PostManager.java | 11 + .../forestry/api/mail/TradeStationInfo.java | 29 +++ .../java/forestry/api/mail/package-info.java | 8 + .../api/recipes/ICarpenterManager.java | 67 ++++++ .../api/recipes/ICentrifugeManager.java | 79 +++++++ .../api/recipes/ICraftingProvider.java | 17 ++ .../api/recipes/IFabricatorManager.java | 18 ++ .../api/recipes/IFermenterManager.java | 53 +++++ .../api/recipes/IMoistenerManager.java | 33 +++ .../api/recipes/ISqueezerManager.java | 51 ++++ .../forestry/api/recipes/IStillManager.java | 34 +++ .../api/recipes/IVariableFermentable.java | 21 ++ .../forestry/api/recipes/RecipeManagers.java | 45 ++++ .../forestry/api/recipes/package-info.java | 8 + .../forestry/api/storage/BackpackEvent.java | 25 ++ .../forestry/api/storage/BackpackManager.java | 27 +++ .../api/storage/BackpackResupplyEvent.java | 24 ++ .../api/storage/BackpackStowEvent.java | 27 +++ .../api/storage/EnumBackpackType.java | 10 + .../api/storage/IBackpackDefinition.java | 47 ++++ .../api/storage/IBackpackInterface.java | 22 ++ .../forestry/api/storage/ICrateRegistry.java | 32 +++ .../forestry/api/storage/StorageManager.java | 12 + .../forestry/api/storage/package-info.java | 8 + .../java/forestry/api/world/ITreeGenData.java | 30 +++ .../api/world/IWorldGenInterface.java | 22 ++ .../forestry/api/world/WorldGenManager.java | 10 + .../java/forestry/api/world/package-info.java | 8 + .../AlchemicalWizardry.java | 2 +- .../BloodMagicConfiguration.java | 10 +- .../api/sacrifice/PlayerSacrificeHandler.java | 6 +- .../common/items/ItemIncense.java | 23 +- .../common/items/ItemRitualDiviner.java | 5 +- .../common/items/SacrificialDagger.java | 15 +- .../common/items/sigil/DivinationSigil.java | 30 ++- .../common/tileEntity/TECrucible.java | 5 +- .../AlchemyArrays/WellOfSufferingArray.png | Bin 0 -> 119530 bytes 202 files changed, 7108 insertions(+), 35 deletions(-) create mode 100644 src/api/java/forestry/api/apiculture/BeeManager.java create mode 100644 src/api/java/forestry/api/apiculture/EnumBeeChromosome.java create mode 100644 src/api/java/forestry/api/apiculture/EnumBeeType.java create mode 100644 src/api/java/forestry/api/apiculture/FlowerManager.java create mode 100644 src/api/java/forestry/api/apiculture/IAlleleBeeEffect.java create mode 100644 src/api/java/forestry/api/apiculture/IAlleleBeeSpecies.java create mode 100644 src/api/java/forestry/api/apiculture/IAlleleBeeSpeciesCustom.java create mode 100644 src/api/java/forestry/api/apiculture/IAlvearyComponent.java create mode 100644 src/api/java/forestry/api/apiculture/IApiaristTracker.java create mode 100644 src/api/java/forestry/api/apiculture/IArmorApiarist.java create mode 100644 src/api/java/forestry/api/apiculture/IBee.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeFactory.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeGenome.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeHousing.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeIconProvider.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeListener.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeModifier.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeMutation.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeMutationCustom.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeMutationFactory.java create mode 100644 src/api/java/forestry/api/apiculture/IBeeRoot.java create mode 100644 src/api/java/forestry/api/apiculture/IBeekeepingLogic.java create mode 100644 src/api/java/forestry/api/apiculture/IBeekeepingMode.java create mode 100644 src/api/java/forestry/api/apiculture/IHiveDrop.java create mode 100644 src/api/java/forestry/api/apiculture/IHiveFrame.java create mode 100644 src/api/java/forestry/api/apiculture/IJubilanceFactory.java create mode 100644 src/api/java/forestry/api/apiculture/IJubilanceProvider.java create mode 100644 src/api/java/forestry/api/apiculture/hives/HiveManager.java create mode 100644 src/api/java/forestry/api/apiculture/hives/IHiveDescription.java create mode 100644 src/api/java/forestry/api/apiculture/hives/IHiveGen.java create mode 100644 src/api/java/forestry/api/apiculture/hives/IHiveGenHelper.java create mode 100644 src/api/java/forestry/api/apiculture/hives/IHiveRegistry.java create mode 100644 src/api/java/forestry/api/apiculture/hives/package-info.java create mode 100644 src/api/java/forestry/api/apiculture/package-info.java create mode 100644 src/api/java/forestry/api/arboriculture/EnumGermlingType.java create mode 100644 src/api/java/forestry/api/arboriculture/EnumGrowthConditions.java create mode 100644 src/api/java/forestry/api/arboriculture/EnumTreeChromosome.java create mode 100644 src/api/java/forestry/api/arboriculture/IAlleleFruit.java create mode 100644 src/api/java/forestry/api/arboriculture/IAlleleGrowth.java create mode 100644 src/api/java/forestry/api/arboriculture/IAlleleLeafEffect.java create mode 100644 src/api/java/forestry/api/arboriculture/IAlleleTreeSpecies.java create mode 100644 src/api/java/forestry/api/arboriculture/IArboristTracker.java create mode 100644 src/api/java/forestry/api/arboriculture/IFruitProvider.java create mode 100644 src/api/java/forestry/api/arboriculture/IGrowthProvider.java create mode 100644 src/api/java/forestry/api/arboriculture/ILeafTickHandler.java create mode 100644 src/api/java/forestry/api/arboriculture/IToolGrafter.java create mode 100644 src/api/java/forestry/api/arboriculture/ITree.java create mode 100644 src/api/java/forestry/api/arboriculture/ITreeGenome.java create mode 100644 src/api/java/forestry/api/arboriculture/ITreeModifier.java create mode 100644 src/api/java/forestry/api/arboriculture/ITreeMutation.java create mode 100644 src/api/java/forestry/api/arboriculture/ITreeRoot.java create mode 100644 src/api/java/forestry/api/arboriculture/ITreekeepingMode.java create mode 100644 src/api/java/forestry/api/arboriculture/package-info.java create mode 100644 src/api/java/forestry/api/circuits/ChipsetManager.java create mode 100644 src/api/java/forestry/api/circuits/ICircuit.java create mode 100644 src/api/java/forestry/api/circuits/ICircuitBoard.java create mode 100644 src/api/java/forestry/api/circuits/ICircuitLayout.java create mode 100644 src/api/java/forestry/api/circuits/ICircuitLibrary.java create mode 100644 src/api/java/forestry/api/circuits/ICircuitRegistry.java create mode 100644 src/api/java/forestry/api/circuits/ISolderManager.java create mode 100644 src/api/java/forestry/api/circuits/package-info.java create mode 100644 src/api/java/forestry/api/core/BiomeHelper.java create mode 100644 src/api/java/forestry/api/core/EnumHumidity.java create mode 100644 src/api/java/forestry/api/core/EnumTemperature.java create mode 100644 src/api/java/forestry/api/core/ErrorStateRegistry.java create mode 100644 src/api/java/forestry/api/core/ForestryAPI.java create mode 100644 src/api/java/forestry/api/core/ForestryEvent.java create mode 100644 src/api/java/forestry/api/core/IArmorNaturalist.java create mode 100644 src/api/java/forestry/api/core/IErrorState.java create mode 100644 src/api/java/forestry/api/core/IForestryConstants.java create mode 100644 src/api/java/forestry/api/core/IGameMode.java create mode 100644 src/api/java/forestry/api/core/IIconProvider.java create mode 100644 src/api/java/forestry/api/core/INBTTagable.java create mode 100644 src/api/java/forestry/api/core/IStructureLogic.java create mode 100644 src/api/java/forestry/api/core/ITextureManager.java create mode 100644 src/api/java/forestry/api/core/ITileStructure.java create mode 100644 src/api/java/forestry/api/core/IToolPipette.java create mode 100644 src/api/java/forestry/api/core/IToolScoop.java create mode 100644 src/api/java/forestry/api/core/Tabs.java create mode 100644 src/api/java/forestry/api/core/package-info.java create mode 100644 src/api/java/forestry/api/farming/Farmables.java create mode 100644 src/api/java/forestry/api/farming/ICrop.java create mode 100644 src/api/java/forestry/api/farming/IFarmComponent.java create mode 100644 src/api/java/forestry/api/farming/IFarmHousing.java create mode 100644 src/api/java/forestry/api/farming/IFarmInterface.java create mode 100644 src/api/java/forestry/api/farming/IFarmListener.java create mode 100644 src/api/java/forestry/api/farming/IFarmLogic.java create mode 100644 src/api/java/forestry/api/farming/IFarmable.java create mode 100644 src/api/java/forestry/api/farming/package-info.java create mode 100644 src/api/java/forestry/api/food/BeverageManager.java create mode 100644 src/api/java/forestry/api/food/IBeverageEffect.java create mode 100644 src/api/java/forestry/api/food/IInfuserManager.java create mode 100644 src/api/java/forestry/api/food/IIngredientManager.java create mode 100644 src/api/java/forestry/api/food/package-info.java create mode 100644 src/api/java/forestry/api/fuels/EngineBronzeFuel.java create mode 100644 src/api/java/forestry/api/fuels/EngineCopperFuel.java create mode 100644 src/api/java/forestry/api/fuels/FermenterFuel.java create mode 100644 src/api/java/forestry/api/fuels/FuelManager.java create mode 100644 src/api/java/forestry/api/fuels/GeneratorFuel.java create mode 100644 src/api/java/forestry/api/fuels/MoistenerFuel.java create mode 100644 src/api/java/forestry/api/fuels/RainSubstrate.java create mode 100644 src/api/java/forestry/api/fuels/package-info.java create mode 100644 src/api/java/forestry/api/genetics/AlleleManager.java create mode 100644 src/api/java/forestry/api/genetics/EnumTolerance.java create mode 100644 src/api/java/forestry/api/genetics/IAllele.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleArea.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleBoolean.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleEffect.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleFactory.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleFloat.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleFlowers.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleHandler.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleInteger.java create mode 100644 src/api/java/forestry/api/genetics/IAllelePlantType.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleRegistry.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleSpecies.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleSpeciesCustom.java create mode 100644 src/api/java/forestry/api/genetics/IAlleleTolerance.java create mode 100644 src/api/java/forestry/api/genetics/IBreedingTracker.java create mode 100644 src/api/java/forestry/api/genetics/IChromosome.java create mode 100644 src/api/java/forestry/api/genetics/IChromosomeType.java create mode 100644 src/api/java/forestry/api/genetics/IClassification.java create mode 100644 src/api/java/forestry/api/genetics/IClimateHelper.java create mode 100644 src/api/java/forestry/api/genetics/IEffectData.java create mode 100644 src/api/java/forestry/api/genetics/IFlower.java create mode 100644 src/api/java/forestry/api/genetics/IFlowerGrowthRule.java create mode 100644 src/api/java/forestry/api/genetics/IFlowerProvider.java create mode 100644 src/api/java/forestry/api/genetics/IFlowerRegistry.java create mode 100644 src/api/java/forestry/api/genetics/IFruitBearer.java create mode 100644 src/api/java/forestry/api/genetics/IFruitFamily.java create mode 100644 src/api/java/forestry/api/genetics/IGenome.java create mode 100644 src/api/java/forestry/api/genetics/IHousing.java create mode 100644 src/api/java/forestry/api/genetics/IIndividual.java create mode 100644 src/api/java/forestry/api/genetics/IIndividualLiving.java create mode 100644 src/api/java/forestry/api/genetics/ILegacyHandler.java create mode 100644 src/api/java/forestry/api/genetics/IMutation.java create mode 100644 src/api/java/forestry/api/genetics/IMutationCondition.java create mode 100644 src/api/java/forestry/api/genetics/IMutationCustom.java create mode 100644 src/api/java/forestry/api/genetics/IPollinatable.java create mode 100644 src/api/java/forestry/api/genetics/ISpeciesRoot.java create mode 100644 src/api/java/forestry/api/genetics/package-info.java create mode 100644 src/api/java/forestry/api/lepidopterology/EnumButterflyChromosome.java create mode 100644 src/api/java/forestry/api/lepidopterology/EnumFlutterType.java create mode 100644 src/api/java/forestry/api/lepidopterology/IAlleleButterflyEffect.java create mode 100644 src/api/java/forestry/api/lepidopterology/IAlleleButterflySpecies.java create mode 100644 src/api/java/forestry/api/lepidopterology/IButterfly.java create mode 100644 src/api/java/forestry/api/lepidopterology/IButterflyGenome.java create mode 100644 src/api/java/forestry/api/lepidopterology/IButterflyMutation.java create mode 100644 src/api/java/forestry/api/lepidopterology/IButterflyNursery.java create mode 100644 src/api/java/forestry/api/lepidopterology/IButterflyRoot.java create mode 100644 src/api/java/forestry/api/lepidopterology/IEntityButterfly.java create mode 100644 src/api/java/forestry/api/lepidopterology/ILepidopteristTracker.java create mode 100644 src/api/java/forestry/api/lepidopterology/package-info.java create mode 100644 src/api/java/forestry/api/mail/EnumAddressee.java create mode 100644 src/api/java/forestry/api/mail/EnumPostage.java create mode 100644 src/api/java/forestry/api/mail/ILetter.java create mode 100644 src/api/java/forestry/api/mail/ILetterHandler.java create mode 100644 src/api/java/forestry/api/mail/IMailAddress.java create mode 100644 src/api/java/forestry/api/mail/IPostOffice.java create mode 100644 src/api/java/forestry/api/mail/IPostRegistry.java create mode 100644 src/api/java/forestry/api/mail/IPostalCarrier.java create mode 100644 src/api/java/forestry/api/mail/IPostalState.java create mode 100644 src/api/java/forestry/api/mail/IStamps.java create mode 100644 src/api/java/forestry/api/mail/ITradeStation.java create mode 100644 src/api/java/forestry/api/mail/PostManager.java create mode 100644 src/api/java/forestry/api/mail/TradeStationInfo.java create mode 100644 src/api/java/forestry/api/mail/package-info.java create mode 100644 src/api/java/forestry/api/recipes/ICarpenterManager.java create mode 100644 src/api/java/forestry/api/recipes/ICentrifugeManager.java create mode 100644 src/api/java/forestry/api/recipes/ICraftingProvider.java create mode 100644 src/api/java/forestry/api/recipes/IFabricatorManager.java create mode 100644 src/api/java/forestry/api/recipes/IFermenterManager.java create mode 100644 src/api/java/forestry/api/recipes/IMoistenerManager.java create mode 100644 src/api/java/forestry/api/recipes/ISqueezerManager.java create mode 100644 src/api/java/forestry/api/recipes/IStillManager.java create mode 100644 src/api/java/forestry/api/recipes/IVariableFermentable.java create mode 100644 src/api/java/forestry/api/recipes/RecipeManagers.java create mode 100644 src/api/java/forestry/api/recipes/package-info.java create mode 100644 src/api/java/forestry/api/storage/BackpackEvent.java create mode 100644 src/api/java/forestry/api/storage/BackpackManager.java create mode 100644 src/api/java/forestry/api/storage/BackpackResupplyEvent.java create mode 100644 src/api/java/forestry/api/storage/BackpackStowEvent.java create mode 100644 src/api/java/forestry/api/storage/EnumBackpackType.java create mode 100644 src/api/java/forestry/api/storage/IBackpackDefinition.java create mode 100644 src/api/java/forestry/api/storage/IBackpackInterface.java create mode 100644 src/api/java/forestry/api/storage/ICrateRegistry.java create mode 100644 src/api/java/forestry/api/storage/StorageManager.java create mode 100644 src/api/java/forestry/api/storage/package-info.java create mode 100644 src/api/java/forestry/api/world/ITreeGenData.java create mode 100644 src/api/java/forestry/api/world/IWorldGenInterface.java create mode 100644 src/api/java/forestry/api/world/WorldGenManager.java create mode 100644 src/api/java/forestry/api/world/package-info.java create mode 100644 src/main/resources/assets/alchemicalwizardry/textures/models/AlchemyArrays/WellOfSufferingArray.png diff --git a/build.properties b/build.properties index f16ca60b..f910d56d 100644 --- a/build.properties +++ b/build.properties @@ -1,5 +1,5 @@ # -#Sat May 02 16:08:45 EDT 2015 +#Fri May 08 12:08:25 EDT 2015 mod_name=BloodMagic forge_version=10.13.3.1374-1.7.10 ccc_version=1.0.4.29 @@ -10,4 +10,4 @@ package_group=com.wayoftime.bloodmagic mod_version=1.3.2aBeta minetweaker_version=Dev-1.7.10-3.0.9B mc_version=1.7.10 -build_number=5 +build_number=7 diff --git a/src/api/java/forestry/api/apiculture/BeeManager.java b/src/api/java/forestry/api/apiculture/BeeManager.java new file mode 100644 index 00000000..80b03a46 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/BeeManager.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.item.ItemStack; +/** + * + * Some miscellaneous lists and settings for bees. + * + * @author SirSengir + */ +public class BeeManager { + + /** + * 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(); + + /** + * Convenient access to AlleleManager.alleleRegistry.getSpeciesRoot("rootBees") + */ + public static IBeeRoot beeRoot; + + /** + * Used to create new bees. + */ + public static IBeeFactory beeFactory; + + /** + * Used to create new bee mutations. + */ + public static IBeeMutationFactory beeMutationFactory; + + /** + * Used to get Forestry's jubilance implementations. + */ + public static IJubilanceFactory jubilanceFactory; +} diff --git a/src/api/java/forestry/api/apiculture/EnumBeeChromosome.java b/src/api/java/forestry/api/apiculture/EnumBeeChromosome.java new file mode 100644 index 00000000..165247ef --- /dev/null +++ b/src/api/java/forestry/api/apiculture/EnumBeeChromosome.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +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 BeeManager.beeRoot; + } +} diff --git a/src/api/java/forestry/api/apiculture/EnumBeeType.java b/src/api/java/forestry/api/apiculture/EnumBeeType.java new file mode 100644 index 00000000..e3e45c2b --- /dev/null +++ b/src/api/java/forestry/api/apiculture/EnumBeeType.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 = this.toString().toLowerCase(Locale.ENGLISH); + } + + public String getName() { + return name; + } +} diff --git a/src/api/java/forestry/api/apiculture/FlowerManager.java b/src/api/java/forestry/api/apiculture/FlowerManager.java new file mode 100644 index 00000000..667b4489 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/FlowerManager.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IFlowerProvider; +import forestry.api.genetics.IFlowerRegistry; + +public class FlowerManager { + /** + * ItemStacks representing simple flower blocks. Meta-sensitive, processed by the basic {@link IFlowerProvider}. + * + * @deprecated since Forestry 3.4. Use {@link #IFlowerRegistry.registerPlantableFlower(ItemStack flower, double weight, String... flowerTypes)} instead. + *
e.g. FlowerManager.flowerRegister.registerPlantableFlower(new ItemStack(Blocks.red_flower), 1.0, FlowerManager.FlowerTypeVanilla, FlowerManager.FlowerTypeSnow);
+ */ + @Deprecated + public static ArrayList plainFlowers = new ArrayList(); + + /** + *
e.g. FlowerManager.flowerRegister.registerPlantableFlower(new ItemStack(Blocks.red_flower), 1.0, FlowerManager.FlowerTypeVanilla, FlowerManager.FlowerTypeSnow);
+ */ + public static IFlowerRegistry flowerRegistry; + + public static final String FlowerTypeVanilla = "flowersVanilla"; + public static final String FlowerTypeNether = "flowersNether"; + public static final String FlowerTypeCacti = "flowersCacti"; + public static final String FlowerTypeMushrooms = "flowersMushrooms"; + public static final String FlowerTypeEnd = "flowersEnd"; + public static final String FlowerTypeJungle = "flowersJungle"; + public static final String FlowerTypeSnow = "flowersSnow"; + public static final String FlowerTypeWheat = "flowersWheat"; + public static final String FlowerTypeGourd = "flowersGourd"; +} diff --git a/src/api/java/forestry/api/apiculture/IAlleleBeeEffect.java b/src/api/java/forestry/api/apiculture/IAlleleBeeEffect.java new file mode 100644 index 00000000..b2dddb31 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IAlleleBeeEffect.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IAlleleBeeSpecies.java b/src/api/java/forestry/api/apiculture/IAlleleBeeSpecies.java new file mode 100644 index 00000000..86346639 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IAlleleBeeSpecies.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 - 1] + */ + Map getProductChances(); + + /** + * @return Map of possible specialities with the chance for drop each bee cycle. (0 - 1] + */ + Map getSpecialtyChances(); + + /** + * 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); + + /** + * @deprecated since Forestry 3.6. + * @return Path of the texture to use for entity rendering. + */ + @Deprecated + String getEntityTexture(); + + /** + * @deprecated Since Forestry 3.6 use getProductChances() + * @return Map of possible products with the chance for drop each bee cycle. (0 - 100) + */ + @Deprecated + Map getProducts(); + + /** + * @deprecated Since Forestry 3.6 use getSpecialtyChances() + * @return Map of possible specialities with the chance for drop each bee cycle. (0 - 100) + */ + @Deprecated + Map getSpecialty(); +} diff --git a/src/api/java/forestry/api/apiculture/IAlleleBeeSpeciesCustom.java b/src/api/java/forestry/api/apiculture/IAlleleBeeSpeciesCustom.java new file mode 100644 index 00000000..06664b2f --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IAlleleBeeSpeciesCustom.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import net.minecraft.item.ItemStack; + +import forestry.api.genetics.IAlleleSpeciesCustom; + +public interface IAlleleBeeSpeciesCustom extends IAlleleBeeSpecies, IAlleleSpeciesCustom { + + /** + * Add a product for this bee species. + * Chance is between 0 and 1. + */ + IAlleleBeeSpeciesCustom addProduct(ItemStack product, Float chance); + + /** + * Add a specialty product for this bee species. + * Bees only produce their specialty when they are Jubilant (see IJubilanceProvider) + * Chance is between 0 and 1. + */ + IAlleleBeeSpeciesCustom addSpecialty(ItemStack specialty, Float chance); + + /** + * Set the Jubilance Provider for this bee species. + * Bees only produce their specialty when they are Jubilant (see IJubilanceProvider) + */ + IAlleleBeeSpeciesCustom setJubilanceProvider(IJubilanceProvider provider); + + /** + * Make this species only active at night. + */ + IAlleleBeeSpeciesCustom setNocturnal(); + + /** Use this if you have custom icons for bees. */ + IAlleleBeeSpeciesCustom setCustomBeeIconProvider(IBeeIconProvider beeIconProvider); +} diff --git a/src/api/java/forestry/api/apiculture/IAlvearyComponent.java b/src/api/java/forestry/api/apiculture/IAlvearyComponent.java new file mode 100644 index 00000000..80cf98b1 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IAlvearyComponent.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IApiaristTracker.java b/src/api/java/forestry/api/apiculture/IApiaristTracker.java new file mode 100644 index 00000000..0c65f56b --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IApiaristTracker.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IArmorApiarist.java b/src/api/java/forestry/api/apiculture/IArmorApiarist.java new file mode 100644 index 00000000..fef81eb5 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IArmorApiarist.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IBee.java b/src/api/java/forestry/api/apiculture/IBee.java new file mode 100644 index 00000000..b77b752e --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBee.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.IErrorState; +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); + + 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 the error code encountered. + */ + IErrorState canWork(IBeeHousing housing); + + boolean hasFlower(IBeeHousing housing); + + ArrayList getSuitableBiomes(); + + 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/src/api/java/forestry/api/apiculture/IBeeFactory.java b/src/api/java/forestry/api/apiculture/IBeeFactory.java new file mode 100644 index 00000000..c164731c --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeFactory.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.IClassification; + +public interface IBeeFactory { + + /** + * Creates a new bee species. + * Automatically registered with AlleleManager.alleleRegistry.registerAllele() + * See IAlleleBeeSpeciesCustom and IAlleleSpeciesCustom for adding additional properties to the returned species. + * + * @param uid Unique Identifier for this species + * @param dominant Whether this species is genetically dominant (false means it is recessive) + * @param authority Authority for the binomial name, e.g. "Sengir" on species of base Forestry. + * @param unlocalizedName Unlocalized name for this species + * @param unlocalizedDescription Unlocalized description for this species + * @param branch Classification of this species + * @param binomial Binomial name of the species sans genus ("Apis"). "humboldti" will have the bee species flavour name be "Apis humboldti". Feel free to use fun names or null. + * @param primaryColor The outline color of this species + * @param secondaryColor The body color of this species + * @return a new bee species allele. + */ + IAlleleBeeSpeciesCustom createSpecies(String uid, boolean dominant, String authority, String unlocalizedName, String unlocalizedDescription, IClassification branch, String binomial, int primaryColor, int secondaryColor); + + /** + * Creates a new bee branch. + * Must be registered with AlleleManager.alleleRegistry.getClassification("family.apidae").addMemberGroup(); + * + * @param uid Unique Identifier for this branch + * @param scientific approximates a "genus" in real life. Real life examples: "Micrapis", "Megapis" + * @return a new bee branch + */ + IClassification createBranch(String uid, String scientific); +} diff --git a/src/api/java/forestry/api/apiculture/IBeeGenome.java b/src/api/java/forestry/api/apiculture/IBeeGenome.java new file mode 100644 index 00000000..642eeeb5 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeGenome.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IBeeHousing.java b/src/api/java/forestry/api/apiculture/IBeeHousing.java new file mode 100644 index 00000000..5d795a3b --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeHousing.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IBeeIconProvider.java b/src/api/java/forestry/api/apiculture/IBeeIconProvider.java new file mode 100644 index 00000000..d29a722b --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeIconProvider.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.util.IIcon; + +public interface IBeeIconProvider { + void registerIcons(IIconRegister register); + IIcon getIcon(EnumBeeType type, int renderPass); +} diff --git a/src/api/java/forestry/api/apiculture/IBeeListener.java b/src/api/java/forestry/api/apiculture/IBeeListener.java new file mode 100644 index 00000000..7fd5865c --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeListener.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IBeeModifier.java b/src/api/java/forestry/api/apiculture/IBeeModifier.java new file mode 100644 index 00000000..4f9f7bbe --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeModifier.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IBeeMutation.java b/src/api/java/forestry/api/apiculture/IBeeMutation.java new file mode 100644 index 00000000..6421c8f6 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeMutation.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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! + * @deprecated since Forestry 3.6, use the IAlleleBeeSpecies / IBeeGenome version + */ + @Deprecated + float getChance(IBeeHousing housing, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1); + + float getChance(IBeeHousing housing, IAlleleBeeSpecies allele0, IAlleleBeeSpecies allele1, IBeeGenome genome0, IBeeGenome genome1); +} diff --git a/src/api/java/forestry/api/apiculture/IBeeMutationCustom.java b/src/api/java/forestry/api/apiculture/IBeeMutationCustom.java new file mode 100644 index 00000000..d97a839a --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeMutationCustom.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.IMutationCustom; + +public interface IBeeMutationCustom extends IBeeMutation, IMutationCustom { + +} diff --git a/src/api/java/forestry/api/apiculture/IBeeMutationFactory.java b/src/api/java/forestry/api/apiculture/IBeeMutationFactory.java new file mode 100644 index 00000000..315a4c6f --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeMutationFactory.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import forestry.api.genetics.IAllele; + +public interface IBeeMutationFactory { + /** + * Creates a new bee mutation. + * Automatically registered with BeeManager.beeRoot.registerMutation() + * See IBeeMutationCustom and IMutationCustom for adding additional properties to the returned mutation. + * + * @param parentBee0 A parent bee for this mutation + * @param parentBee1 A parent bee for this mutation + * @param result The resulting alleles for this mutation + * @param chance The chance that breeding the two parent bees will result in this mutation + * @return a new bee mutation. + */ + IBeeMutationCustom createMutation(IAlleleBeeSpecies parentBee0, IAlleleBeeSpecies parentBee1, IAllele[] result, int chance); +} diff --git a/src/api/java/forestry/api/apiculture/IBeeRoot.java b/src/api/java/forestry/api/apiculture/IBeeRoot.java new file mode 100644 index 00000000..b4bbb291 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeeRoot.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 com.mojang.authlib.GameProfile; + +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 + */ + @Override + boolean isMember(ItemStack stack); + + /** + * @return {@link IBee} pattern parsed from the passed stack's nbt data. + */ + @Override + IBee getMember(ItemStack stack); + + @Override + IBee getMember(NBTTagCompound compound); + + /* GENOME CONVERSION */ + @Override + IBee templateAsIndividual(IAllele[] template); + + @Override + IBee templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive); + + @Override + IBeeGenome templateAsGenome(IAllele[] template); + + @Override + IBeeGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive); + + /* BREEDING TRACKER */ + /** + * @param world + * @return {@link IApiaristTracker} associated with the passed world. + */ + IApiaristTracker getBreedingTracker(World world, GameProfile 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 */ + @Override + ArrayList getIndividualTemplates(); + + /* MUTATIONS */ + @Override + 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/src/api/java/forestry/api/apiculture/IBeekeepingLogic.java b/src/api/java/forestry/api/apiculture/IBeekeepingLogic.java new file mode 100644 index 00000000..0a4da7b3 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeekeepingLogic.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IBeekeepingMode.java b/src/api/java/forestry/api/apiculture/IBeekeepingMode.java new file mode 100644 index 00000000..80d30981 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IBeekeepingMode.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IHiveDrop.java b/src/api/java/forestry/api/apiculture/IHiveDrop.java new file mode 100644 index 00000000..ea175f8b --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IHiveDrop.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 with HiveManager.get___Hive.addDrop + * + * @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/src/api/java/forestry/api/apiculture/IHiveFrame.java b/src/api/java/forestry/api/apiculture/IHiveFrame.java new file mode 100644 index 00000000..dabc9e01 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IHiveFrame.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/apiculture/IJubilanceFactory.java b/src/api/java/forestry/api/apiculture/IJubilanceFactory.java new file mode 100644 index 00000000..1b81a9d0 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IJubilanceFactory.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +import net.minecraft.block.Block; + +public interface IJubilanceFactory { + /** The default Jubilance Provider is satisfied when the humidity and temperature are ideal for the bee. */ + IJubilanceProvider getDefault(); + + /** The Requires Resource Jubilance Provider is satisfied when a specific block is under the hive. */ + IJubilanceProvider getRequiresResource(Block block, int meta); +} diff --git a/src/api/java/forestry/api/apiculture/IJubilanceProvider.java b/src/api/java/forestry/api/apiculture/IJubilanceProvider.java new file mode 100644 index 00000000..faf34d05 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/IJubilanceProvider.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture; + +public interface IJubilanceProvider { + + /** + * Returns true when conditions are right to make this species Jubilant. + * Jubilant bees can produce their Specialty products. + */ + boolean isJubilant(IAlleleBeeSpecies species, IBeeGenome genome, IBeeHousing housing); +} diff --git a/src/api/java/forestry/api/apiculture/hives/HiveManager.java b/src/api/java/forestry/api/apiculture/hives/HiveManager.java new file mode 100644 index 00000000..17ca7d20 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/hives/HiveManager.java @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture.hives; + +public class HiveManager { + + public static IHiveRegistry hiveRegistry; + public static IHiveGenHelper genHelper; + +} diff --git a/src/api/java/forestry/api/apiculture/hives/IHiveDescription.java b/src/api/java/forestry/api/apiculture/hives/IHiveDescription.java new file mode 100644 index 00000000..82d761db --- /dev/null +++ b/src/api/java/forestry/api/apiculture/hives/IHiveDescription.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture.hives; + +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public interface IHiveDescription { + + /** + * The hive generator for this hive. + */ + IHiveGen getHiveGen(); + + /** + * The hive block to be placed in the world. + */ + Block getBlock(); + int getMeta(); + + /** + * returns true if the hive can be generated in these conditions. + * Used as a fast early-elimination check for hives that have no hope of spawning in the area. + */ + boolean isGoodBiome(BiomeGenBase biome); + boolean isGoodHumidity(EnumHumidity humidity); + boolean isGoodTemperature(EnumTemperature temperature); + + /** + * float representing the relative chance a hive will generate in a chunk. + * Default is 1.0, higher numbers result in more hives, smaller will result in fewer. + * Tree hives want around 3.0 to 4.0 since there are less locations to generate on. + */ + float getGenChance(); + + /** + * Called after successful hive generation. + * world, x, y, z give the location of the new hive. + **/ + void postGen(World world, int x, int y, int z); +} diff --git a/src/api/java/forestry/api/apiculture/hives/IHiveGen.java b/src/api/java/forestry/api/apiculture/hives/IHiveGen.java new file mode 100644 index 00000000..57569d26 --- /dev/null +++ b/src/api/java/forestry/api/apiculture/hives/IHiveGen.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture.hives; + +import net.minecraft.world.World; + +public interface IHiveGen { + + /** + * return a Y value that the hive should try to generate at. + * returns negative if the hive can't be placed anywhere. + */ + int getYForHive(World world, int x, int z); + + /** + * returns true if the hive can be generated at this location. + * Used for advanced conditions, like checking that the ground below the hive is a certain type. + */ + boolean isValidLocation(World world, int x, int y, int z); + + /** + * returns true if the hive can safely replace the block at this location. + */ + boolean canReplace(World world, int x, int y, int z); + +} diff --git a/src/api/java/forestry/api/apiculture/hives/IHiveGenHelper.java b/src/api/java/forestry/api/apiculture/hives/IHiveGenHelper.java new file mode 100644 index 00000000..0eb6400c --- /dev/null +++ b/src/api/java/forestry/api/apiculture/hives/IHiveGenHelper.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture.hives; + +import net.minecraft.block.Block; + +public interface IHiveGenHelper { + + /** + * Returns a hiveGen for a hive that spawns on the ground. + * validGroundBlocks specifies which block materials it can spawn on. + */ + IHiveGen ground(Block... validGroundBlocks); + + /** + * Returns a hiveGen for a hive that spawns in trees. + */ + IHiveGen tree(); + +} diff --git a/src/api/java/forestry/api/apiculture/hives/IHiveRegistry.java b/src/api/java/forestry/api/apiculture/hives/IHiveRegistry.java new file mode 100644 index 00000000..73f3524c --- /dev/null +++ b/src/api/java/forestry/api/apiculture/hives/IHiveRegistry.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.apiculture.hives; + +import java.util.List; + +import forestry.api.apiculture.IHiveDrop; + +public interface IHiveRegistry { + + /* Forestry Hive Names */ + public static final String forest = "Forestry:forest"; + public static final String meadows = "Forestry:meadows"; + public static final String desert = "Forestry:desert"; + public static final String jungle = "Forestry:jungle"; + public static final String end = "Forestry:end"; + public static final String snow = "Forestry:snow"; + public static final String swamp = "Forestry:swamp"; + + /** + * Adds a new hive to be generated in the world. + */ + void registerHive(String hiveName, IHiveDescription hiveDescription); + + /** + * Add drops to a registered hive. + */ + void addDrops(String hiveName, IHiveDrop... drops); + void addDrops(String hiveName, List drop); +} diff --git a/src/api/java/forestry/api/apiculture/hives/package-info.java b/src/api/java/forestry/api/apiculture/hives/package-info.java new file mode 100644 index 00000000..a045530c --- /dev/null +++ b/src/api/java/forestry/api/apiculture/hives/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="4.1.0", owner="ForestryAPI|apiculture", provides="ForestryAPI|hives") +package forestry.api.apiculture.hives; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/apiculture/package-info.java b/src/api/java/forestry/api/apiculture/package-info.java new file mode 100644 index 00000000..3114e3eb --- /dev/null +++ b/src/api/java/forestry/api/apiculture/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="3.3.0", owner="ForestryAPI|core", provides="ForestryAPI|apiculture") +package forestry.api.apiculture; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/arboriculture/EnumGermlingType.java b/src/api/java/forestry/api/arboriculture/EnumGermlingType.java new file mode 100644 index 00000000..a564be0d --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/EnumGermlingType.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.arboriculture; + +public enum EnumGermlingType { + SAPLING("sapling"), BLOSSOM("blossom"), POLLEN("pollen"), GERMLING("germling"), NONE("none"); + + public static final EnumGermlingType[] VALUES = values(); + + private final String name; + + private EnumGermlingType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + +} diff --git a/src/api/java/forestry/api/arboriculture/EnumGrowthConditions.java b/src/api/java/forestry/api/arboriculture/EnumGrowthConditions.java new file mode 100644 index 00000000..8b28601c --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/EnumGrowthConditions.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.arboriculture; + +public enum EnumGrowthConditions { + HOSTILE, PALTRY, NORMAL, GOOD, EXCELLENT +} diff --git a/src/api/java/forestry/api/arboriculture/EnumTreeChromosome.java b/src/api/java/forestry/api/arboriculture/EnumTreeChromosome.java new file mode 100644 index 00000000..8f74d0c2 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/EnumTreeChromosome.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.arboriculture; + +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.IAlleleInteger; +import forestry.api.genetics.IAllelePlantType; +import forestry.api.genetics.IChromosomeType; +import forestry.api.genetics.IFruitFamily; +import forestry.api.genetics.ISpeciesRoot; +import net.minecraftforge.common.EnumPlantType; + +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), + /** + * Determines if the tree can burn. + */ + FIREPROOF(IAlleleBoolean.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/src/api/java/forestry/api/arboriculture/IAlleleFruit.java b/src/api/java/forestry/api/arboriculture/IAlleleFruit.java new file mode 100644 index 00000000..0f54db51 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IAlleleFruit.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/IAlleleGrowth.java b/src/api/java/forestry/api/arboriculture/IAlleleGrowth.java new file mode 100644 index 00000000..6cb4b438 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IAlleleGrowth.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/IAlleleLeafEffect.java b/src/api/java/forestry/api/arboriculture/IAlleleLeafEffect.java new file mode 100644 index 00000000..d52d963a --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IAlleleLeafEffect.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/IAlleleTreeSpecies.java b/src/api/java/forestry/api/arboriculture/IAlleleTreeSpecies.java new file mode 100644 index 00000000..be057254 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IAlleleTreeSpecies.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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(); + + /** + * @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/src/api/java/forestry/api/arboriculture/IArboristTracker.java b/src/api/java/forestry/api/arboriculture/IArboristTracker.java new file mode 100644 index 00000000..9777e876 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IArboristTracker.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.arboriculture; + +import forestry.api.genetics.IBreedingTracker; + +public interface IArboristTracker extends IBreedingTracker { + +} diff --git a/src/api/java/forestry/api/arboriculture/IFruitProvider.java b/src/api/java/forestry/api/arboriculture/IFruitProvider.java new file mode 100644 index 00000000..ef54fc99 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IFruitProvider.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/IGrowthProvider.java b/src/api/java/forestry/api/arboriculture/IGrowthProvider.java new file mode 100644 index 00000000..92e553e0 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IGrowthProvider.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/ILeafTickHandler.java b/src/api/java/forestry/api/arboriculture/ILeafTickHandler.java new file mode 100644 index 00000000..4d7fba44 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/ILeafTickHandler.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/IToolGrafter.java b/src/api/java/forestry/api/arboriculture/IToolGrafter.java new file mode 100644 index 00000000..339725e6 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IToolGrafter.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/ITree.java b/src/api/java/forestry/api/arboriculture/ITree.java new file mode 100644 index 00000000..5cbd736f --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/ITree.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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; +import forestry.api.world.ITreeGenData; + +public interface ITree extends IIndividual, ITreeGenData { + + 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/src/api/java/forestry/api/arboriculture/ITreeGenome.java b/src/api/java/forestry/api/arboriculture/ITreeGenome.java new file mode 100644 index 00000000..ee5a1f02 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/ITreeGenome.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/ITreeModifier.java b/src/api/java/forestry/api/arboriculture/ITreeModifier.java new file mode 100644 index 00000000..775f91eb --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/ITreeModifier.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/ITreeMutation.java b/src/api/java/forestry/api/arboriculture/ITreeMutation.java new file mode 100644 index 00000000..65804969 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/ITreeMutation.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/ITreeRoot.java b/src/api/java/forestry/api/arboriculture/ITreeRoot.java new file mode 100644 index 00000000..e966ca04 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/ITreeRoot.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 com.mojang.authlib.GameProfile; + +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 { + + @Override + boolean isMember(ItemStack itemstack); + + @Override + ITree getMember(ItemStack itemstack); + + @Override + ITree getMember(NBTTagCompound compound); + + @Override + ITree templateAsIndividual(IAllele[] template); + + @Override + ITree templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive); + + @Override + ITreeGenome templateAsGenome(IAllele[] template); + + @Override + ITreeGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive); + + /** + * @param world + * @return {@link IArboristTracker} associated with the passed world. + */ + @Override + IArboristTracker getBreedingTracker(World world, GameProfile 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, GameProfile owner, int x, int y, int z); + + /** + * @deprecated since Forestry 3.5.0. Use ITreeGenData setLeavesDecorative. + */ + @Deprecated + // decorative=true for creative and player-placed leaves. No decay, pollination, or drops. + boolean setLeaves(World world, IIndividual tree, GameProfile owner, int x, int y, int z, boolean decorative); + + /** + * @deprecated since Forestry 3.5.0. Use ITreeGenData setLeaves. + */ + @Deprecated + // set normal leaves created as worldgen + boolean setLeaves(World world, IIndividual tree, GameProfile owner, int x, int y, int z); + + @Override + IChromosome[] templateAsChromosomes(IAllele[] template); + + @Override + 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 */ + @Override + ArrayList getIndividualTemplates(); + + /* MUTATIONS */ + @Override + Collection getMutations(boolean shuffle); + +} diff --git a/src/api/java/forestry/api/arboriculture/ITreekeepingMode.java b/src/api/java/forestry/api/arboriculture/ITreekeepingMode.java new file mode 100644 index 00000000..cc5224d8 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/ITreekeepingMode.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/arboriculture/package-info.java b/src/api/java/forestry/api/arboriculture/package-info.java new file mode 100644 index 00000000..de961141 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="2.3.0", owner="ForestryAPI|core", provides="ForestryAPI|arboriculture") +package forestry.api.arboriculture; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/circuits/ChipsetManager.java b/src/api/java/forestry/api/circuits/ChipsetManager.java new file mode 100644 index 00000000..c5f0db5c --- /dev/null +++ b/src/api/java/forestry/api/circuits/ChipsetManager.java @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.circuits; + +public class ChipsetManager { + + public static ISolderManager solderManager; + public static ICircuitRegistry circuitRegistry; + +} diff --git a/src/api/java/forestry/api/circuits/ICircuit.java b/src/api/java/forestry/api/circuits/ICircuit.java new file mode 100644 index 00000000..01b7e79d --- /dev/null +++ b/src/api/java/forestry/api/circuits/ICircuit.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/circuits/ICircuitBoard.java b/src/api/java/forestry/api/circuits/ICircuitBoard.java new file mode 100644 index 00000000..3b424d75 --- /dev/null +++ b/src/api/java/forestry/api/circuits/ICircuitBoard.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/circuits/ICircuitLayout.java b/src/api/java/forestry/api/circuits/ICircuitLayout.java new file mode 100644 index 00000000..e90853b9 --- /dev/null +++ b/src/api/java/forestry/api/circuits/ICircuitLayout.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.circuits; + +public interface ICircuitLayout { + + String getUID(); + + String getName(); + + String getUsage(); + +} diff --git a/src/api/java/forestry/api/circuits/ICircuitLibrary.java b/src/api/java/forestry/api/circuits/ICircuitLibrary.java new file mode 100644 index 00000000..0d65ba45 --- /dev/null +++ b/src/api/java/forestry/api/circuits/ICircuitLibrary.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.circuits; + +public interface ICircuitLibrary { + +} diff --git a/src/api/java/forestry/api/circuits/ICircuitRegistry.java b/src/api/java/forestry/api/circuits/ICircuitRegistry.java new file mode 100644 index 00000000..9fb2b94d --- /dev/null +++ b/src/api/java/forestry/api/circuits/ICircuitRegistry.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.circuits; + +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface ICircuitRegistry { + + /* CIRCUITS */ + Map getRegisteredCircuits(); + + void registerCircuit(ICircuit circuit); + + ICircuit getCircuit(String uid); + + ICircuitLibrary getCircuitLibrary(World world, String playername); + + /* LAYOUTS */ + Map getRegisteredLayouts(); + + void registerLayout(ICircuitLayout layout); + + ICircuitLayout getLayout(String uid); + + ICircuitLayout getDefaultLayout(); + + ICircuitBoard getCircuitboard(ItemStack itemstack); + + boolean isChipset(ItemStack itemstack); + +} diff --git a/src/api/java/forestry/api/circuits/ISolderManager.java b/src/api/java/forestry/api/circuits/ISolderManager.java new file mode 100644 index 00000000..af9b41f1 --- /dev/null +++ b/src/api/java/forestry/api/circuits/ISolderManager.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.circuits; + +import net.minecraft.item.ItemStack; + +public interface ISolderManager { + + void addRecipe(ICircuitLayout layout, ItemStack resource, ICircuit circuit); + +} diff --git a/src/api/java/forestry/api/circuits/package-info.java b/src/api/java/forestry/api/circuits/package-info.java new file mode 100644 index 00000000..88612198 --- /dev/null +++ b/src/api/java/forestry/api/circuits/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="2.0.0", owner="ForestryAPI|core", provides="ForestryAPI|circuits") +package forestry.api.circuits; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/core/BiomeHelper.java b/src/api/java/forestry/api/core/BiomeHelper.java new file mode 100644 index 00000000..bc20cd66 --- /dev/null +++ b/src/api/java/forestry/api/core/BiomeHelper.java @@ -0,0 +1,36 @@ +package forestry.api.core; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.world.biome.BiomeGenBase; + +import net.minecraftforge.common.BiomeDictionary; + +public class BiomeHelper { + + private static final Map isBiomeHellishCache = new HashMap(); + + /** + * Determines if it can rain or snow in the given biome. + */ + public static boolean canRainOrSnow(BiomeGenBase biomeGenBase) { + return biomeGenBase.getEnableSnow() || biomeGenBase.canSpawnLightningBolt(); + } + + /** + * Determines if a given BiomeGenBase is of HELLISH temperature, since it is treated separately 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) { + if (isBiomeHellishCache.containsKey(biomeGen)) { + return isBiomeHellishCache.get(biomeGen); + } + + boolean isBiomeHellish = BiomeDictionary.isBiomeOfType(biomeGen, BiomeDictionary.Type.NETHER); + isBiomeHellishCache.put(biomeGen, isBiomeHellish); + return isBiomeHellish; + } +} diff --git a/src/api/java/forestry/api/core/EnumHumidity.java b/src/api/java/forestry/api/core/EnumHumidity.java new file mode 100644 index 00000000..a8743169 --- /dev/null +++ b/src/api/java/forestry/api/core/EnumHumidity.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.core; + +/** + * 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"); + + public final String name; + + private EnumHumidity(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + /** + * Determines the EnumHumidity given a floating point representation of Minecraft Rainfall. + * To check if rainfall is possible in a biome, use BiomeHelper.canRainOrSnow(). + * @param rawHumidity raw rainfall value + * @return EnumHumidity corresponding to rainfall value + */ + public static EnumHumidity getFromValue(float rawHumidity) { + if (rawHumidity > 0.85f) { // matches BiomeGenBase.isHighHumidity() + return DAMP; + } + else if (rawHumidity >= 0.3f) { + return NORMAL; + } + else { + return ARID; + } + } +} diff --git a/src/api/java/forestry/api/core/EnumTemperature.java b/src/api/java/forestry/api/core/EnumTemperature.java new file mode 100644 index 00000000..b0c4c889 --- /dev/null +++ b/src/api/java/forestry/api/core/EnumTemperature.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.util.IIcon; +import net.minecraft.world.biome.BiomeGenBase; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * 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"); + + 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); + } + + /** + * Determines the EnumTemperature given a floating point representation of + * Minecraft temperature. Hellish biomes are handled based on their biome + * type - check BiomeHelper.isBiomeHellish. + * @param rawTemp raw temperature value + * @return EnumTemperature corresponding to value of rawTemp + */ + public static EnumTemperature getFromValue(float rawTemp) { + if (rawTemp > 1.00f) { + return HOT; + } + else if (rawTemp > 0.80f) { + return WARM; + } + else if (rawTemp > 0.30f) { + return NORMAL; + } + else if (rawTemp > 0.0f) { + return COLD; + } + else { + return ICY; + } + } + + public static EnumTemperature getFromBiome(BiomeGenBase biomeGenBase) { + if (BiomeHelper.isBiomeHellish(biomeGenBase)) { + return HELLISH; + } + return getFromValue(biomeGenBase.temperature); + } +} diff --git a/src/api/java/forestry/api/core/ErrorStateRegistry.java b/src/api/java/forestry/api/core/ErrorStateRegistry.java new file mode 100644 index 00000000..67e5c466 --- /dev/null +++ b/src/api/java/forestry/api/core/ErrorStateRegistry.java @@ -0,0 +1,77 @@ +/* + ******************************************************************************* + * Copyright (c) 2011-2014 SirSengir. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v3 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-3.0.txt + * + * Various Contributors including, but not limited to: + * SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges + ******************************************************************************* + */ +package forestry.api.core; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import net.minecraft.client.renderer.texture.IIconRegister; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * + * @author CovertJaguar + */ +public class ErrorStateRegistry { + + private static final BiMap states = HashBiMap.create(); + private static final Map stateNames = new HashMap(); + private static final Set stateView = Collections.unmodifiableSet(states.inverse().keySet()); + + public static void registerErrorState(IErrorState state) { + if (states.containsKey(state.getID())) + throw new RuntimeException("Forestry Error State does not possess a unique id."); + states.put(state.getID(), state); + addStateName(state, state.getUniqueName()); + } + + public static void addAlias(IErrorState state, String name) { + if (!states.values().contains(state)) + throw new RuntimeException("Forestry Error State did not exist while trying to register alias."); + addStateName(state, name); + } + + private static void addStateName(IErrorState state, String name) { + if (!name.contains(":")) + throw new RuntimeException("Forestry Error State name must be in the format :."); + if (stateNames.containsKey(name)) + throw new RuntimeException("Forestry Error State does not possess a unique name."); + stateNames.put(name, state); + } + + public static IErrorState getErrorState(short id) { + return states.get(id); + } + + public static IErrorState getErrorState(String name) { + return stateNames.get(name); + } + + public static Set getErrorStates() { + return stateView; + } + + @SideOnly(Side.CLIENT) + public static void initIcons(IIconRegister register) { + for (IErrorState code : states.values()) { + code.registerIcons(register); + } + } +} diff --git a/src/api/java/forestry/api/core/ForestryAPI.java b/src/api/java/forestry/api/core/ForestryAPI.java new file mode 100644 index 00000000..24c5b7eb --- /dev/null +++ b/src/api/java/forestry/api/core/ForestryAPI.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/ForestryEvent.java b/src/api/java/forestry/api/core/ForestryEvent.java new file mode 100644 index 00000000..86aac9bc --- /dev/null +++ b/src/api/java/forestry/api/core/ForestryEvent.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.entity.player.EntityPlayer; + +import com.mojang.authlib.GameProfile; + +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 GameProfile username; + + private BreedingEvent(ISpeciesRoot root, GameProfile 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, GameProfile 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, GameProfile 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/src/api/java/forestry/api/core/IArmorNaturalist.java b/src/api/java/forestry/api/core/IArmorNaturalist.java new file mode 100644 index 00000000..87400e27 --- /dev/null +++ b/src/api/java/forestry/api/core/IArmorNaturalist.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/IErrorState.java b/src/api/java/forestry/api/core/IErrorState.java new file mode 100644 index 00000000..b17305fb --- /dev/null +++ b/src/api/java/forestry/api/core/IErrorState.java @@ -0,0 +1,41 @@ +/* + ******************************************************************************* + * Copyright (c) 2011-2014 SirSengir. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v3 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-3.0.txt + * + * Various Contributors including, but not limited to: + * SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges + ******************************************************************************* + */ +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; + +/** + * + * @author CovertJaguar + */ +public interface IErrorState { + + short getID(); + + String getUniqueName(); + + String getDescription(); + + String getHelp(); + + @SideOnly(Side.CLIENT) + void registerIcons(IIconRegister register); + + @SideOnly(value = Side.CLIENT) + IIcon getIcon(); + +} diff --git a/src/api/java/forestry/api/core/IForestryConstants.java b/src/api/java/forestry/api/core/IForestryConstants.java new file mode 100644 index 00000000..4cf876f6 --- /dev/null +++ b/src/api/java/forestry/api/core/IForestryConstants.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/IGameMode.java b/src/api/java/forestry/api/core/IGameMode.java new file mode 100644 index 00000000..0b2b0c55 --- /dev/null +++ b/src/api/java/forestry/api/core/IGameMode.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/IIconProvider.java b/src/api/java/forestry/api/core/IIconProvider.java new file mode 100644 index 00000000..308e3ce5 --- /dev/null +++ b/src/api/java/forestry/api/core/IIconProvider.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/INBTTagable.java b/src/api/java/forestry/api/core/INBTTagable.java new file mode 100644 index 00000000..1d3f8580 --- /dev/null +++ b/src/api/java/forestry/api/core/INBTTagable.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.nbt.NBTTagCompound; + +public interface INBTTagable { + void readFromNBT(NBTTagCompound nbttagcompound); + + void writeToNBT(NBTTagCompound nbttagcompound); +} diff --git a/src/api/java/forestry/api/core/IStructureLogic.java b/src/api/java/forestry/api/core/IStructureLogic.java new file mode 100644 index 00000000..aa93d171 --- /dev/null +++ b/src/api/java/forestry/api/core/IStructureLogic.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/ITextureManager.java b/src/api/java/forestry/api/core/ITextureManager.java new file mode 100644 index 00000000..a259fcae --- /dev/null +++ b/src/api/java/forestry/api/core/ITextureManager.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/ITileStructure.java b/src/api/java/forestry/api/core/ITileStructure.java new file mode 100644 index 00000000..c8c29cad --- /dev/null +++ b/src/api/java/forestry/api/core/ITileStructure.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.inventory.ISidedInventory; +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 ISidedInventory representing the inventory accessed from this block. + */ + ISidedInventory getStructureInventory(); + + /** + * 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/src/api/java/forestry/api/core/IToolPipette.java b/src/api/java/forestry/api/core/IToolPipette.java new file mode 100644 index 00000000..f5f1a633 --- /dev/null +++ b/src/api/java/forestry/api/core/IToolPipette.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2011-2014 SirSengir. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v3 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-3.0.txt + * + * Various Contributors including, but not limited to: + * SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges + ******************************************************************************/ +package forestry.api.core; + +import net.minecraft.item.ItemStack; + +import net.minecraftforge.fluids.FluidStack; + +/** + * Taken from BuildCraft 5.0.x + */ +public interface IToolPipette { + + /** + * @param pipette + * ItemStack of the pipette. + * @return Capacity of the pipette. + */ + int getCapacity(ItemStack pipette); + + /** + * @param pipette + * @return true if the pipette can pipette. + */ + boolean canPipette(ItemStack pipette); + + /** + * Fills the pipette with the given liquid stack. + * + * @param pipette + * @param liquid + * @param doFill + * @return Amount of liquid used in filling the pipette. + */ + int fill(ItemStack pipette, FluidStack liquid, boolean doFill); + + /** + * Drains liquid from the pipette + * + * @param pipette + * @param maxDrain + * @param doDrain + * @return Fluid stack representing the liquid and amount drained from the pipette. + */ + FluidStack drain(ItemStack pipette, int maxDrain, boolean doDrain); +} diff --git a/src/api/java/forestry/api/core/IToolScoop.java b/src/api/java/forestry/api/core/IToolScoop.java new file mode 100644 index 00000000..583b6c7e --- /dev/null +++ b/src/api/java/forestry/api/core/IToolScoop.java @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.core; + +/** + * Marks a tool as a scoop. + */ +public interface IToolScoop { + +} diff --git a/src/api/java/forestry/api/core/Tabs.java b/src/api/java/forestry/api/core/Tabs.java new file mode 100644 index 00000000..4ce85838 --- /dev/null +++ b/src/api/java/forestry/api/core/Tabs.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/core/package-info.java b/src/api/java/forestry/api/core/package-info.java new file mode 100644 index 00000000..3db8ba25 --- /dev/null +++ b/src/api/java/forestry/api/core/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="3.0.0", owner="Forestry", provides="ForestryAPI|core") +package forestry.api.core; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/farming/Farmables.java b/src/api/java/forestry/api/farming/Farmables.java new file mode 100644 index 00000000..bc4c159c --- /dev/null +++ b/src/api/java/forestry/api/farming/Farmables.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/farming/ICrop.java b/src/api/java/forestry/api/farming/ICrop.java new file mode 100644 index 00000000..22575477 --- /dev/null +++ b/src/api/java/forestry/api/farming/ICrop.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/farming/IFarmComponent.java b/src/api/java/forestry/api/farming/IFarmComponent.java new file mode 100644 index 00000000..3387f7a3 --- /dev/null +++ b/src/api/java/forestry/api/farming/IFarmComponent.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/farming/IFarmHousing.java b/src/api/java/forestry/api/farming/IFarmHousing.java new file mode 100644 index 00000000..acdd982d --- /dev/null +++ b/src/api/java/forestry/api/farming/IFarmHousing.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/farming/IFarmInterface.java b/src/api/java/forestry/api/farming/IFarmInterface.java new file mode 100644 index 00000000..08968747 --- /dev/null +++ b/src/api/java/forestry/api/farming/IFarmInterface.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/farming/IFarmListener.java b/src/api/java/forestry/api/farming/IFarmListener.java new file mode 100644 index 00000000..461525ff --- /dev/null +++ b/src/api/java/forestry/api/farming/IFarmListener.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/farming/IFarmLogic.java b/src/api/java/forestry/api/farming/IFarmLogic.java new file mode 100644 index 00000000..1c2482c0 --- /dev/null +++ b/src/api/java/forestry/api/farming/IFarmLogic.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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); + + IFarmLogic setManual(boolean manual); + + @SideOnly(Side.CLIENT) + IIcon getIcon(); + + ResourceLocation getSpriteSheet(); + + String getName(); +} diff --git a/src/api/java/forestry/api/farming/IFarmable.java b/src/api/java/forestry/api/farming/IFarmable.java new file mode 100644 index 00000000..440ae599 --- /dev/null +++ b/src/api/java/forestry/api/farming/IFarmable.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.farming; + +import net.minecraft.entity.player.EntityPlayer; +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(EntityPlayer player, ItemStack germling, World world, int x, int y, int z); + +} diff --git a/src/api/java/forestry/api/farming/package-info.java b/src/api/java/forestry/api/farming/package-info.java new file mode 100644 index 00000000..4460886c --- /dev/null +++ b/src/api/java/forestry/api/farming/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="1.1.0", owner="ForestryAPI|core", provides="ForestryAPI|farming") +package forestry.api.farming; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/food/BeverageManager.java b/src/api/java/forestry/api/food/BeverageManager.java new file mode 100644 index 00000000..2b0143ab --- /dev/null +++ b/src/api/java/forestry/api/food/BeverageManager.java @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/food/IBeverageEffect.java b/src/api/java/forestry/api/food/IBeverageEffect.java new file mode 100644 index 00000000..6a787411 --- /dev/null +++ b/src/api/java/forestry/api/food/IBeverageEffect.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/food/IInfuserManager.java b/src/api/java/forestry/api/food/IInfuserManager.java new file mode 100644 index 00000000..d778ffa4 --- /dev/null +++ b/src/api/java/forestry/api/food/IInfuserManager.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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); + + boolean isIngredient(ItemStack itemstack); + + ItemStack[] getRequired(ItemStack[] ingredients); + +} diff --git a/src/api/java/forestry/api/food/IIngredientManager.java b/src/api/java/forestry/api/food/IIngredientManager.java new file mode 100644 index 00000000..fab0e012 --- /dev/null +++ b/src/api/java/forestry/api/food/IIngredientManager.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/food/package-info.java b/src/api/java/forestry/api/food/package-info.java new file mode 100644 index 00000000..372c3016 --- /dev/null +++ b/src/api/java/forestry/api/food/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="1.1.0", owner="ForestryAPI|core", provides="ForestryAPI|food") +package forestry.api.food; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/fuels/EngineBronzeFuel.java b/src/api/java/forestry/api/fuels/EngineBronzeFuel.java new file mode 100644 index 00000000..cbab0caf --- /dev/null +++ b/src/api/java/forestry/api/fuels/EngineBronzeFuel.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/fuels/EngineCopperFuel.java b/src/api/java/forestry/api/fuels/EngineCopperFuel.java new file mode 100644 index 00000000..af568dd4 --- /dev/null +++ b/src/api/java/forestry/api/fuels/EngineCopperFuel.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/fuels/FermenterFuel.java b/src/api/java/forestry/api/fuels/FermenterFuel.java new file mode 100644 index 00000000..32989a80 --- /dev/null +++ b/src/api/java/forestry/api/fuels/FermenterFuel.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/fuels/FuelManager.java b/src/api/java/forestry/api/fuels/FuelManager.java new file mode 100644 index 00000000..f53d6fb7 --- /dev/null +++ b/src/api/java/forestry/api/fuels/FuelManager.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.fuels; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; + +import java.util.HashMap; + + +public class FuelManager { + /** + * Add new fuels for the fermenter here (i.e. fertilizer). + */ + 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; + /** + * Add new fuels for Generator here + */ + public static HashMap generatorFuel; + +} diff --git a/src/api/java/forestry/api/fuels/GeneratorFuel.java b/src/api/java/forestry/api/fuels/GeneratorFuel.java new file mode 100644 index 00000000..16e2ee4d --- /dev/null +++ b/src/api/java/forestry/api/fuels/GeneratorFuel.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.fuels; + +import net.minecraftforge.fluids.FluidStack; + +public class GeneratorFuel { + + /** + * 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/src/api/java/forestry/api/fuels/MoistenerFuel.java b/src/api/java/forestry/api/fuels/MoistenerFuel.java new file mode 100644 index 00000000..4c4c7a0b --- /dev/null +++ b/src/api/java/forestry/api/fuels/MoistenerFuel.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/fuels/RainSubstrate.java b/src/api/java/forestry/api/fuels/RainSubstrate.java new file mode 100644 index 00000000..ab0deb5a --- /dev/null +++ b/src/api/java/forestry/api/fuels/RainSubstrate.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/fuels/package-info.java b/src/api/java/forestry/api/fuels/package-info.java new file mode 100644 index 00000000..748fa228 --- /dev/null +++ b/src/api/java/forestry/api/fuels/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="2.0.1", owner="ForestryAPI|core", provides="ForestryAPI|fuels") +package forestry.api.fuels; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/genetics/AlleleManager.java b/src/api/java/forestry/api/genetics/AlleleManager.java new file mode 100644 index 00000000..6e351162 --- /dev/null +++ b/src/api/java/forestry/api/genetics/AlleleManager.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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(); + /** + * Queryable instance of an {@link IClimateHelper} for easier implementation. + */ + public static IClimateHelper climateHelper; + /** + * Creates Forestry alleles. + */ + public static IAlleleFactory alleleFactory; +} diff --git a/src/api/java/forestry/api/genetics/EnumTolerance.java b/src/api/java/forestry/api/genetics/EnumTolerance.java new file mode 100644 index 00000000..6ff0085e --- /dev/null +++ b/src/api/java/forestry/api/genetics/EnumTolerance.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IAllele.java b/src/api/java/forestry/api/genetics/IAllele.java new file mode 100644 index 00000000..52747410 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAllele.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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(); + + /** + * @return The unlocalized identifier + */ + String getUnlocalizedName(); + +} diff --git a/src/api/java/forestry/api/genetics/IAlleleArea.java b/src/api/java/forestry/api/genetics/IAlleleArea.java new file mode 100644 index 00000000..7277ff0a --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleArea.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleArea extends IAllele { + + int[] getValue(); + +} diff --git a/src/api/java/forestry/api/genetics/IAlleleBoolean.java b/src/api/java/forestry/api/genetics/IAlleleBoolean.java new file mode 100644 index 00000000..887da3b9 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleBoolean.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleBoolean extends IAllele { + + boolean getValue(); + + +} diff --git a/src/api/java/forestry/api/genetics/IAlleleEffect.java b/src/api/java/forestry/api/genetics/IAlleleEffect.java new file mode 100644 index 00000000..7b94e6b1 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleEffect.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IAlleleFactory.java b/src/api/java/forestry/api/genetics/IAlleleFactory.java new file mode 100644 index 00000000..2b390069 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleFactory.java @@ -0,0 +1,80 @@ +package forestry.api.genetics; + +/** + * Creates new alleles with smart localization. + * + * + * UID is created like this: + * modId + '.' + category + WordUtils.capitalize(valueName); + * For Example: + * modId:forestry, category:height, valueName:smallest => forestry.heightSmallest + * This is mainly for legacy compatibility and may change in future major versions. + * + * + * The default localization uses: + * [modId].allele.[valueName] + * + * Languages that need category-specific names can override it by defining: + * [modId].allele.[category].[valueName] + * + * For example: + * en_US + * forestry.allele.smallest=Smallest + * ru_RU + * forestry.allele.smallest=????? ????????? + * forestry.allele.height.smallest=????? ?????? + */ +public interface IAlleleFactory { + /** + * @param modId mod prefix for uid and localization (i.e. "forestry") + * @param category allele category for uid and localization (i.e. "height") + * @param valueName allele value name for uid and localization (i.e. "smallest") + * @param value allele float value + * @param isDominant allele dominance + * @return a new IAlleleFloat + */ + IAlleleFloat createFloat(String modId, String category, String valueName, float value, boolean isDominant); + + /** + * @param modId mod prefix for uid and localization (i.e. "forestry") + * @param category allele category for uid and localization (i.e. "territory") + * @param valueName allele value name for uid and localization (i.e. "large") + * @param xDimValue allele area X Size + * @param yDimValue allele area Y Size + * @param zDimValue allele area Z Size + * @param isDominant allele dominance + * @return a new IAlleleArea + */ + IAlleleArea createArea(String modId, String category, String valueName, int xDimValue, int yDimValue, int zDimValue, boolean isDominant); + + /** + * @param modId mod prefix for uid and localization (i.e. "forestry") + * @param category allele category for uid and localization (i.e. "fertility") + * @param valueName allele value name for uid and localization (i.e. "low") + * @param value allele int value + * @param isDominant allele dominance + * @return a new IAlleleInteger + */ + IAlleleInteger createInteger(String modId, String category, String valueName, int value, boolean isDominant); + + /** + * @param modId mod prefix for uid and localization (i.e. "forestry") + * @param category allele category for uid and localization (i.e. "fireproof") + * @param value allele boolean value + * @param isDominant allele dominance + * @return a new IAlleleBoolean + * Note that valueName will always be "true" or "false" + */ + IAlleleBoolean createBoolean(String modId, String category, boolean value, boolean isDominant); + + /** + * @param modId mod prefix for uid (i.e. "forestry") + * @param category allele category for uid (i.e. "flowers") + * @param valueName allele value name for uid (i.e. "vanilla") + * @param value allele IFlowerProvider value + * @param isDominant allele dominance + * @return a new IAlleleFlowers + * IAlleleFlowers localization is handled by the IFlowerProvider.getDescription(), unlike the other alleles. + */ + IAlleleFlowers createFlowers(String modId, String category, String valueName, IFlowerProvider value, boolean isDominant); +} diff --git a/src/api/java/forestry/api/genetics/IAlleleFloat.java b/src/api/java/forestry/api/genetics/IAlleleFloat.java new file mode 100644 index 00000000..6ca28776 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleFloat.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleFloat extends IAllele { + + float getValue(); + +} diff --git a/src/api/java/forestry/api/genetics/IAlleleFlowers.java b/src/api/java/forestry/api/genetics/IAlleleFlowers.java new file mode 100644 index 00000000..0368ca41 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleFlowers.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + + +public interface IAlleleFlowers extends IAllele { + + /** + * @return FlowerProvider + */ + IFlowerProvider getProvider(); + +} diff --git a/src/api/java/forestry/api/genetics/IAlleleHandler.java b/src/api/java/forestry/api/genetics/IAlleleHandler.java new file mode 100644 index 00000000..3d052afe --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleHandler.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IAlleleInteger.java b/src/api/java/forestry/api/genetics/IAlleleInteger.java new file mode 100644 index 00000000..6991efe5 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleInteger.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing integer values. + */ +public interface IAlleleInteger extends IAllele { + + int getValue(); + +} diff --git a/src/api/java/forestry/api/genetics/IAllelePlantType.java b/src/api/java/forestry/api/genetics/IAllelePlantType.java new file mode 100644 index 00000000..211237f2 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAllelePlantType.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.EnumSet; + +import net.minecraftforge.common.EnumPlantType; + +public interface IAllelePlantType extends IAllele { + + public EnumSet getPlantTypes(); + +} diff --git a/src/api/java/forestry/api/genetics/IAlleleRegistry.java b/src/api/java/forestry/api/genetics/IAlleleRegistry.java new file mode 100644 index 00000000..9b0907b0 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleRegistry.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.Collection; +import java.util.Map; + +import net.minecraft.item.ItemStack; + +import com.mojang.authlib.GameProfile; + +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); + + /* 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(GameProfile 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(GameProfile researcher, IMutation mutation); + +} diff --git a/src/api/java/forestry/api/genetics/IAlleleSpecies.java b/src/api/java/forestry/api/genetics/IAlleleSpecies.java new file mode 100644 index 00000000..5a75adef --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleSpecies.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import com.mojang.authlib.GameProfile; + +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 gameProfile + * @param individual + * @param bountyLevel + * @return Array of itemstacks representing the bounty for this research success. + */ + ItemStack[] getResearchBounty(World world, GameProfile gameProfile, 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/src/api/java/forestry/api/genetics/IAlleleSpeciesCustom.java b/src/api/java/forestry/api/genetics/IAlleleSpeciesCustom.java new file mode 100644 index 00000000..ff138162 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleSpeciesCustom.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public interface IAlleleSpeciesCustom extends IAlleleSpecies { + + IAlleleSpeciesCustom setTemperature(EnumTemperature temperature); + IAlleleSpeciesCustom setHumidity(EnumHumidity humidity); + + IAlleleSpeciesCustom setHasEffect(); + + /** Secret species are not shown in creative mode. */ + IAlleleSpeciesCustom setIsSecret(); + + /** Uncounted species do not count toward total species discovered. */ + IAlleleSpeciesCustom setIsNotCounted(); +} diff --git a/src/api/java/forestry/api/genetics/IAlleleTolerance.java b/src/api/java/forestry/api/genetics/IAlleleTolerance.java new file mode 100644 index 00000000..f5ba9e67 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IAlleleTolerance.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * Simple interface to allow adding additional alleles containing float values. + */ +public interface IAlleleTolerance extends IAllele { + + EnumTolerance getValue(); + +} diff --git a/src/api/java/forestry/api/genetics/IBreedingTracker.java b/src/api/java/forestry/api/genetics/IBreedingTracker.java new file mode 100644 index 00000000..e3614481 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IBreedingTracker.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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. + * + * @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/src/api/java/forestry/api/genetics/IChromosome.java b/src/api/java/forestry/api/genetics/IChromosome.java new file mode 100644 index 00000000..d501efba --- /dev/null +++ b/src/api/java/forestry/api/genetics/IChromosome.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IChromosomeType.java b/src/api/java/forestry/api/genetics/IChromosomeType.java new file mode 100644 index 00000000..a3b1f8e0 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IChromosomeType.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IClassification.java b/src/api/java/forestry/api/genetics/IClassification.java new file mode 100644 index 00000000..f365b915 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IClassification.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IClimateHelper.java b/src/api/java/forestry/api/genetics/IClimateHelper.java new file mode 100644 index 00000000..48146042 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IClimateHelper.java @@ -0,0 +1,53 @@ +package forestry.api.genetics; + +import java.util.Collection; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +public interface IClimateHelper { + /** + * Determines whether the given temperature and humidity are within the given constraints. + * @param temperature The temperature to test. + * @param humidity The humidity to test. + * @param baseTemp Base temperature for the test. + * @param tolTemp Temperature tolerance to apply. + * @param baseHumid Base humidity for the test. + * @param tolHumid Humidity tolerance to apply. + * @return true if both temperature and humidity fit the given constraints. + */ + boolean isWithinLimits(EnumTemperature temperature, EnumHumidity humidity, + EnumTemperature baseTemp, EnumTolerance tolTemp, + EnumHumidity baseHumid, EnumTolerance tolHumid); + + boolean isWithinLimits(EnumTemperature temperature, EnumTemperature baseTemp, EnumTolerance tolTemp); + boolean isWithinLimits(EnumHumidity humidity, EnumHumidity baseHumid, EnumTolerance tolHumid); + + /** + * Gets a collection of humidities which fit the given parameters. + * @param prefered Base humidity from which to measure. + * @param tolerance Tolerance to apply to the base humidity. + * @return A collection of humidities which fall within the given parameters. + */ + Collection getToleratedHumidity(EnumHumidity prefered, EnumTolerance tolerance); + /** + * Gets a collection of temperatures which fit the given parameters. + * @param prefered Base temperature from which to measure. + * @param tolerance Tolerance to apply to the base temperatures. + * @return A collection of temperatures which fall within the given parameters. + */ + Collection getToleratedTemperature(EnumTemperature prefered, EnumTolerance tolerance); + + /** + * Gets a localized, human readable string for the given temperature. + * @param temperature Temperature to generate the string for. + * @return A localized, human readable string for the given temperature. + */ + String toDisplay(EnumTemperature temperature); + /** + * Gets a localized, human readable string for the given humidity. + * @param humidity Humidity to generate the string for. + * @return A localized, human readable string for the given humidity. + */ + String toDisplay(EnumHumidity humidity); +} \ No newline at end of file diff --git a/src/api/java/forestry/api/genetics/IEffectData.java b/src/api/java/forestry/api/genetics/IEffectData.java new file mode 100644 index 00000000..909ab78d --- /dev/null +++ b/src/api/java/forestry/api/genetics/IEffectData.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IFlower.java b/src/api/java/forestry/api/genetics/IFlower.java new file mode 100644 index 00000000..79ef8115 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IFlower.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.block.Block; + +public interface IFlower extends Comparable { + + Block getBlock(); + int getMeta(); + + double getWeight(); + void setWeight(double weight); + + boolean isPlantable(); + +} diff --git a/src/api/java/forestry/api/genetics/IFlowerGrowthRule.java b/src/api/java/forestry/api/genetics/IFlowerGrowthRule.java new file mode 100644 index 00000000..55237399 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IFlowerGrowthRule.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.world.World; + +/** + * Basic condition for flower growing + */ +public interface IFlowerGrowthRule { + boolean growFlower(IFlowerRegistry fr, String flowerType, World world, IIndividual individual, int x, int y, int z); +} diff --git a/src/api/java/forestry/api/genetics/IFlowerProvider.java b/src/api/java/forestry/api/genetics/IFlowerProvider.java new file mode 100644 index 00000000..9849da03 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IFlowerProvider.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IFlowerProvider { + /** + * @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); + + /** + * @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. + * + * @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 List of valid flowers for the flower provider. The first in the array is for use as an icon. + * Returns an empty list if the flower provider does not have any valid flowers. + */ + List getFlowers(); +} diff --git a/src/api/java/forestry/api/genetics/IFlowerRegistry.java b/src/api/java/forestry/api/genetics/IFlowerRegistry.java new file mode 100644 index 00000000..ce6cb42c --- /dev/null +++ b/src/api/java/forestry/api/genetics/IFlowerRegistry.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import java.util.List; +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.world.World; + +public interface IFlowerRegistry { + + List getAcceptableFlowers(String flowerType); + + boolean growFlower(String flowerType, World world, IIndividual individual, int x, int y, int z); + + boolean isAcceptedFlower(String flowerType, World world, IIndividual individual, int x, int y, int z); + + /** + * Registers a non-plantable flower, but bees accept them. + * + * @param flowerTypes See {@link forestry.api.apiculture.FlowerManager}.FlowerTypeXXX + */ + void registerAcceptableFlower(Block flowerBlock, String... flowerTypes); + void registerAcceptableFlower(Block flowerBlock, int flowerMeta, String... flowerTypes); + + void registerGrowthRule(IFlowerGrowthRule rule, String... flowerTypes); + + /** + * Registers a plantable flower. + * The distribution is based on its own weight and the total number of plants for this flowerType. + * + * @param weight Weight for the Flower (Vanilla = 1.0, Modded flowers < 1.0) + * @param flowerTypes See {@link forestry.api.apiculture.FlowerManager}.FlowerTypeXXX + */ + void registerPlantableFlower(Block flowerBlock, int flowerMeta, double weight, String... flowerTypes); + + IFlower getRandomPlantableFlower(String flowerType, Random rand); + +} diff --git a/src/api/java/forestry/api/genetics/IFruitBearer.java b/src/api/java/forestry/api/genetics/IFruitBearer.java new file mode 100644 index 00000000..5316f9eb --- /dev/null +++ b/src/api/java/forestry/api/genetics/IFruitBearer.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IFruitFamily.java b/src/api/java/forestry/api/genetics/IFruitFamily.java new file mode 100644 index 00000000..d48a4d8a --- /dev/null +++ b/src/api/java/forestry/api/genetics/IFruitFamily.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IGenome.java b/src/api/java/forestry/api/genetics/IGenome.java new file mode 100644 index 00000000..0d3ad231 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IGenome.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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(IChromosomeType chromosomeType); + + IAllele getInactiveAllele(IChromosomeType chromosomeType); + + boolean isGeneticEqual(IGenome other); + + ISpeciesRoot getSpeciesRoot(); +} diff --git a/src/api/java/forestry/api/genetics/IHousing.java b/src/api/java/forestry/api/genetics/IHousing.java new file mode 100644 index 00000000..5a510311 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IHousing.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; + +import com.mojang.authlib.GameProfile; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.IErrorState; + +/** + * 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. + */ + GameProfile getOwnerName(); + + World getWorld(); + + int getXCoord(); + + int getYCoord(); + + int getZCoord(); + + BiomeGenBase getBiome(); + + EnumTemperature getTemperature(); + + EnumHumidity getHumidity(); + + void setErrorState(IErrorState state); + + IErrorState getErrorState(); + + /** + * Adds products to the housing's inventory. + * + * @param product + * ItemStack with the product to add. + * @param all + * if true, success requires that all products are added + * @return Boolean indicating success or failure. + */ + boolean addProduct(ItemStack product, boolean all); + +} diff --git a/src/api/java/forestry/api/genetics/IIndividual.java b/src/api/java/forestry/api/genetics/IIndividual.java new file mode 100644 index 00000000..f86aa582 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IIndividual.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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(); + + boolean isPureBred(IChromosomeType chromosomeType); + +} diff --git a/src/api/java/forestry/api/genetics/IIndividualLiving.java b/src/api/java/forestry/api/genetics/IIndividualLiving.java new file mode 100644 index 00000000..67ce0a97 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IIndividualLiving.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/ILegacyHandler.java b/src/api/java/forestry/api/genetics/ILegacyHandler.java new file mode 100644 index 00000000..901afa7f --- /dev/null +++ b/src/api/java/forestry/api/genetics/ILegacyHandler.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +/** + * AlleleManager.alleleRegistry can be cast to this type. + * @deprecated Since Forestry 3.6. Use IAlleleRegistry. + */ +@Deprecated +public interface ILegacyHandler { + void registerLegacyMapping(int id, String uid); + + IAllele getFromLegacyMap(int id); +} diff --git a/src/api/java/forestry/api/genetics/IMutation.java b/src/api/java/forestry/api/genetics/IMutation.java new file mode 100644 index 00000000..8c15ca58 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IMutation.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/IMutationCondition.java b/src/api/java/forestry/api/genetics/IMutationCondition.java new file mode 100644 index 00000000..ac8de0a2 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IMutationCondition.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.world.World; + +public interface IMutationCondition { + + /** + * Returns a float from 0 to 1 representing the chance for mutation to occur. + * Most will return 1 if the condition is met and 0 otherwise, + * but the float offers flexibility for more advanced conditions. + */ + float getChance(World world, int x, int y, int z, IAllele allele0, IAllele allele1, IGenome genome0, IGenome genome1); + + /** + * A localized description of the mutation condition. (i.e. "A temperature of HOT is required.") + */ + String getDescription(); +} diff --git a/src/api/java/forestry/api/genetics/IMutationCustom.java b/src/api/java/forestry/api/genetics/IMutationCustom.java new file mode 100644 index 00000000..f6d366cd --- /dev/null +++ b/src/api/java/forestry/api/genetics/IMutationCustom.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.genetics; + +import net.minecraft.block.Block; + +import net.minecraftforge.common.BiomeDictionary; + +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; + +/** Set custom mutation requirements */ +public interface IMutationCustom extends IMutation { + + /** Prevent this mutation from being shown in the analyzers */ + IMutationCustom setIsSecret(); + + /** Require a specific temperature for this mutation to occur */ + IMutationCustom restrictTemperature(EnumTemperature temperature); + IMutationCustom restrictTemperature(EnumTemperature minTemperature, EnumTemperature maxTemperature); + + /** Require a specific humidity for this mutation to occur */ + IMutationCustom restrictHumidity(EnumHumidity humidity); + IMutationCustom restrictHumidity(EnumHumidity minHumidity, EnumHumidity maxHumidity); + + /** + * Restrict this mutation to certain types of biomes. + * @param types The types of biomes this mutation can occur. + */ + IMutationCustom restrictBiomeType(BiomeDictionary.Type... types); + + /** Restrict the days of the year that this mutation can occur */ + IMutationCustom restrictDateRange(int startMonth, int startDay, int endMonth, int endDay); + + /** Restrict the time of day that this mutation can occur */ + IMutationCustom requireDay(); + IMutationCustom requireNight(); + + /** Require a specific resource to be under the location of the mutation */ + IMutationCustom requireResource(Block block, int meta); + + /** Require some other custom mutation condition */ + IMutationCustom addMutationCondition(IMutationCondition mutationCondition); +} diff --git a/src/api/java/forestry/api/genetics/IPollinatable.java b/src/api/java/forestry/api/genetics/IPollinatable.java new file mode 100644 index 00000000..5b0694d7 --- /dev/null +++ b/src/api/java/forestry/api/genetics/IPollinatable.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/genetics/ISpeciesRoot.java b/src/api/java/forestry/api/genetics/ISpeciesRoot.java new file mode 100644 index 00000000..7424405d --- /dev/null +++ b/src/api/java/forestry/api/genetics/ISpeciesRoot.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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; + +import com.mojang.authlib.GameProfile; + +/** + * 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, GameProfile 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); + + Collection getPaths(IAllele result, IChromosomeType chromosomeType); + + /* 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/src/api/java/forestry/api/genetics/package-info.java b/src/api/java/forestry/api/genetics/package-info.java new file mode 100644 index 00000000..fdd093bb --- /dev/null +++ b/src/api/java/forestry/api/genetics/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="3.2.0", owner="ForestryAPI|core", provides="ForestryAPI|genetics") +package forestry.api.genetics; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/lepidopterology/EnumButterflyChromosome.java b/src/api/java/forestry/api/lepidopterology/EnumButterflyChromosome.java new file mode 100644 index 00000000..9f89f7f8 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/EnumButterflyChromosome.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/EnumFlutterType.java b/src/api/java/forestry/api/lepidopterology/EnumFlutterType.java new file mode 100644 index 00000000..f197d7b7 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/EnumFlutterType.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.lepidopterology; + +public enum EnumFlutterType { + BUTTERFLY, + SERUM, + CATERPILLAR, + NONE; + + public static final EnumFlutterType[] VALUES = values(); +} diff --git a/src/api/java/forestry/api/lepidopterology/IAlleleButterflyEffect.java b/src/api/java/forestry/api/lepidopterology/IAlleleButterflyEffect.java new file mode 100644 index 00000000..6457dbe8 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IAlleleButterflyEffect.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/IAlleleButterflySpecies.java b/src/api/java/forestry/api/lepidopterology/IAlleleButterflySpecies.java new file mode 100644 index 00000000..c1536118 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IAlleleButterflySpecies.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/IButterfly.java b/src/api/java/forestry/api/lepidopterology/IButterfly.java new file mode 100644 index 00000000..c3013247 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IButterfly.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/IButterflyGenome.java b/src/api/java/forestry/api/lepidopterology/IButterflyGenome.java new file mode 100644 index 00000000..93816600 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IButterflyGenome.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/IButterflyMutation.java b/src/api/java/forestry/api/lepidopterology/IButterflyMutation.java new file mode 100644 index 00000000..027e96eb --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IButterflyMutation.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/IButterflyNursery.java b/src/api/java/forestry/api/lepidopterology/IButterflyNursery.java new file mode 100644 index 00000000..56e42f2e --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IButterflyNursery.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/IButterflyRoot.java b/src/api/java/forestry/api/lepidopterology/IButterflyRoot.java new file mode 100644 index 00000000..7028df15 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IButterflyRoot.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 com.mojang.authlib.GameProfile; + +import forestry.api.genetics.IAllele; +import forestry.api.genetics.IIndividual; +import forestry.api.genetics.ISpeciesRoot; + +public interface IButterflyRoot extends ISpeciesRoot { + + @Override + boolean isMember(ItemStack stack); + + @Override + IButterfly getMember(ItemStack stack); + + @Override + IButterfly getMember(NBTTagCompound compound); + + @Override + ItemStack getMemberStack(IIndividual butterfly, int type); + + /* GENOME CONVERSION */ + @Override + IButterfly templateAsIndividual(IAllele[] template); + + @Override + IButterfly templateAsIndividual(IAllele[] templateActive, IAllele[] templateInactive); + + @Override + IButterflyGenome templateAsGenome(IAllele[] template); + + @Override + IButterflyGenome templateAsGenome(IAllele[] templateActive, IAllele[] templateInactive); + + /* BUTTERFLY SPECIFIC */ + ILepidopteristTracker getBreedingTracker(World world, GameProfile 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 */ + @Override + ArrayList getIndividualTemplates(); + + /* MUTATIONS */ + @Override + Collection getMutations(boolean shuffle); + + EnumFlutterType getType(ItemStack stack); + +} diff --git a/src/api/java/forestry/api/lepidopterology/IEntityButterfly.java b/src/api/java/forestry/api/lepidopterology/IEntityButterfly.java new file mode 100644 index 00000000..963c7210 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/IEntityButterfly.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/lepidopterology/ILepidopteristTracker.java b/src/api/java/forestry/api/lepidopterology/ILepidopteristTracker.java new file mode 100644 index 00000000..79926975 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/ILepidopteristTracker.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.lepidopterology; + +import forestry.api.genetics.IBreedingTracker; + +public interface ILepidopteristTracker extends IBreedingTracker { + + void registerCatch(IButterfly butterfly); + +} diff --git a/src/api/java/forestry/api/lepidopterology/package-info.java b/src/api/java/forestry/api/lepidopterology/package-info.java new file mode 100644 index 00000000..070b4322 --- /dev/null +++ b/src/api/java/forestry/api/lepidopterology/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="1.1", owner="ForestryAPI|core", provides="ForestryAPI|lepidopterology") +package forestry.api.lepidopterology; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/mail/EnumAddressee.java b/src/api/java/forestry/api/mail/EnumAddressee.java new file mode 100644 index 00000000..28c73847 --- /dev/null +++ b/src/api/java/forestry/api/mail/EnumAddressee.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +import java.util.Locale; + +public enum EnumAddressee { + PLAYER, TRADER; + + public static EnumAddressee fromString(String ident) { + ident = ident.toLowerCase(Locale.ENGLISH); + for(EnumAddressee addr : values()) { + if(addr.toString().equals(ident)) + return addr; + } + + return null; + } + + public String toString() { + return super.toString().toLowerCase(Locale.ENGLISH); + } +} diff --git a/src/api/java/forestry/api/mail/EnumPostage.java b/src/api/java/forestry/api/mail/EnumPostage.java new file mode 100644 index 00000000..772114fb --- /dev/null +++ b/src/api/java/forestry/api/mail/EnumPostage.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/mail/ILetter.java b/src/api/java/forestry/api/mail/ILetter.java new file mode 100644 index 00000000..42df8acb --- /dev/null +++ b/src/api/java/forestry/api/mail/ILetter.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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(IMailAddress address); + + IMailAddress getSender(); + + boolean hasRecipient(); + + void setRecipient(IMailAddress address); + + IMailAddress[] getRecipients(); + + String getRecipientString(); + + void setText(String text); + + String getText(); + + 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/src/api/java/forestry/api/mail/ILetterHandler.java b/src/api/java/forestry/api/mail/ILetterHandler.java new file mode 100644 index 00000000..576a0d7d --- /dev/null +++ b/src/api/java/forestry/api/mail/ILetterHandler.java @@ -0,0 +1,13 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface ILetterHandler { + IPostalState handleLetter(World world, IMailAddress recipient, ItemStack letterStack, boolean doLodge); +} diff --git a/src/api/java/forestry/api/mail/IMailAddress.java b/src/api/java/forestry/api/mail/IMailAddress.java new file mode 100644 index 00000000..8441b09a --- /dev/null +++ b/src/api/java/forestry/api/mail/IMailAddress.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +import com.mojang.authlib.GameProfile; + +import forestry.api.core.INBTTagable; + +public interface IMailAddress extends INBTTagable { + + EnumAddressee getType(); + String getName(); + + boolean isValid(); + + boolean isPlayer(); + boolean isTrader(); + + GameProfile getPlayerProfile(); +} diff --git a/src/api/java/forestry/api/mail/IPostOffice.java b/src/api/java/forestry/api/mail/IPostOffice.java new file mode 100644 index 00000000..a8a14eac --- /dev/null +++ b/src/api/java/forestry/api/mail/IPostOffice.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/mail/IPostRegistry.java b/src/api/java/forestry/api/mail/IPostRegistry.java new file mode 100644 index 00000000..f20352d9 --- /dev/null +++ b/src/api/java/forestry/api/mail/IPostRegistry.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import com.mojang.authlib.GameProfile; + +public interface IPostRegistry { + + /* POST OFFICE */ + IPostOffice getPostOffice(World world); + + /* MAIL ADDRESSES */ + IMailAddress getMailAddress(GameProfile gameProfile); + IMailAddress getMailAddress(String traderName); + + /* LETTERS */ + boolean isLetter(ItemStack itemstack); + + ILetter createLetter(IMailAddress sender, IMailAddress 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(EnumAddressee uid); + + Map getRegisteredCarriers(); + + /* TRADE STATIONS */ + void deleteTradeStation(World world, IMailAddress address); + + ITradeStation getOrCreateTradeStation(World world, GameProfile owner, IMailAddress address); + + ITradeStation getTradeStation(World world, IMailAddress address); + + boolean isAvailableTradeAddress(World world, IMailAddress address); + + boolean isValidTradeAddress(World world, IMailAddress address); + + /* PO BOXES */ + boolean isValidPOBox(World world, IMailAddress address); + +} diff --git a/src/api/java/forestry/api/mail/IPostalCarrier.java b/src/api/java/forestry/api/mail/IPostalCarrier.java new file mode 100644 index 00000000..28db78ae --- /dev/null +++ b/src/api/java/forestry/api/mail/IPostalCarrier.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 An EnumAddressee identifying the type of carrier + */ + EnumAddressee getType(); + + /** + * @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, IMailAddress recipient, ItemStack letterstack, boolean doDeliver); + +} diff --git a/src/api/java/forestry/api/mail/IPostalState.java b/src/api/java/forestry/api/mail/IPostalState.java new file mode 100644 index 00000000..bc843621 --- /dev/null +++ b/src/api/java/forestry/api/mail/IPostalState.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +public interface IPostalState { + boolean isOk(); + + String getIdentifier(); + + int ordinal(); +} diff --git a/src/api/java/forestry/api/mail/IStamps.java b/src/api/java/forestry/api/mail/IStamps.java new file mode 100644 index 00000000..4332a811 --- /dev/null +++ b/src/api/java/forestry/api/mail/IStamps.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.item.ItemStack; + +public interface IStamps { + + EnumPostage getPostage(ItemStack itemstack); + +} diff --git a/src/api/java/forestry/api/mail/ITradeStation.java b/src/api/java/forestry/api/mail/ITradeStation.java new file mode 100644 index 00000000..78a498a0 --- /dev/null +++ b/src/api/java/forestry/api/mail/ITradeStation.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +import net.minecraft.inventory.IInventory; + +public interface ITradeStation extends ILetterHandler, IInventory { + + IMailAddress getAddress(); + + boolean isValid(); + + void invalidate(); + + void setVirtual(boolean isVirtual); + + boolean isVirtual(); + + TradeStationInfo getTradeInfo(); + +} diff --git a/src/api/java/forestry/api/mail/PostManager.java b/src/api/java/forestry/api/mail/PostManager.java new file mode 100644 index 00000000..c3f0e45b --- /dev/null +++ b/src/api/java/forestry/api/mail/PostManager.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + + +public class PostManager { + public static IPostRegistry postRegistry; +} diff --git a/src/api/java/forestry/api/mail/TradeStationInfo.java b/src/api/java/forestry/api/mail/TradeStationInfo.java new file mode 100644 index 00000000..14424bed --- /dev/null +++ b/src/api/java/forestry/api/mail/TradeStationInfo.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.mail; + +import java.lang.IllegalArgumentException; +import net.minecraft.item.ItemStack; +import com.mojang.authlib.GameProfile; + +public class TradeStationInfo { + public final IMailAddress address; + public final GameProfile owner; + public final ItemStack tradegood; + public final ItemStack[] required; + public final IPostalState state; + + public TradeStationInfo(IMailAddress address, GameProfile owner, ItemStack tradegood, ItemStack[] required, IPostalState state) { + if (!address.isTrader()) { + throw new IllegalArgumentException("TradeStation address must be a trader"); + } + this.address = address; + this.owner = owner; + this.tradegood = tradegood; + this.required = required; + this.state = state; + } +} diff --git a/src/api/java/forestry/api/mail/package-info.java b/src/api/java/forestry/api/mail/package-info.java new file mode 100644 index 00000000..a1050727 --- /dev/null +++ b/src/api/java/forestry/api/mail/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="3.0.0", owner="ForestryAPI|core", provides="ForestryAPI|mail") +package forestry.api.mail; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/recipes/ICarpenterManager.java b/src/api/java/forestry/api/recipes/ICarpenterManager.java new file mode 100644 index 00000000..8e3eabbe --- /dev/null +++ b/src/api/java/forestry/api/recipes/ICarpenterManager.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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); +} diff --git a/src/api/java/forestry/api/recipes/ICentrifugeManager.java b/src/api/java/forestry/api/recipes/ICentrifugeManager.java new file mode 100644 index 00000000..910bd32c --- /dev/null +++ b/src/api/java/forestry/api/recipes/ICentrifugeManager.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/ICraftingProvider.java b/src/api/java/forestry/api/recipes/ICraftingProvider.java new file mode 100644 index 00000000..502dffb4 --- /dev/null +++ b/src/api/java/forestry/api/recipes/ICraftingProvider.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/IFabricatorManager.java b/src/api/java/forestry/api/recipes/IFabricatorManager.java new file mode 100644 index 00000000..a01f0da4 --- /dev/null +++ b/src/api/java/forestry/api/recipes/IFabricatorManager.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/IFermenterManager.java b/src/api/java/forestry/api/recipes/IFermenterManager.java new file mode 100644 index 00000000..92c903bb --- /dev/null +++ b/src/api/java/forestry/api/recipes/IFermenterManager.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/IMoistenerManager.java b/src/api/java/forestry/api/recipes/IMoistenerManager.java new file mode 100644 index 00000000..711264b4 --- /dev/null +++ b/src/api/java/forestry/api/recipes/IMoistenerManager.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/ISqueezerManager.java b/src/api/java/forestry/api/recipes/ISqueezerManager.java new file mode 100644 index 00000000..0a63b731 --- /dev/null +++ b/src/api/java/forestry/api/recipes/ISqueezerManager.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/IStillManager.java b/src/api/java/forestry/api/recipes/IStillManager.java new file mode 100644 index 00000000..47fd4215 --- /dev/null +++ b/src/api/java/forestry/api/recipes/IStillManager.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/IVariableFermentable.java b/src/api/java/forestry/api/recipes/IVariableFermentable.java new file mode 100644 index 00000000..f0997f53 --- /dev/null +++ b/src/api/java/forestry/api/recipes/IVariableFermentable.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/recipes/RecipeManagers.java b/src/api/java/forestry/api/recipes/RecipeManagers.java new file mode 100644 index 00000000..403bd5b5 --- /dev/null +++ b/src/api/java/forestry/api/recipes/RecipeManagers.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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 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/src/api/java/forestry/api/recipes/package-info.java b/src/api/java/forestry/api/recipes/package-info.java new file mode 100644 index 00000000..c76d83b9 --- /dev/null +++ b/src/api/java/forestry/api/recipes/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="3.0.0", owner="ForestryAPI|core", provides="ForestryAPI|recipes") +package forestry.api.recipes; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/storage/BackpackEvent.java b/src/api/java/forestry/api/storage/BackpackEvent.java new file mode 100644 index 00000000..37427788 --- /dev/null +++ b/src/api/java/forestry/api/storage/BackpackEvent.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/storage/BackpackManager.java b/src/api/java/forestry/api/storage/BackpackManager.java new file mode 100644 index 00000000..8805904d --- /dev/null +++ b/src/api/java/forestry/api/storage/BackpackManager.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/storage/BackpackResupplyEvent.java b/src/api/java/forestry/api/storage/BackpackResupplyEvent.java new file mode 100644 index 00000000..e6e5e119 --- /dev/null +++ b/src/api/java/forestry/api/storage/BackpackResupplyEvent.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/storage/BackpackStowEvent.java b/src/api/java/forestry/api/storage/BackpackStowEvent.java new file mode 100644 index 00000000..3afbf7a1 --- /dev/null +++ b/src/api/java/forestry/api/storage/BackpackStowEvent.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/storage/EnumBackpackType.java b/src/api/java/forestry/api/storage/EnumBackpackType.java new file mode 100644 index 00000000..48ad7ee0 --- /dev/null +++ b/src/api/java/forestry/api/storage/EnumBackpackType.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.storage; + +public enum EnumBackpackType { + APIARIST, T1, T2 +} diff --git a/src/api/java/forestry/api/storage/IBackpackDefinition.java b/src/api/java/forestry/api/storage/IBackpackDefinition.java new file mode 100644 index 00000000..31c66631 --- /dev/null +++ b/src/api/java/forestry/api/storage/IBackpackDefinition.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.storage; + +import java.util.List; + +import net.minecraft.item.ItemStack; + +public interface IBackpackDefinition { + + /** + * @return A unique string identifier + */ + String getKey(); + + /** + * @return Human-readable name of the backpack. + */ + String getName(ItemStack backpack); + + /** + * @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); + void addValidItems(List validItems); + + /** + * Returns true if the itemstack is a valid item for this backpack type. + */ + boolean isValidItem(ItemStack itemstack); + +} diff --git a/src/api/java/forestry/api/storage/IBackpackInterface.java b/src/api/java/forestry/api/storage/IBackpackInterface.java new file mode 100644 index 00000000..27a2eba5 --- /dev/null +++ b/src/api/java/forestry/api/storage/IBackpackInterface.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/storage/ICrateRegistry.java b/src/api/java/forestry/api/storage/ICrateRegistry.java new file mode 100644 index 00000000..868511e3 --- /dev/null +++ b/src/api/java/forestry/api/storage/ICrateRegistry.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.storage; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public interface ICrateRegistry { + + /** + * Makes a new crate, registers it with the game registry with uid, + * and creates crating and uncrating recipes for the Carpenter. + * The icon is rendered automatically from the contained item. + * + * Can only be called during the Init stage. + */ + void registerCrate(Item item, String uid); + void registerCrate(Block block, String uid); + void registerCrate(ItemStack stack, String uid); + + /** + * Same as the above, but uses the ore dictionary for the Carpenter crating recipe. + */ + void registerCrateUsingOreDict(Item item, String uid); + void registerCrateUsingOreDict(Block block, String uid); + void registerCrateUsingOreDict(ItemStack stack, String uid); + +} diff --git a/src/api/java/forestry/api/storage/StorageManager.java b/src/api/java/forestry/api/storage/StorageManager.java new file mode 100644 index 00000000..ef4ec4cf --- /dev/null +++ b/src/api/java/forestry/api/storage/StorageManager.java @@ -0,0 +1,12 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.storage; + +public class StorageManager { + + public static ICrateRegistry crateRegistry; + +} diff --git a/src/api/java/forestry/api/storage/package-info.java b/src/api/java/forestry/api/storage/package-info.java new file mode 100644 index 00000000..3d0c1e9d --- /dev/null +++ b/src/api/java/forestry/api/storage/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="3.0.0", owner="ForestryAPI|core", provides="ForestryAPI|storage") +package forestry.api.storage; +import cpw.mods.fml.common.API; diff --git a/src/api/java/forestry/api/world/ITreeGenData.java b/src/api/java/forestry/api/world/ITreeGenData.java new file mode 100644 index 00000000..bf59c5e5 --- /dev/null +++ b/src/api/java/forestry/api/world/ITreeGenData.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.world; + +import net.minecraft.world.World; + +import com.mojang.authlib.GameProfile; + +import forestry.api.arboriculture.ITreeGenome; + +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, GameProfile owner, int x, int y, int z); + void setLeavesDecorative(World world, GameProfile owner, int x, int y, int z); + + boolean allowsFruitBlocks(); + + boolean trySpawnFruitBlock(World world, int x, int y, int z); + + ITreeGenome getGenome(); +} diff --git a/src/api/java/forestry/api/world/IWorldGenInterface.java b/src/api/java/forestry/api/world/IWorldGenInterface.java new file mode 100644 index 00000000..b7b5555f --- /dev/null +++ b/src/api/java/forestry/api/world/IWorldGenInterface.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +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/src/api/java/forestry/api/world/WorldGenManager.java b/src/api/java/forestry/api/world/WorldGenManager.java new file mode 100644 index 00000000..a2a5b4f8 --- /dev/null +++ b/src/api/java/forestry/api/world/WorldGenManager.java @@ -0,0 +1,10 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.world; + +public class WorldGenManager { + public static IWorldGenInterface worldgenInterface; +} diff --git a/src/api/java/forestry/api/world/package-info.java b/src/api/java/forestry/api/world/package-info.java new file mode 100644 index 00000000..c7e60f4e --- /dev/null +++ b/src/api/java/forestry/api/world/package-info.java @@ -0,0 +1,8 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +@API(apiVersion="1.1.0", owner="ForestryAPI|core", provides="ForestryAPI|world") +package forestry.api.world; +import cpw.mods.fml.common.API; diff --git a/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java b/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java index 002b39f4..db2866f9 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java +++ b/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java @@ -1397,7 +1397,7 @@ public class AlchemicalWizardry Rituals.registerRitual("AW010Crusher", 1, 2500, new RitualEffectCrushing(), "Ritual of the Crusher", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/SimpleTransCircle.png"), 0, 0, 0, 255, 0, 0.501, 0.501, 0, 1.5, false)); Rituals.registerRitual("AW011Speed", 1, 1000, new RitualEffectLeap(), "Ritual of Speed", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/SimpleTransCircle.png"), 0, 0, 0, 255, 0, 0.501, 0.501, 0, 1.5, false)); Rituals.registerRitual("AW012AnimalGrowth", 1, 10000, new RitualEffectAnimalGrowth(), "Ritual of the Shepherd", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/SimpleTransCircle.png"), 0, 0, 0, 255, 0, 0.501, 0.501, 0, 1.5, false)); - Rituals.registerRitual("AW013Suffering", 1, 50000, new RitualEffectWellOfSuffering(), "Well of Suffering", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/TransCircleSuffering.png"), 0, 0, 0, 255, 0, 0.501, 0.8, 0, 2.5, true)); + Rituals.registerRitual("AW013Suffering", 1, 50000, new RitualEffectWellOfSuffering(), "Well of Suffering", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/AlchemyArrays/WellOfSufferingArray.png"), 0, 0, 0, 255, 0, 0.501, 0.8, 0, 2.5, true)); Rituals.registerRitual("AW014Regen", 1, 25000, new RitualEffectHealing(), "Ritual of Regeneration", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/SimpleTransCircle.png"), 0, 0, 0, 255, 0, 0.501, 0.501, 0, 1.5, false)); Rituals.registerRitual("AW015FeatheredKnife", 1, 50000, new RitualEffectFeatheredKnife(), "Ritual of the Feathered Knife", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/SimpleTransCircle.png"), 0, 0, 0, 255, 0, 0.501, 0.501, 0, 1.5, false)); Rituals.registerRitual("AW016FeatheredEarth", 2, 100000, new RitualEffectFeatheredEarth(), "Ritual of the Feathered Earth", new AlchemyCircleRenderer(new ResourceLocation("alchemicalwizardry:textures/models/SimpleTransCircle.png"), 0, 0, 0, 255, 0, 0.501, 0.501, 0, 1.5, false)); diff --git a/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java b/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java index 969aac58..589771a1 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java +++ b/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java @@ -166,11 +166,11 @@ public class BloodMagicConfiguration BoundArmour.tryComplexRendering = config.get("WimpySettings", "UseFancyBoundArmour", true).getBoolean(true); - ItemIncense.itemDuration = config.get("TestIncenseSettings", "ItemDuration", 100).getInt(); - ItemIncense.minValue = config.get("TestIncenseSettings", "MinValue", 0).getInt(); - ItemIncense.maxValue = config.get("TestIncenseSettings", "MaxValue", 100).getInt(); - PlayerSacrificeHandler.scalingOfSacrifice = (float) config.get("TestIncenseSettings", "ScalingFactor", 0.0025f).getDouble(); - PlayerSacrificeHandler.soulFrayDuration = config.get("TestIncenseSettings", "SoulFrayDuration", 400).getInt(); +// ItemIncense.itemDuration = config.get("TestIncenseSettings", "ItemDuration", 100).getInt(); +// ItemIncense.minValue = config.get("TestIncenseSettings", "MinValue", 0).getInt(); +// ItemIncense.maxValue = config.get("TestIncenseSettings", "MaxValue", 100).getInt(); +// PlayerSacrificeHandler.scalingOfSacrifice = (float) config.get("TestIncenseSettings", "ScalingFactor", 0.0025f).getDouble(); +// PlayerSacrificeHandler.soulFrayDuration = config.get("TestIncenseSettings", "SoulFrayDuration", 400).getInt(); Side side = FMLCommonHandler.instance().getSide(); diff --git a/src/main/java/WayofTime/alchemicalWizardry/api/sacrifice/PlayerSacrificeHandler.java b/src/main/java/WayofTime/alchemicalWizardry/api/sacrifice/PlayerSacrificeHandler.java index 1bff133d..9ed5766a 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/api/sacrifice/PlayerSacrificeHandler.java +++ b/src/main/java/WayofTime/alchemicalWizardry/api/sacrifice/PlayerSacrificeHandler.java @@ -10,7 +10,7 @@ import WayofTime.alchemicalWizardry.api.tile.IBloodAltar; public class PlayerSacrificeHandler { - public static float scalingOfSacrifice = 0.0025f; + public static float scalingOfSacrifice = 0.001f; public static int soulFrayDuration = 400; public static float getPlayerIncense(EntityPlayer player) { @@ -22,7 +22,7 @@ public class PlayerSacrificeHandler APISpellHelper.setCurrentIncense(player, amount); } - public static boolean incrementIncense(EntityPlayer player, float min, float max) + public static boolean incrementIncense(EntityPlayer player, float min, float max, float increment) { float amount = getPlayerIncense(player); if(amount < min || amount >= max) @@ -30,7 +30,7 @@ public class PlayerSacrificeHandler return false; } - amount++; + amount = amount + Math.max(increment, max - amount); setPlayerIncense(player, amount); return true; diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemIncense.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemIncense.java index 7883a489..c46c5551 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemIncense.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemIncense.java @@ -17,7 +17,7 @@ import cpw.mods.fml.relauncher.SideOnly; public class ItemIncense extends Item implements IIncense { - private static final String[] ITEM_NAMES = new String[]{"Woodash"}; + private static final String[] ITEM_NAMES = new String[]{"Woodash", "Cloves"}; @SideOnly(Side.CLIENT) private IIcon[] icons; @@ -80,12 +80,26 @@ public class ItemIncense extends Item implements IIncense @Override public int getMinLevel(ItemStack stack) { + switch(stack.getItemDamage()) + { + case 0: + return 0; + case 1: + return 200; + } return 0; } @Override public int getMaxLevel(ItemStack stack) { + switch(stack.getItemDamage()) + { + case 0: + return 200; + case 1: + return 500; + } return 100; } @@ -98,6 +112,13 @@ public class ItemIncense extends Item implements IIncense @Override public float getTickRate(ItemStack stack) { + switch(stack.getItemDamage()) + { + case 0: + return 1.0f; + case 1: + return 0.5f; + } return 1.0f; } diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemRitualDiviner.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemRitualDiviner.java index 8f9fedaf..89a7106c 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemRitualDiviner.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/ItemRitualDiviner.java @@ -328,7 +328,10 @@ public class ItemRitualDiviner extends EnergyItems implements IRitualDiviner } NBTTagCompound locTag = (NBTTagCompound)tag.getTag("location"); - locTag.setBoolean("isStored", false); + if(locTag != null) + { + locTag.setBoolean("isStored", false); + } } public Int3 getStoredLocation(ItemStack stack) diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/SacrificialDagger.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/SacrificialDagger.java index d87d812e..a22cae6f 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/SacrificialDagger.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/SacrificialDagger.java @@ -91,11 +91,11 @@ public class SacrificialDagger extends Item @Override public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { -// if (this.canUseForSacrifice(stack)) -// { -// player.setItemInUse(stack, this.getMaxItemUseDuration(stack)); -// return stack; -// } + if (this.canUseForSacrifice(stack)) + { + player.setItemInUse(stack, this.getMaxItemUseDuration(stack)); + return stack; + } if (!player.capabilities.isCreativeMode) { @@ -183,6 +183,11 @@ public class SacrificialDagger extends Item for (int k = -2; k <= 1; k++) { tileEntity = world.getTileEntity(i + x, k + y, j + z); + + if(tileEntity instanceof IBloodAltar) + { + return (IBloodAltar)tileEntity; + } } } } diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/sigil/DivinationSigil.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/sigil/DivinationSigil.java index 9b9d7612..b777d8f9 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/sigil/DivinationSigil.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/sigil/DivinationSigil.java @@ -1,5 +1,18 @@ package WayofTime.alchemicalWizardry.common.items.sigil; +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 net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; import WayofTime.alchemicalWizardry.AlchemicalWizardry; import WayofTime.alchemicalWizardry.api.alchemy.energy.IReagentHandler; import WayofTime.alchemicalWizardry.api.alchemy.energy.ReagentContainerInfo; @@ -10,21 +23,6 @@ import WayofTime.alchemicalWizardry.api.items.interfaces.IReagentManipulator; import WayofTime.alchemicalWizardry.common.items.EnergyItems; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -import net.minecraft.client.renderer.texture.IIconRegister; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.potion.Potion; -import net.minecraft.potion.PotionEffect; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.MovingObjectPosition; -import net.minecraft.util.StatCollector; -import net.minecraft.world.World; -import net.minecraftforge.common.util.ForgeDirection; - -import java.util.List; public class DivinationSigil extends Item implements ArmourUpgrade, IReagentManipulator, IBindable { @@ -130,7 +128,7 @@ public class DivinationSigil extends Item implements ArmourUpgrade, IReagentMani @Override public boolean isUpgrade() { - return true; + return false; } @Override diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TECrucible.java b/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TECrucible.java index aa25b207..5552a5cd 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TECrucible.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TECrucible.java @@ -23,6 +23,7 @@ public class TECrucible extends TEInventory public int ticksRemaining = 0; public int minValue = 0; public int maxValue = 0; + public float incrementValue = 0; public int state = 0; //0 is when it gives off gray particles, 1 is when it gives off white particles (player can't use this incense anymore), 2 is the normal colour of the incense, 3 means no particles (it is out) @@ -59,6 +60,8 @@ public class TECrucible extends TEInventory minValue = incense.getMinLevel(stack); maxValue = incense.getMaxLevel(stack); + incrementValue = incense.getTickRate(stack); + stack.stackSize--; if(stack.stackSize <= 0) { @@ -78,7 +81,7 @@ public class TECrucible extends TEInventory for(EntityPlayer player : playerList) { - if(ticksRemaining > 0 && PlayerSacrificeHandler.incrementIncense(player, minValue, maxValue)) + if(ticksRemaining > 0 && PlayerSacrificeHandler.incrementIncense(player, minValue, maxValue, incrementValue)) { ticksRemaining--; if(state != 2) diff --git a/src/main/resources/assets/alchemicalwizardry/textures/models/AlchemyArrays/WellOfSufferingArray.png b/src/main/resources/assets/alchemicalwizardry/textures/models/AlchemyArrays/WellOfSufferingArray.png new file mode 100644 index 0000000000000000000000000000000000000000..c5c63f6ad6da8be309497dada66f2cec707fb607 GIT binary patch literal 119530 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

DJGVxl<_I!PB2LF`L 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