diff --git a/src/main/java/thaumic/tinkerer/client/lib/LibResources.java b/src/main/java/thaumic/tinkerer/client/lib/LibResources.java index 4eada524..0682234c 100644 --- a/src/main/java/thaumic/tinkerer/client/lib/LibResources.java +++ b/src/main/java/thaumic/tinkerer/client/lib/LibResources.java @@ -32,6 +32,7 @@ public final class LibResources { public static final String GUI_ICHOR_POUCH = PREFIX_GUI + "ichorPouch.png"; public static final String GUI_WARP_GATE = PREFIX_GUI + "warpGate.png"; public static final String GUI_REMOTE_PLACER = PREFIX_GUI + "remotePlacer.png"; + public static final String NEI_RECIPE_ARROW = PREFIX_GUI + "neiRecipeArrow.png"; public static final String MISC_R_ENCHANTING = PREFIX_MISC + "r_enchanting.png"; public static final String MISC_AT_CENTER = PREFIX_MISC + "atCenter.png"; diff --git a/src/main/java/thaumic/tinkerer/client/nei/NEIConfig.java b/src/main/java/thaumic/tinkerer/client/nei/NEIConfig.java index e15a1b87..2d874e0b 100644 --- a/src/main/java/thaumic/tinkerer/client/nei/NEIConfig.java +++ b/src/main/java/thaumic/tinkerer/client/nei/NEIConfig.java @@ -1,5 +1,6 @@ package thaumic.tinkerer.client.nei; +import codechicken.nei.api.API; import codechicken.nei.api.IConfigureNEI; import codechicken.nei.recipe.GuiCraftingRecipe; import codechicken.nei.recipe.GuiUsageRecipe; @@ -12,6 +13,10 @@ public class NEIConfig implements IConfigureNEI { public void loadConfig() { if (!LoadedMods.aspectRecipeIndexLoaded) return; AspectRecipeIndexIntegration.register(); + + NEIInfusedSeedRecipeHandler seedHandler = new NEIInfusedSeedRecipeHandler(); + API.registerRecipeHandler(seedHandler); + API.registerUsageHandler(seedHandler); } @Override diff --git a/src/main/java/thaumic/tinkerer/client/nei/NEIInfusedSeedRecipeHandler.java b/src/main/java/thaumic/tinkerer/client/nei/NEIInfusedSeedRecipeHandler.java new file mode 100644 index 00000000..5199132f --- /dev/null +++ b/src/main/java/thaumic/tinkerer/client/nei/NEIInfusedSeedRecipeHandler.java @@ -0,0 +1,244 @@ +package thaumic.tinkerer.client.nei; + +import static thaumic.tinkerer.client.lib.LibResources.NEI_RECIPE_ARROW; + +import java.awt.Rectangle; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; + +import org.lwjgl.opengl.GL11; + +import codechicken.lib.gui.GuiDraw; +import codechicken.nei.NEIServerUtils; +import codechicken.nei.PositionedStack; +import codechicken.nei.recipe.GuiRecipe; +import codechicken.nei.recipe.TemplateRecipeHandler; +import thaumcraft.api.aspects.Aspect; +import thaumic.tinkerer.common.core.helper.AspectCropLootManager; +import thaumic.tinkerer.common.core.helper.AspectCropLootManager.LootEntry; +import thaumic.tinkerer.common.item.ItemInfusedSeeds; + +public class NEIInfusedSeedRecipeHandler extends TemplateRecipeHandler { + + private static final int SLOT_NUM_X = 9; + private static final DecimalFormat CHANCE_FORMAT = new DecimalFormat("#.##"); + + public static class DropInfo { + + public final ItemStack stack; + public final float chance; + + public DropInfo(ItemStack stack, float chance) { + this.stack = stack; + this.chance = chance; + } + } + + public static class SeedDropRecipeWrapper { + + public final ItemStack seed; + public final List drops; + + public SeedDropRecipeWrapper(ItemStack seed, List drops) { + this.seed = seed; + this.drops = drops; + } + } + + public class CachedSeedRecipe extends CachedRecipe { + + private final List input = new ArrayList<>(); + private final List outputs = new ArrayList<>(); + public final SeedDropRecipeWrapper wrapper; + public int rows = 0; + + public CachedSeedRecipe(SeedDropRecipeWrapper recipe) { + this.wrapper = recipe; + this.input.add(new PositionedStack(recipe.seed, 74, 4)); + + int row = 0; + int col = 0; + + for (DropInfo drop : recipe.drops) { + int xPos = 3 + 18 * col; + int yPos = 36 + 18 * row; + + this.outputs.add(new PositionedStack(drop.stack, xPos, yPos)); + + col++; + if (col >= SLOT_NUM_X) { + col = 0; + row++; + } + } + + this.rows = col == 0 ? row - 1 : row; + if (this.rows < 0) this.rows = 0; + } + + @Override + public List getIngredients() { + return input; + } + + @Override + public PositionedStack getResult() { + return null; + } + + @Override + public List getOtherStacks() { + return outputs; + } + } + + private List getSeedRecipes() { + List recipes = new ArrayList<>(); + Map> allLoot = AspectCropLootManager.getAllLoot(); + + for (Map.Entry> entry : allLoot.entrySet()) { + Aspect aspect = entry.getKey(); + List lootList = entry.getValue(); + + if (lootList == null || lootList.isEmpty()) continue; + + int totalWeight = 0; + for (LootEntry loot : lootList) { + totalWeight += loot.weight; + } + + List drops = new ArrayList<>(); + for (LootEntry loot : lootList) { + if (loot.stack != null) { + float chance = ((float) loot.weight / totalWeight) * 100f; + drops.add(new DropInfo(loot.stack.copy(), chance)); + } + } + + ItemStack seedStack = ItemInfusedSeeds.getStackFromAspect(aspect); + + recipes.add(new SeedDropRecipeWrapper(seedStack, drops)); + } + + return recipes; + } + + @Override + public void loadTransferRects() { + transferRects.add(new RecipeTransferRect(new Rectangle(73, 22, 18, 12), getOverlayIdentifier())); + } + + @Override + public void loadCraftingRecipes(String outputId, Object... results) { + if (outputId.equals(getOverlayIdentifier()) && getClass() == NEIInfusedSeedRecipeHandler.class) { + for (SeedDropRecipeWrapper recipe : getSeedRecipes()) { + arecipes.add(new CachedSeedRecipe(recipe)); + } + } else { + super.loadCraftingRecipes(outputId, results); + } + } + + @Override + public void loadCraftingRecipes(ItemStack result) { + for (SeedDropRecipeWrapper recipe : getSeedRecipes()) { + for (DropInfo drop : recipe.drops) { + if (NEIServerUtils.areStacksSameTypeCrafting(result, drop.stack)) { + arecipes.add(new CachedSeedRecipe(recipe)); + break; + } + } + } + } + + @Override + public void loadUsageRecipes(ItemStack ingredient) { + if (ingredient != null && ingredient.getItem() instanceof ItemInfusedSeeds) { + Aspect aspectIn = ItemInfusedSeeds.getAspect(ingredient); + + if (aspectIn != null) { + for (SeedDropRecipeWrapper recipe : getSeedRecipes()) { + Aspect aspectRecipe = ItemInfusedSeeds.getAspect(recipe.seed); + if (aspectIn == aspectRecipe || aspectIn.getTag().equals(aspectRecipe.getTag())) { + arecipes.add(new CachedSeedRecipe(recipe)); + } + } + } + } + } + + @Override + public int getRecipeHeight(int recipeIndex) { + return 36 + 18 * (((CachedSeedRecipe) this.arecipes.get(recipeIndex)).rows + 1) + 6; + } + + @Override + public void drawBackground(int recipeIndex) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + GuiDraw.changeTexture(getGuiTexture()); + + GuiDraw.drawTexturedModalRect(74, 3, 7, 83, 18, 18); + + CachedSeedRecipe recipe = (CachedSeedRecipe) this.arecipes.get(recipeIndex); + int totalDrops = recipe.outputs.size(); + + for (int i = 0; i < totalDrops; i++) { + int col = i % SLOT_NUM_X; + int row = i / SLOT_NUM_X; + int xPos = 2 + 18 * col; + int yPos = 35 + 18 * row; + + GuiDraw.drawTexturedModalRect(xPos, yPos, 7, 83, 18, 18); + } + + GuiDraw.changeTexture(NEI_RECIPE_ARROW); + + GuiDraw.drawTexturedModalRect(74, 20, 0, 0, 18, 14); + } + + @Override + public List handleItemTooltip(GuiRecipe gui, ItemStack stack, List currenttip, int recipeIndex) { + CachedSeedRecipe recipe = (CachedSeedRecipe) this.arecipes.get(recipeIndex); + + for (DropInfo drop : recipe.wrapper.drops) { + if (NEIServerUtils.areStacksSameTypeCrafting(stack, drop.stack)) { + + String chancePrefix = StatCollector.translateToLocal("tt.nei.chance"); + + String chanceStr = CHANCE_FORMAT.format(drop.chance) + "%"; + currenttip.add(EnumChatFormatting.GRAY + chancePrefix + ": " + EnumChatFormatting.YELLOW + chanceStr); + + break; + } + } + + return currenttip; + } + + @Override + public String getGuiTexture() { + return "minecraft:textures/gui/container/inventory.png"; + } + + @Override + public String getOverlayIdentifier() { + return "tt_infused_seeds_drops"; + } + + @Override + public String getHandlerId() { + return "tt_infused_seeds_drops"; + } + + @Override + public String getRecipeName() { + return StatCollector.translateToLocal("tt.nei.category.infusedseeds"); + } +} diff --git a/src/main/java/thaumic/tinkerer/common/core/helper/AspectCropLootManager.java b/src/main/java/thaumic/tinkerer/common/core/helper/AspectCropLootManager.java index a2e0dbf1..5113d2f8 100644 --- a/src/main/java/thaumic/tinkerer/common/core/helper/AspectCropLootManager.java +++ b/src/main/java/thaumic/tinkerer/common/core/helper/AspectCropLootManager.java @@ -1,6 +1,8 @@ package thaumic.tinkerer.common.core.helper; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; @@ -22,29 +24,46 @@ import thaumic.tinkerer.common.item.ItemBrightNitor; import thaumic.tinkerer.common.item.ItemInfusedGrain; /** - * Created by pixlepix on 8/7/14. + * Created by pixlepix on 8/7/14, reworked by Spaghetti on 2026-08-21 These very lines of code will cause great trouble + * in the future. However, they have proven to be less chaotic than anticipated in the past, so they live on ... even if + * that means nerfing them to the ground. */ public class AspectCropLootManager { - private static HashMap> lootMap = new HashMap<>(); + public static class LootEntry { + + public final ItemStack stack; + public final int weight; + + public LootEntry(ItemStack stack, int weight) { + this.stack = stack; + this.weight = weight; + } + } + + private static final Random RAND = new Random(); + + private static HashMap> lootMap = new HashMap<>(); public static ItemStack getLootForAspect(Aspect aspect) { - HashMap aspectHashmap = lootMap.get(aspect); - // Find total value of the possible ItemStacks for the aspect - if (aspectHashmap == null) return null; - int sum = 0; + List aspectLootList = lootMap.get(aspect); - for (Integer i : aspectHashmap.values()) { - sum += i; + if (aspectLootList == null || aspectLootList.isEmpty()) { + return null; } + + int sum = 0; + for (LootEntry entry : aspectLootList) { + sum += entry.weight; + } + if (sum > 0) { - Random rand = new Random(); - int randInt = rand.nextInt(sum); - for (Map.Entry pair : aspectHashmap.entrySet()) { - if (randInt < pair.getValue()) { - return pair.getKey().copy(); + int randInt = RAND.nextInt(sum); + for (LootEntry entry : aspectLootList) { + if (randInt < entry.weight) { + return entry.stack.copy(); } - randInt -= pair.getValue(); + randInt -= entry.weight; } } return null; @@ -63,6 +82,9 @@ public class AspectCropLootManager { if (ore.contains(WordUtils.capitalizeFully(target)) || ore.contains(target)) { for (ItemStack stack : OreDictionary.getOres(ore)) { ItemStack newStack = stack.copy(); + if (newStack.getItemDamage() == OreDictionary.WILDCARD_VALUE) { + newStack.setItemDamage(0); + } newStack.stackSize = count; addAspectLoot(aspect, newStack); } @@ -71,12 +93,21 @@ public class AspectCropLootManager { } public static void addAspectLoot(Aspect aspect, ItemStack stack, int power) { - lootMap.get(aspect).put(stack, power); + if (stack == null || stack.getItem() == null) { + return; + } + + lootMap.putIfAbsent(aspect, new ArrayList<>()); + lootMap.get(aspect).add(new LootEntry(stack.copy(), power)); + } + + public static Map> getAllLoot() { + return lootMap; } public static void populateLootMap() { for (Aspect a : Aspect.aspects.values()) { - lootMap.put(a, new HashMap<>()); + lootMap.put(a, new ArrayList<>()); } addAspectLoot( Aspect.AIR, @@ -103,16 +134,14 @@ public class AspectCropLootManager { 1, ItemInfusedGrain.getMetaForAspect(Aspect.WATER))); - addAspectLoot(Aspect.ORDER, new ItemStack(Blocks.glass, 64)); - addAspectLoot(Aspect.ENTROPY, new ItemStack(Blocks.sand, 64)); + addAspectLoot(Aspect.ORDER, new ItemStack(Blocks.glass, 16)); + addAspectLoot(Aspect.ENTROPY, new ItemStack(Blocks.sand, 16)); addAspectLoot(Aspect.ELDRITCH, new ItemStack(Items.ender_pearl, 4), 10); addAspectLoot(Aspect.ELDRITCH, new ItemStack(Items.ender_eye, 4), 5); addAspectLoot(Aspect.ELDRITCH, "bucketEnder"); - // addAspectLoot(Aspect.TREE, "wood"); - - addAspectLoot(Aspect.TREE, new ItemStack(Blocks.log)); + addAspectLoot(Aspect.TREE, "logWood"); for (Aspect tag : Aspect.aspects.values()) { ItemStack i = new ItemStack(ConfigItems.itemWispEssence, 1, 0); @@ -120,15 +149,10 @@ public class AspectCropLootManager { addAspectLoot(Aspect.AURA, i); } - for (int i = 0; i < 24; i++) { - addAspectLoot(Aspect.BEAST, new ItemStack(Items.spawn_egg, 1, i)); - } - addAspectLoot(Aspect.MIND, new ItemStack(Items.paper, 64), 15); addAspectLoot(Aspect.MIND, new ItemStack(Items.book, 32), 10); addAspectLoot(Aspect.MIND, new ItemStack(Blocks.bookshelf, 16), 5); - addAspectLoot(Aspect.FLESH, new ItemStack(ConfigItems.itemResource, 16, 5), 4); addAspectLoot(Aspect.FLESH, new ItemStack(ConfigItems.itemResource, 16, 5), 1); addAspectLoot(Aspect.UNDEAD, new ItemStack(Items.rotten_flesh, 32)); @@ -137,16 +161,18 @@ public class AspectCropLootManager { Aspect.CRAFT, new ItemStack(ThaumicTinkerer.registry.getFirstBlockFromClass(BlockDarkQuartz.class), 32)); addAspectLoot(Aspect.CRAFT, new ItemStack(ConfigBlocks.blockStoneDevice, 16)); + addAspectLoot(Aspect.CRAFT, new ItemStack(Blocks.crafting_table, 4)); addAspectLoot(Aspect.HUNGER, new ItemStack(Items.nether_wart, 16)); - addAspectLoot(Aspect.COLD, new ItemStack(Items.snowball, 16)); - addAspectLoot(Aspect.COLD, "rodBlizz"); + addAspectLoot(Aspect.COLD, new ItemStack(Blocks.ice, 2)); + addAspectLoot(Aspect.COLD, new ItemStack(Items.snowball, 64)); + addAspectLoot(Aspect.COLD, new ItemStack(Blocks.snow, 32)); + addAspectLoot(Aspect.COLD, new ItemStack(Blocks.snow_layer, 8)); + addAspectLoot(Aspect.COLD, "rodBlizz", 1); + addAspectLoot(Aspect.PLANT, "grass"); addAspectLoot(Aspect.PLANT, "sapling"); - for (int i = 0; i < 6; i++) { - addAspectLoot(Aspect.PLANT, new ItemStack(Blocks.sapling, 1, i)); - } for (int i = 0; i < 12; i++) { addAspectLoot(Aspect.MAN, new ItemStack(ConfigItems.itemGolemCore, 1, i)); @@ -162,9 +188,7 @@ public class AspectCropLootManager { addAspectLoot(Aspect.WEAPON, new ItemStack(ConfigItems.itemSwordThaumium)); addAspectLoot(Aspect.TOOL, new ItemStack(ConfigItems.itemShovelThaumium)); addAspectLoot(Aspect.TOOL, new ItemStack(ConfigItems.itemAxeThaumium)); - addAspectLoot(Aspect.TRAVEL, new ItemStack(ConfigBlocks.blockCosmeticSolid, 8, 7)); - addAspectLoot(Aspect.SLIME, new ItemStack(Items.slime_ball, 16)); addAspectLoot(Aspect.SLIME, "slime"); addAspectLoot(Aspect.GREED, new ItemStack(Items.gold_ingot, 4)); @@ -176,12 +200,10 @@ public class AspectCropLootManager { new ItemStack(ThaumicTinkerer.registry.getFirstItemFromClass(ItemBrightNitor.class))); addAspectLoot(Aspect.MECHANISM, new ItemStack(Blocks.piston, 8)); - // addAspectLoot(Aspect.MECHANISM, "gear"); addAspectLoot(Aspect.CROP, new ItemStack(Items.wheat, 32)); addAspectLoot(Aspect.METAL, new ItemStack(Items.iron_ingot, 4), 100); - // addAspectLoot(Aspect.METAL, "iron"); addAspectLoot(Aspect.DEATH, new ItemStack(Items.bone, 32)); @@ -210,29 +232,36 @@ public class AspectCropLootManager { addAspectLoot(Aspect.HEAL, new ItemStack(Items.golden_apple)); addAspectLoot(Aspect.HEAL, new ItemStack(Items.cake)); + addAspectLoot(Aspect.HEAL, new ItemStack(Items.potionitem, 1, 8261)); - addAspectLoot(Aspect.SENSES, new ItemStack(Items.dye, 20, 4)); + for (int i = 0; i < 16; i++) { + addAspectLoot(Aspect.SENSES, new ItemStack(Items.dye, 1, i)); + addAspectLoot(Aspect.SENSES, new ItemStack(Blocks.stained_glass, 1, i)); + addAspectLoot(Aspect.SENSES, new ItemStack(Blocks.stained_glass_pane, 2, i)); + } - addAspectLoot(Aspect.SOUL, new ItemStack(Blocks.soul_sand, 64), 2); - addAspectLoot(Aspect.SOUL, new ItemStack(Blocks.netherrack, 64), 2); + addAspectLoot(Aspect.SOUL, new ItemStack(Blocks.soul_sand, 16), 2); + addAspectLoot(Aspect.SOUL, new ItemStack(Blocks.netherrack, 32), 2); addAspectLoot(Aspect.SOUL, new ItemStack(Blocks.nether_brick)); - addAspectLoot(Aspect.WEATHER, new ItemStack(Blocks.air)); - addAspectLoot(Aspect.WEATHER, "cloud", 100); + addAspectLoot(Aspect.WEATHER, "cloud", 64); addAspectLoot(Aspect.DARKNESS, new ItemStack(Blocks.obsidian, 10)); addAspectLoot(Aspect.VOID, new ItemStack(Items.bucket)); addAspectLoot(Aspect.VOID, "bucket"); + addAspectLoot(Aspect.VOID, "bowl"); addAspectLoot(Aspect.POISON, new ItemStack(ConfigItems.itemResource, 16, 3)); addAspectLoot(Aspect.LIFE, new ItemStack(Items.egg, 8)); addAspectLoot(Aspect.TRAP, new ItemStack(Blocks.web, 4)); + addAspectLoot(Aspect.TRAP, "trapdoorWood"); addAspectLoot(Aspect.TAINT, new ItemStack(ConfigItems.itemResource, 4, 11)); - addAspectLoot(Aspect.CRYSTAL, new ItemStack(Items.diamond)); + addAspectLoot(Aspect.CRYSTAL, "gemDiamond"); + addAspectLoot(Aspect.CRYSTAL, new ItemStack(Blocks.glass), 100); } } diff --git a/src/main/java/thaumic/tinkerer/common/core/proxy/TTCommonProxy.java b/src/main/java/thaumic/tinkerer/common/core/proxy/TTCommonProxy.java index 4813a37d..abc321f4 100644 --- a/src/main/java/thaumic/tinkerer/common/core/proxy/TTCommonProxy.java +++ b/src/main/java/thaumic/tinkerer/common/core/proxy/TTCommonProxy.java @@ -40,6 +40,7 @@ import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.relauncher.Side; import dan200.computercraft.api.ComputerCraftAPI; import li.cil.oc.api.Driver; +import thaumcraft.api.aspects.Aspect; import thaumcraft.api.aspects.IEssentiaTransport; import thaumcraft.api.wands.WandCap; import thaumcraft.api.wands.WandRod; @@ -81,6 +82,7 @@ import thaumic.tinkerer.common.core.helper.NumericAspectHelper; import thaumic.tinkerer.common.enchantment.ModEnchantments; import thaumic.tinkerer.common.enchantment.core.EnchantmentManager; import thaumic.tinkerer.common.item.ItemBloodSword; +import thaumic.tinkerer.common.item.ItemInfusedSeeds; import thaumic.tinkerer.common.item.SpellClothCraftingHandler; import thaumic.tinkerer.common.item.foci.ItemFocusDeflect; import thaumic.tinkerer.common.item.kami.wand.CapIchor; @@ -289,6 +291,11 @@ public class TTCommonProxy { Arrays.asList( new ItemStack(ThaumicTinkerer.registry.getFirstItemFromClass(ItemBloodSword.class)), necromancyTablet)); + + event.registerHandlerInfo( + new HandlerInfo.Builder("tt_infused_seeds_drops", LibMisc.MOD_NAME, LibMisc.MOD_ID) + .setDisplayStack(ItemInfusedSeeds.getStackFromAspect(Aspect.AIR)) + .setShowFavoritesButton(false).setShowOverlayButton(false).build()); } } } diff --git a/src/main/resources/assets/ttinkerer/lang/en_US.lang b/src/main/resources/assets/ttinkerer/lang/en_US.lang index 3ec8b5f4..cc09264b 100644 --- a/src/main/resources/assets/ttinkerer/lang/en_US.lang +++ b/src/main/resources/assets/ttinkerer/lang/en_US.lang @@ -654,3 +654,7 @@ ttwaila.pullingAdultType=Pulling: Adult %s ttwaila.pullingChildType=Pulling: Child %s ttwaila.pushingAdultType=Pushing: Adult %s ttwaila.pushingChildType=Pushing: Child %s + +# -- NEI +tt.nei.category.infusedseeds=Infused Seed Drops +tt.nei.chance=Drop Chance diff --git a/src/main/resources/assets/ttinkerer/textures/gui/neiRecipeArrow.png b/src/main/resources/assets/ttinkerer/textures/gui/neiRecipeArrow.png new file mode 100644 index 00000000..a7f4b89c Binary files /dev/null and b/src/main/resources/assets/ttinkerer/textures/gui/neiRecipeArrow.png differ