From 8f75d3a26485db62e7b31e31975067a15a64afe2 Mon Sep 17 00:00:00 2001 From: ReignOfFROZE Date: Tue, 17 Mar 2026 16:42:02 -0400 Subject: [PATCH 1/7] Make alchemic router not suck --- .../common/block/BlockReagentConduit.java | 38 ++++ .../items/energy/ItemAttunedCrystal.java | 213 ++++++++++++------ .../common/tileEntity/TEReagentConduit.java | 31 ++- .../assets/alchemicalwizardry/lang/en_US.lang | 21 +- 4 files changed, 217 insertions(+), 86 deletions(-) diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/block/BlockReagentConduit.java b/src/main/java/WayofTime/alchemicalWizardry/common/block/BlockReagentConduit.java index c8680e3bcc..3225516001 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/block/BlockReagentConduit.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/block/BlockReagentConduit.java @@ -1,13 +1,21 @@ package WayofTime.alchemicalWizardry.common.block; +import java.util.List; +import java.util.Map; + import net.minecraft.block.BlockContainer; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentTranslation; import net.minecraft.world.World; import WayofTime.alchemicalWizardry.AlchemicalWizardry; +import WayofTime.alchemicalWizardry.api.Int3; +import WayofTime.alchemicalWizardry.api.alchemy.energy.Reagent; +import WayofTime.alchemicalWizardry.api.items.interfaces.IReagentManipulator; import WayofTime.alchemicalWizardry.common.tileEntity.TEReagentConduit; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -41,6 +49,36 @@ public boolean canProvidePower() { @Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float what, float these, float are) { + if (!world.isRemote) { + ItemStack held = player.getHeldItem(); + if (held == null || !(held.getItem() instanceof IReagentManipulator)) { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile instanceof TEReagentConduit relay) { + if (relay.reagentTargetList.isEmpty()) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.reagentconduit.noconnections")); + } else { + player.addChatComponentMessage( + new ChatComponentTranslation("message.reagentconduit.connections")); + for (Map.Entry> entry : relay.reagentTargetList.entrySet()) { + Reagent reagent = entry.getKey(); + List offsets = entry.getValue(); + if (offsets == null) continue; + for (Int3 offset : offsets) { + player.addChatComponentMessage( + new ChatComponentTranslation( + "message.reagentconduit.connection.entry", + reagent.name(), + x + offset.x(), + y + offset.y(), + z + offset.z())); + } + } + } + return true; + } + } + } return super.onBlockActivated(world, x, y, z, player, side, what, these, are); } diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java index 12bb3b580c..90d99c4962 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java @@ -60,6 +60,9 @@ public String getItemStackDisplayName(ItemStack stack) { public void addInformation(ItemStack item, EntityPlayer player, List tooltip, boolean adv) { tooltip.add(StatCollector.translateToLocal("tooltip.attunedcrystal.desc1")); tooltip.add(StatCollector.translateToLocal("tooltip.attunedcrystal.desc2")); + tooltip.add(StatCollector.translateToLocal("tooltip.attunedcrystal.desc3")); + tooltip.add(StatCollector.translateToLocal("tooltip.attunedcrystal.desc4")); + tooltip.add(StatCollector.translateToLocal("tooltip.attunedcrystal.desc5")); if (item.getTagCompound() == null) { return; @@ -136,97 +139,159 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer if (movingobjectposition == null) { if (player.isSneaking()) { this.setHasSavedCoordinates(itemStack, false); + if (!itemStack.hasTagCompound()) { + itemStack.setTagCompound(new NBTTagCompound()); + } + itemStack.getTagCompound().setString("reagent", ""); player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.clearing")); } return itemStack; - } else { - if (movingobjectposition.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { - int x = movingobjectposition.blockX; - int y = movingobjectposition.blockY; - int z = movingobjectposition.blockZ; + } + + if (movingobjectposition.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) { + return itemStack; + } - TileEntity tile = world.getTileEntity(x, y, z); + int x = movingobjectposition.blockX; + int y = movingobjectposition.blockY; + int z = movingobjectposition.blockZ; - if (!(tile instanceof IReagentHandler relay)) { + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof IReagentHandler relay)) { + return itemStack; + } + + if (player.isSneaking()) { + if (this.getHasSavedCoordinates(itemStack)) { + Int3 coords = this.getCoordinates(itemStack); + int dimension = this.getDimension(itemStack); + + if (coords == null) { return itemStack; } - if (player.isSneaking()) { - ReagentContainerInfo[] infos = relay.getContainerInfo(ForgeDirection.UNKNOWN); - if (infos != null) { - List reagentList = getReagents(infos); + // Sneak+right-click saved source block again -> clear all of reagent's connections + if (coords.x() == x && coords.y() == y && coords.z() == z) { + TileEntity pastTile = world.getTileEntity(coords.x(), coords.y(), coords.z()); + if (!(pastTile instanceof TEReagentConduit pastRelay)) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); + return itemStack; + } + Reagent reagent = this.getReagent(itemStack); + if (reagent == null) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.noreagent")); + return itemStack; + } + pastRelay.reagentTargetList.remove(reagent); + this.setHasSavedCoordinates(itemStack, false); + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.clearedreagent", reagent.name())); + world.markBlockForUpdate(coords.x(), coords.y(), coords.z()); + return itemStack; + } - Reagent pastReagent = this.getReagent(itemStack); + if (dimension != world.provider.dimensionId || Math.abs(coords.x() - x) > maxDistance + || Math.abs(coords.y() - y) > maxDistance + || Math.abs(coords.z() - z) > maxDistance) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.toofar")); + return itemStack; + } - if (reagentList.isEmpty()) { - return itemStack; - } + TileEntity pastTile = world.getTileEntity(coords.x(), coords.y(), coords.z()); + if (!(pastTile instanceof TEReagentConduit pastRelay)) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); + return itemStack; + } - int reagentLocation; + Reagent reagent = this.getReagent(itemStack); + if (reagent == null) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.noreagent")); + return itemStack; + } - reagentLocation = reagentList.indexOf(pastReagent); + boolean removed = pastRelay.removeReagentDestinationViaActual(reagent, x, y, z); + player.addChatComponentMessage( + new ChatComponentTranslation( + removed ? "message.attunedcrystal.removed" + : "message.attunedcrystal.error.notremoved")); + world.markBlockForUpdate(coords.x(), coords.y(), coords.z()); + return itemStack; + } - if (reagentLocation == -1 || reagentLocation + 1 >= reagentList.size()) { - this.setReagentWithNotification(itemStack, reagentList.getFirst(), player); - } else { - this.setReagentWithNotification(itemStack, reagentList.get(reagentLocation + 1), player); - } - } + // No saved coords -> cycle reagent selection + ReagentContainerInfo[] infos = relay.getContainerInfo(ForgeDirection.UNKNOWN); + if (infos != null) { + List reagentList = getReagents(infos); + if (reagentList.isEmpty()) { + return itemStack; + } + Reagent pastReagent = this.getReagent(itemStack); + int reagentLocation = reagentList.indexOf(pastReagent); + if (reagentLocation == -1 || reagentLocation + 1 >= reagentList.size()) { + this.setReagentWithNotification(itemStack, reagentList.getFirst(), player); } else { - if (this.getHasSavedCoordinates(itemStack)) { - Int3 coords = this.getCoordinates(itemStack); - int dimension = this.getDimension(itemStack); - - if (coords == null) { - return itemStack; - } - - if (dimension != world.provider.dimensionId || Math.abs(coords.x() - x) > maxDistance - || Math.abs(coords.y() - y) > maxDistance - || Math.abs(coords.z() - z) > maxDistance) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.toofar")); - return itemStack; - } - - TileEntity pastTile = world.getTileEntity(coords.x(), coords.y(), coords.z()); - if (!(pastTile instanceof TEReagentConduit pastRelay)) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); - return itemStack; - } - - Reagent reagent = this.getReagent(itemStack); - - if (reagent == null) { - return itemStack; - } - - if (player.isSneaking()) { - pastRelay.removeReagentDestinationViaActual(reagent, x, y, z); - } else { - if (pastRelay.addReagentDestinationViaActual(reagent, x, y, z)) { - player.addChatComponentMessage( - new ChatComponentText( - StatCollector.translateToLocal("message.attunedcrystal.linked") + " " - + reagent.name())); - } else { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.noconnections")); - } - } - world.markBlockForUpdate(coords.x(), coords.y(), coords.z()); - } else { - int dimension = world.provider.dimensionId; - - this.setDimension(itemStack, dimension); - this.setCoordinates(itemStack, new Int3(x, y, z)); - - player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.linking")); - } + this.setReagentWithNotification(itemStack, reagentList.get(reagentLocation + 1), player); } } + return itemStack; + } + + // Not sneaking + if (this.getHasSavedCoordinates(itemStack)) { + Int3 coords = this.getCoordinates(itemStack); + int dimension = this.getDimension(itemStack); + + if (coords == null) { + return itemStack; + } + + if (dimension != world.provider.dimensionId || Math.abs(coords.x() - x) > maxDistance + || Math.abs(coords.y() - y) > maxDistance + || Math.abs(coords.z() - z) > maxDistance) { + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.error.toofar")); + return itemStack; + } + + TileEntity pastTile = world.getTileEntity(coords.x(), coords.y(), coords.z()); + if (!(pastTile instanceof TEReagentConduit pastRelay)) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); + return itemStack; + } + + Reagent reagent = this.getReagent(itemStack); + if (reagent == null) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.noreagent")); + return itemStack; + } + + if (pastRelay.hasReagentDestination(reagent, x, y, z)) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.duplicate")); + } else if (pastRelay.addReagentDestinationViaActual(reagent, x, y, z)) { + int used = pastRelay.getTotalConnections(); + int max = pastRelay.maxConnextions; + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.linked", reagent.name(), used, max)); + } else { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.noconnections")); + } + world.markBlockForUpdate(coords.x(), coords.y(), coords.z()); + } else { + int dimension = world.provider.dimensionId; + this.setDimension(itemStack, dimension); + this.setCoordinates(itemStack, new Int3(x, y, z)); + + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.linking", x, y, z)); } return itemStack; diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEReagentConduit.java b/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEReagentConduit.java index 4a204a9ea0..644828a14f 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEReagentConduit.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/tileEntity/TEReagentConduit.java @@ -415,17 +415,31 @@ public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity packet) { readClientNBT(packet.func_148857_g()); } - public boolean addReagentDestinationViaOffset(Reagent reagent, int xOffset, int yOffset, int zOffset) { - int totalConnections = 0; + public int getTotalConnections() { + int total = 0; + for (List list : this.reagentTargetList.values()) { + if (list != null) { + total += list.size(); + } + } + return total; + } - for (Entry> entry : this.reagentTargetList.entrySet()) { - if (entry.getValue() != null) { - totalConnections += entry.getValue().size(); + public boolean hasReagentDestination(Reagent reagent, int x, int y, int z) { + int xOffset = x - this.xCoord; + int yOffset = y - this.yCoord; + int zOffset = z - this.zCoord; + if (this.reagentTargetList.containsKey(reagent)) { + List coords = this.reagentTargetList.get(reagent); + if (coords != null) { + return coords.contains(new Int3(xOffset, yOffset, zOffset)); } } + return false; + } - if (totalConnections >= this.maxConnextions) { - // Send message that it cannot be done? Maybe add a Player instance + public boolean addReagentDestinationViaOffset(Reagent reagent, int xOffset, int yOffset, int zOffset) { + if (getTotalConnections() >= this.maxConnextions) { return false; } @@ -442,6 +456,9 @@ public boolean addReagentDestinationViaOffset(Reagent reagent, int xOffset, int newCoordList.add(newCoord); this.reagentTargetList.put(reagent, newCoordList); } else { + if (coordList.contains(newCoord)) { + return false; + } coordList.add(newCoord); } diff --git a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang index dd3f62ec52..04b57c946d 100644 --- a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang +++ b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang @@ -434,8 +434,11 @@ tooltip.alchemyflask.caution=CAUTION: Contents are throwable tooltip.alchemyflask.swigsleft=Swigs Left: tooltip.armorinhibitor.desc1=Used to suppress a soul's tooltip.armorinhibitor.desc2=unnatural abilities. -tooltip.attunedcrystal.desc1=A tool to tune alchemy -tooltip.attunedcrystal.desc2=reagent transmission +tooltip.attunedcrystal.desc1=1) Sneak+right-click relay to select reagent +tooltip.attunedcrystal.desc2=2) Right-click source relay +tooltip.attunedcrystal.desc3=3) Right-click destination relay to link +tooltip.attunedcrystal.desc4=Sneak+right-click air to clear selection. +tooltip.attunedcrystal.desc5=Sneak+right-click relay to remove/clear links. tooltip.blankspell.desc=Crystal of infinite possibilities. tooltip.bloodframe.desc=Stirs bees into a frenzy. tooltip.bloodletterpack.desc=This pack really chafes... @@ -548,13 +551,21 @@ message.altar.progress=Altar's Progress: %,d LP / %,d LP message.altar.inputtank= Input Tank: %,d LP message.altar.outputtank= Output Tank: %,d LP message.altar.hunger=[BM] Your high regeneration rate has caused you to become hungry... -message.attunedcrystal.clearing=Clearing saved container... +message.attunedcrystal.clearing=Cleared saved source and reagent selection. message.attunedcrystal.error.cannotfind=Can no longer find linked container. message.attunedcrystal.error.noconnections=Linked container has no connections remaining! message.attunedcrystal.error.toofar=Linked container is either too far or is in a different dimension. -message.attunedcrystal.linked=Container is now linked. Transmitting: -message.attunedcrystal.linking=Linking to selected container. +message.attunedcrystal.error.noreagent=No reagent selected! Sneak+right-click a relay to select one. +message.attunedcrystal.error.duplicate=Already connected to that destination! +message.attunedcrystal.error.notremoved=No matching connection found to remove. +message.attunedcrystal.removed=Connection removed successfully. +message.attunedcrystal.clearedreagent=Cleared all %s connections from this relay. +message.attunedcrystal.linked=Linked! Transmitting %s. (%s/%s connections used) +message.attunedcrystal.linking=Source relay saved at %s, %s, %s. Right-click a destination to link. message.attunedcrystal.setto=Attuned Crystal now set to: +message.reagentconduit.noconnections=This relay has no routing connections. +message.reagentconduit.connections=Routing connections: +message.reagentconduit.connection.entry= %s -> (%s, %s, %s) message.demon.shallfollow=I shall follow and protect you! message.demon.willstay=I will stay here for now, Master. message.destinationclearer.cleared=Destination list now cleared. From 571ce697bfca7e33286b2f5f55b01a4bebb9ceb0 Mon Sep 17 00:00:00 2001 From: ReignOfFROZE Date: Thu, 14 May 2026 12:53:53 -0400 Subject: [PATCH 2/7] Comments --- .../client/nei/IMCForNEI.java | 1 + .../items/energy/ItemAttunedCrystal.java | 174 ++++++++---------- .../items/energy/ItemDestinationClearer.java | 68 +++++-- .../assets/alchemicalwizardry/lang/en_US.lang | 36 ++-- 4 files changed, 158 insertions(+), 121 deletions(-) diff --git a/src/main/java/WayofTime/alchemicalWizardry/client/nei/IMCForNEI.java b/src/main/java/WayofTime/alchemicalWizardry/client/nei/IMCForNEI.java index 05895f802d..ed6d737805 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/client/nei/IMCForNEI.java +++ b/src/main/java/WayofTime/alchemicalWizardry/client/nei/IMCForNEI.java @@ -96,6 +96,7 @@ public static void IMCSender() { sendInfoPage("AWWayofTime masterStone,blockAlchemicCalcinator", "nei.infopage.reagents.1"); sendInfoPage("AWWayofTime masterStone,blockAlchemicCalcinator|", "nei.infopage.reagents.2"); sendInfoPage("AWWayofTime masterStone,blockAlchemicCalcinator,itemAttunedCrystal", "nei.infopage.reagents.3"); + sendInfoPage("AWWayofTime masterStone,blockAlchemicCalcinator,itemAttunedCrystal", "nei.infopage.reagents.3b"); sendInfoPage( "AWWayofTime masterStone,blockAlchemicCalcinator,itemTankSegmenter,itemDestinationClearer", "nei.infopage.reagents.4"); diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java index 90d99c4962..ce5393baf2 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java @@ -134,22 +134,21 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer return itemStack; } - MovingObjectPosition movingobjectposition = this.getMovingObjectPositionFromPlayer(world, player, false); - - if (movingobjectposition == null) { - if (player.isSneaking()) { + // Sneak wipes the source first, then the reagent — regardless of where the cursor points. + if (player.isSneaking()) { + if (this.getHasSavedCoordinates(itemStack)) { this.setHasSavedCoordinates(itemStack, false); - if (!itemStack.hasTagCompound()) { - itemStack.setTagCompound(new NBTTagCompound()); - } - itemStack.getTagCompound().setString("reagent", ""); player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.clearing")); + } else if (this.getReagent(itemStack) != null) { + this.clearReagent(itemStack); + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.reagentcleared")); } - return itemStack; } - if (movingobjectposition.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) { + MovingObjectPosition movingobjectposition = this.getMovingObjectPositionFromPlayer(world, player, false); + if (movingobjectposition == null + || movingobjectposition.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) { return itemStack; } @@ -162,92 +161,30 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer return itemStack; } - if (player.isSneaking()) { - if (this.getHasSavedCoordinates(itemStack)) { - Int3 coords = this.getCoordinates(itemStack); - int dimension = this.getDimension(itemStack); - - if (coords == null) { - return itemStack; - } - - // Sneak+right-click saved source block again -> clear all of reagent's connections - if (coords.x() == x && coords.y() == y && coords.z() == z) { - TileEntity pastTile = world.getTileEntity(coords.x(), coords.y(), coords.z()); - if (!(pastTile instanceof TEReagentConduit pastRelay)) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); - return itemStack; - } - Reagent reagent = this.getReagent(itemStack); - if (reagent == null) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.noreagent")); - return itemStack; - } - pastRelay.reagentTargetList.remove(reagent); - this.setHasSavedCoordinates(itemStack, false); - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.clearedreagent", reagent.name())); - world.markBlockForUpdate(coords.x(), coords.y(), coords.z()); - return itemStack; - } - - if (dimension != world.provider.dimensionId || Math.abs(coords.x() - x) > maxDistance - || Math.abs(coords.y() - y) > maxDistance - || Math.abs(coords.z() - z) > maxDistance) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.toofar")); - return itemStack; - } - - TileEntity pastTile = world.getTileEntity(coords.x(), coords.y(), coords.z()); - if (!(pastTile instanceof TEReagentConduit pastRelay)) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); - return itemStack; - } - - Reagent reagent = this.getReagent(itemStack); - if (reagent == null) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.noreagent")); - return itemStack; - } - - boolean removed = pastRelay.removeReagentDestinationViaActual(reagent, x, y, z); - player.addChatComponentMessage( - new ChatComponentTranslation( - removed ? "message.attunedcrystal.removed" - : "message.attunedcrystal.error.notremoved")); - world.markBlockForUpdate(coords.x(), coords.y(), coords.z()); + if (this.getHasSavedCoordinates(itemStack)) { + Int3 coords = this.getCoordinates(itemStack); + int dimension = this.getDimension(itemStack); + if (coords == null) { return itemStack; } - // No saved coords -> cycle reagent selection - ReagentContainerInfo[] infos = relay.getContainerInfo(ForgeDirection.UNKNOWN); - if (infos != null) { - List reagentList = getReagents(infos); - if (reagentList.isEmpty()) { + // Re-clicking the saved source cycles its reagents, never tries to self-link. + if (dimension == world.provider.dimensionId && coords.x() == x + && coords.y() == y + && coords.z() == z) { + List reagentList = collectReagents(relay); + if (reagentList.size() <= 1) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.cannotlinktoself")); return itemStack; } + Reagent pastReagent = this.getReagent(itemStack); int reagentLocation = reagentList.indexOf(pastReagent); - if (reagentLocation == -1 || reagentLocation + 1 >= reagentList.size()) { - this.setReagentWithNotification(itemStack, reagentList.getFirst(), player); - } else { - this.setReagentWithNotification(itemStack, reagentList.get(reagentLocation + 1), player); - } - } - return itemStack; - } - - // Not sneaking - if (this.getHasSavedCoordinates(itemStack)) { - Int3 coords = this.getCoordinates(itemStack); - int dimension = this.getDimension(itemStack); - - if (coords == null) { + Reagent next = (reagentLocation == -1 || reagentLocation + 1 >= reagentList.size()) + ? reagentList.getFirst() + : reagentList.get(reagentLocation + 1); + this.setReagentWithNotification(itemStack, next, player); return itemStack; } @@ -260,6 +197,8 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer TileEntity pastTile = world.getTileEntity(coords.x(), coords.y(), coords.z()); if (!(pastTile instanceof TEReagentConduit pastRelay)) { + // Saved source is gone — clear it so the player can start over without a manual reset. + this.setHasSavedCoordinates(itemStack, false); player.addChatComponentMessage( new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); return itemStack; @@ -280,23 +219,63 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer int max = pastRelay.maxConnextions; player.addChatComponentMessage( new ChatComponentTranslation("message.attunedcrystal.linked", reagent.name(), used, max)); + // Successful link: clear the source so the next click starts a fresh link, but + // keep the reagent so the player can fan out to multiple destinations quickly. + this.setHasSavedCoordinates(itemStack, false); } else { player.addChatComponentMessage( new ChatComponentTranslation("message.attunedcrystal.error.noconnections")); } world.markBlockForUpdate(coords.x(), coords.y(), coords.z()); - } else { - int dimension = world.provider.dimensionId; - this.setDimension(itemStack, dimension); - this.setCoordinates(itemStack, new Int3(x, y, z)); + return itemStack; + } + + // No saved source — this click saves one and (when useful) copies its reagent. + if (tile instanceof TEReagentConduit conduit && conduit.getTotalConnections() >= conduit.maxConnextions) { + player.addChatComponentMessage( + new ChatComponentTranslation("message.attunedcrystal.error.sourcefull")); + return itemStack; + } + List reagentList = collectReagents(relay); + Reagent currentReagent = this.getReagent(itemStack); + if (reagentList.isEmpty() && currentReagent == null) { player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.linking", x, y, z)); + new ChatComponentTranslation("message.attunedcrystal.error.nothingtocopy")); + return itemStack; } + // Keep the crystal's existing reagent if the source has it (or if the source is empty); + // otherwise replace with the source's first tank. + if (!reagentList.isEmpty() && (currentReagent == null || !reagentList.contains(currentReagent))) { + this.setReagentWithNotification(itemStack, reagentList.getFirst(), player); + } + + this.setDimension(itemStack, world.provider.dimensionId); + this.setCoordinates(itemStack, new Int3(x, y, z)); + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.linking", x, y, z)); + return itemStack; } + private static List collectReagents(IReagentHandler relay) { + List reagentList = new LinkedList<>(); + ReagentContainerInfo[] infos = relay.getContainerInfo(ForgeDirection.UNKNOWN); + if (infos == null) { + return reagentList; + } + for (ReagentContainerInfo info : infos) { + if (info == null) continue; + ReagentStack reagentStack = info.reagent; + if (reagentStack == null) continue; + Reagent reagent = reagentStack.reagent; + if (reagent != null && !reagentList.contains(reagent)) { + reagentList.add(reagent); + } + } + return reagentList; + } + public static List getReagents(ReagentContainerInfo[] infos) { List reagentList = new LinkedList<>(); for (ReagentContainerInfo info : infos) { @@ -313,6 +292,13 @@ public static List getReagents(ReagentContainerInfo[] infos) { return reagentList; } + public void clearReagent(ItemStack stack) { + if (!stack.hasTagCompound()) { + stack.setTagCompound(new NBTTagCompound()); + } + stack.getTagCompound().setString("reagent", ""); + } + public void setCoordinates(ItemStack stack, Int3 coords) { if (!stack.hasTagCompound()) { stack.setTagCompound(new NBTTagCompound()); diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java index 94bb4981ea..3acc5ed9ab 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java @@ -1,6 +1,8 @@ package WayofTime.alchemicalWizardry.common.items.energy; +import java.util.Iterator; import java.util.List; +import java.util.Map; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.player.EntityPlayer; @@ -13,6 +15,8 @@ import net.minecraft.world.World; import WayofTime.alchemicalWizardry.AlchemicalWizardry; +import WayofTime.alchemicalWizardry.api.Int3; +import WayofTime.alchemicalWizardry.api.alchemy.energy.Reagent; import WayofTime.alchemicalWizardry.api.items.interfaces.IReagentManipulator; import WayofTime.alchemicalWizardry.common.tileEntity.TEReagentConduit; import cpw.mods.fml.relauncher.Side; @@ -36,6 +40,7 @@ public void registerIcons(IIconRegister iconRegister) { public void addInformation(ItemStack item, EntityPlayer player, List tooltip, boolean adv) { tooltip.add(StatCollector.translateToLocal("tooltip.destclearer.desc1")); tooltip.add(StatCollector.translateToLocal("tooltip.destclearer.desc2")); + tooltip.add(StatCollector.translateToLocal("tooltip.destclearer.desc3")); } @Override @@ -45,26 +50,67 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer } MovingObjectPosition movingobjectposition = this.getMovingObjectPositionFromPlayer(world, player, false); - - if (movingobjectposition == null) { + if (movingobjectposition == null + || movingobjectposition.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) { return itemStack; } - if (movingobjectposition.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { - int x = movingobjectposition.blockX; - int y = movingobjectposition.blockY; - int z = movingobjectposition.blockZ; - TileEntity tile = world.getTileEntity(x, y, z); + int x = movingobjectposition.blockX; + int y = movingobjectposition.blockY; + int z = movingobjectposition.blockZ; - if (!(tile instanceof TEReagentConduit relay)) { - return itemStack; - } + TileEntity tile = world.getTileEntity(x, y, z); + if (!(tile instanceof TEReagentConduit relay)) { + return itemStack; + } + if (player.isSneaking()) { + int removed = clearIncomingConnections(world, x, y, z); + player.addChatComponentMessage( + new ChatComponentTranslation("message.destinationclearer.incoming.cleared", removed)); + } else { relay.reagentTargetList.clear(); - + world.markBlockForUpdate(x, y, z); player.addChatComponentMessage(new ChatComponentTranslation("message.destinationclearer.cleared")); } return itemStack; } + + private static int clearIncomingConnections(World world, int x, int y, int z) { + int range = ItemAttunedCrystal.maxDistance; + int totalRemoved = 0; + for (int dx = -range; dx <= range; dx++) { + for (int dy = -range; dy <= range; dy++) { + for (int dz = -range; dz <= range; dz++) { + if (dx == 0 && dy == 0 && dz == 0) continue; + TileEntity neighbor = world.getTileEntity(x + dx, y + dy, z + dz); + if (!(neighbor instanceof TEReagentConduit src)) continue; + + boolean changed = false; + Iterator>> entries = src.reagentTargetList.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry> entry = entries.next(); + List coords = entry.getValue(); + if (coords == null) continue; + Iterator it = coords.iterator(); + while (it.hasNext()) { + Int3 off = it.next(); + if (src.xCoord + off.x() == x && src.yCoord + off.y() == y + && src.zCoord + off.z() == z) { + it.remove(); + changed = true; + totalRemoved++; + } + } + if (coords.isEmpty()) entries.remove(); + } + if (changed) { + world.markBlockForUpdate(src.xCoord, src.yCoord, src.zCoord); + } + } + } + } + return totalRemoved; + } } diff --git a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang index 04b57c946d..611facf8a0 100644 --- a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang +++ b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang @@ -434,11 +434,11 @@ tooltip.alchemyflask.caution=CAUTION: Contents are throwable tooltip.alchemyflask.swigsleft=Swigs Left: tooltip.armorinhibitor.desc1=Used to suppress a soul's tooltip.armorinhibitor.desc2=unnatural abilities. -tooltip.attunedcrystal.desc1=1) Sneak+right-click relay to select reagent -tooltip.attunedcrystal.desc2=2) Right-click source relay -tooltip.attunedcrystal.desc3=3) Right-click destination relay to link -tooltip.attunedcrystal.desc4=Sneak+right-click air to clear selection. -tooltip.attunedcrystal.desc5=Sneak+right-click relay to remove/clear links. +tooltip.attunedcrystal.desc1=1) Right-click a source relay to save it and copy its AR. +tooltip.attunedcrystal.desc2=2) Right-click the same source again to cycle its AR. +tooltip.attunedcrystal.desc3=3) Right-click a destination relay to link (keeps AR for fan-out). +tooltip.attunedcrystal.desc4=Sneak+right-click to clear the saved source. +tooltip.attunedcrystal.desc5=Sneak+right-click again to clear the held reagent. tooltip.blankspell.desc=Crystal of infinite possibilities. tooltip.bloodframe.desc=Stirs bees into a frenzy. tooltip.bloodletterpack.desc=This pack really chafes... @@ -458,8 +458,9 @@ tooltip.crystalbelljar.empty=- Empty tooltip.demonictelepfocus.desc1=A stronger version of the focus, tooltip.demonictelepfocus.desc2=using a demonic shard tooltip.demonplacer.desc=Used to spawn demons. -tooltip.destclearer.desc1=Used to clear the destination -tooltip.destclearer.desc2=list for an alchemy container +tooltip.destclearer.desc1=Right-click a relay to clear its outgoing links. +tooltip.destclearer.desc2=Sneak+right-click a relay to clear links +tooltip.destclearer.desc3=pointing AT it from nearby relays. tooltip.diablokey.desc=Binds other items to the owner's network tooltip.divinationsigil.desc1=Peer into the soul to tooltip.divinationsigil.desc2=get the current essence @@ -551,15 +552,16 @@ message.altar.progress=Altar's Progress: %,d LP / %,d LP message.altar.inputtank= Input Tank: %,d LP message.altar.outputtank= Output Tank: %,d LP message.altar.hunger=[BM] Your high regeneration rate has caused you to become hungry... -message.attunedcrystal.clearing=Cleared saved source and reagent selection. -message.attunedcrystal.error.cannotfind=Can no longer find linked container. +message.attunedcrystal.clearing=Cleared saved source. +message.attunedcrystal.reagentcleared=Cleared held reagent. +message.attunedcrystal.error.cannotfind=Can no longer find saved source. message.attunedcrystal.error.noconnections=Linked container has no connections remaining! -message.attunedcrystal.error.toofar=Linked container is either too far or is in a different dimension. -message.attunedcrystal.error.noreagent=No reagent selected! Sneak+right-click a relay to select one. +message.attunedcrystal.error.toofar=Saved source is either too far or is in a different dimension. +message.attunedcrystal.error.noreagent=No reagent selected! Right-click a source relay to copy one. message.attunedcrystal.error.duplicate=Already connected to that destination! -message.attunedcrystal.error.notremoved=No matching connection found to remove. -message.attunedcrystal.removed=Connection removed successfully. -message.attunedcrystal.clearedreagent=Cleared all %s connections from this relay. +message.attunedcrystal.error.sourcefull=Source has no more open outgoing links. +message.attunedcrystal.error.cannotlinktoself=Cannot link a source to itself. +message.attunedcrystal.error.nothingtocopy=Source has no reagents to copy. message.attunedcrystal.linked=Linked! Transmitting %s. (%s/%s connections used) message.attunedcrystal.linking=Source relay saved at %s, %s, %s. Right-click a destination to link. message.attunedcrystal.setto=Attuned Crystal now set to: @@ -569,6 +571,7 @@ message.reagentconduit.connection.entry= %s -> (%s, %s, %s) message.demon.shallfollow=I shall follow and protect you! message.demon.willstay=I will stay here for now, Master. message.destinationclearer.cleared=Destination list now cleared. +message.destinationclearer.incoming.cleared=Cleared %s incoming connection(s) from nearby relays. message.divinationsigil.amount=Amount: %,d AR message.divinationsigil.currentessence=Current Essence: %,d LP message.divinationsigil.reagent=Reagent: %s @@ -748,6 +751,7 @@ nei.infopage.rituals.2=To build a ritual, place a Master Ritual Stone surrounded nei.infopage.rituals.3=Once the ritual is assembled, right-click the Master Ritual Stone with a bound Activation Crystal. If everything is in place and your Soul Network contains sufficient LP, the ritual will commence! Each ritual has a unique effect. Experimentation is encouraged to discover the full potential of the Master Ritual Stone. nei.infopage.reagents.1=Some rituals can be modified by providing reagents to the Master Ritual Stone. However, raw reagents are too impure to be used directly. They must first be refined in an Alchemic Calcinator into AR (Alchemy Reagent), a pure essence usable by the ritual. nei.infopage.reagents.2=To use an Alchemic Calcinator, right-click it with a bound Blood Orb, and then right-click it with the reagent item. Reagents may also be inserted via hoppers or pipes. The reagent will be consumed and converted into AR, which the Calcinator will store internally. -nei.infopage.reagents.3=An Alchemic Router is required to transfer AR. Shift-right-click a block containing AR to attune the Router to that reagent. Then right-click the source block, followed by the destination block, to create a link. Shift-right-click in the air to remove the currently saved source. -nei.infopage.reagents.4=An Alchemic Cleanser may be used to remove AR links by using it on the source block. An Alchemic Segmenter may be used to limit how many internal AR tanks a single reagent may occupy; it is attuned in the same way as the Router. +nei.infopage.reagents.3=An Alchemic Router (Attuned Crystal) transfers AR. Right-click a block holding AR to save it as the source — the Router copies that source's AR automatically. Right-click the saved source again to cycle through its remaining AR types. Right-click a different block to link it as a destination; the source clears but the AR stays, so you can fan out to many destinations quickly. +nei.infopage.reagents.3b=Sneak+right-click anywhere to clear the saved source; sneak+right-click again to clear the held AR. Right-clicking a relay with an empty hand prints its current outgoing routing connections to chat. +nei.infopage.reagents.4=An Alchemic Cleanser clears AR routing connections — right-click a relay to wipe its outgoing links, or sneak+right-click to wipe nearby relays' links pointing AT it. An Alchemic Segmenter may be used to limit how many internal AR tanks a single reagent may occupy; it is attuned in the same way as the Router. nei.infopage.reagents.5=The range of AR links is limited to a few blocks. To extend the transfer distance, use Alchemic Relays. Crystal Belljars may be placed to store AR, and they will retain their contents when broken. From ffa58879f2e8668efd5b0fe7ab92f2ef8791a3d6 Mon Sep 17 00:00:00 2001 From: ReignOfFROZE Date: Thu, 14 May 2026 12:56:45 -0400 Subject: [PATCH 3/7] Update tooltip to not use shorthand that wasn't explained on tooltip --- .../resources/assets/alchemicalwizardry/lang/en_US.lang | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang index 611facf8a0..ea89536f01 100644 --- a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang +++ b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang @@ -434,9 +434,9 @@ tooltip.alchemyflask.caution=CAUTION: Contents are throwable tooltip.alchemyflask.swigsleft=Swigs Left: tooltip.armorinhibitor.desc1=Used to suppress a soul's tooltip.armorinhibitor.desc2=unnatural abilities. -tooltip.attunedcrystal.desc1=1) Right-click a source relay to save it and copy its AR. -tooltip.attunedcrystal.desc2=2) Right-click the same source again to cycle its AR. -tooltip.attunedcrystal.desc3=3) Right-click a destination relay to link (keeps AR for fan-out). +tooltip.attunedcrystal.desc1=1) Right-click a source relay to save it and copy its reagent. +tooltip.attunedcrystal.desc2=2) Right-click the same source again to cycle its reagent. +tooltip.attunedcrystal.desc3=3) Right-click a destination relay to link. tooltip.attunedcrystal.desc4=Sneak+right-click to clear the saved source. tooltip.attunedcrystal.desc5=Sneak+right-click again to clear the held reagent. tooltip.blankspell.desc=Crystal of infinite possibilities. From 10f4068e2d39e51a5af7592d5bda778506e5928c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 13:15:19 -0400 Subject: [PATCH 4/7] Spotless apply for branch alchemic-router-not-bad for #124 (#129) Co-authored-by: GitHub GTNH Actions <> --- .../items/energy/ItemAttunedCrystal.java | 19 ++++++------------- .../items/energy/ItemDestinationClearer.java | 3 +-- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java index ce5393baf2..3976be96f3 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemAttunedCrystal.java @@ -169,9 +169,7 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer } // Re-clicking the saved source cycles its reagents, never tries to self-link. - if (dimension == world.provider.dimensionId && coords.x() == x - && coords.y() == y - && coords.z() == z) { + if (dimension == world.provider.dimensionId && coords.x() == x && coords.y() == y && coords.z() == z) { List reagentList = collectReagents(relay); if (reagentList.size() <= 1) { player.addChatComponentMessage( @@ -199,21 +197,18 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer if (!(pastTile instanceof TEReagentConduit pastRelay)) { // Saved source is gone — clear it so the player can start over without a manual reset. this.setHasSavedCoordinates(itemStack, false); - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.error.cannotfind")); return itemStack; } Reagent reagent = this.getReagent(itemStack); if (reagent == null) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.noreagent")); + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.error.noreagent")); return itemStack; } if (pastRelay.hasReagentDestination(reagent, x, y, z)) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.duplicate")); + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.error.duplicate")); } else if (pastRelay.addReagentDestinationViaActual(reagent, x, y, z)) { int used = pastRelay.getTotalConnections(); int max = pastRelay.maxConnextions; @@ -232,16 +227,14 @@ public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer // No saved source — this click saves one and (when useful) copies its reagent. if (tile instanceof TEReagentConduit conduit && conduit.getTotalConnections() >= conduit.maxConnextions) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.sourcefull")); + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.error.sourcefull")); return itemStack; } List reagentList = collectReagents(relay); Reagent currentReagent = this.getReagent(itemStack); if (reagentList.isEmpty() && currentReagent == null) { - player.addChatComponentMessage( - new ChatComponentTranslation("message.attunedcrystal.error.nothingtocopy")); + player.addChatComponentMessage(new ChatComponentTranslation("message.attunedcrystal.error.nothingtocopy")); return itemStack; } diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java index 3acc5ed9ab..341744d1ad 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java @@ -96,8 +96,7 @@ private static int clearIncomingConnections(World world, int x, int y, int z) { Iterator it = coords.iterator(); while (it.hasNext()) { Int3 off = it.next(); - if (src.xCoord + off.x() == x && src.yCoord + off.y() == y - && src.zCoord + off.z() == z) { + if (src.xCoord + off.x() == x && src.yCoord + off.y() == y && src.zCoord + off.z() == z) { it.remove(); changed = true; totalRemoved++; From e4c52fd1340a885d75464e6edfa457b632acab93 Mon Sep 17 00:00:00 2001 From: reign Date: Tue, 19 May 2026 10:47:35 -0400 Subject: [PATCH 5/7] Update src/main/resources/assets/alchemicalwizardry/lang/en_US.lang Co-authored-by: koolkrafter5 --- .../resources/assets/alchemicalwizardry/lang/en_US.lang | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang index ea89536f01..c9a7d122d4 100644 --- a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang +++ b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang @@ -751,7 +751,7 @@ nei.infopage.rituals.2=To build a ritual, place a Master Ritual Stone surrounded nei.infopage.rituals.3=Once the ritual is assembled, right-click the Master Ritual Stone with a bound Activation Crystal. If everything is in place and your Soul Network contains sufficient LP, the ritual will commence! Each ritual has a unique effect. Experimentation is encouraged to discover the full potential of the Master Ritual Stone. nei.infopage.reagents.1=Some rituals can be modified by providing reagents to the Master Ritual Stone. However, raw reagents are too impure to be used directly. They must first be refined in an Alchemic Calcinator into AR (Alchemy Reagent), a pure essence usable by the ritual. nei.infopage.reagents.2=To use an Alchemic Calcinator, right-click it with a bound Blood Orb, and then right-click it with the reagent item. Reagents may also be inserted via hoppers or pipes. The reagent will be consumed and converted into AR, which the Calcinator will store internally. -nei.infopage.reagents.3=An Alchemic Router (Attuned Crystal) transfers AR. Right-click a block holding AR to save it as the source — the Router copies that source's AR automatically. Right-click the saved source again to cycle through its remaining AR types. Right-click a different block to link it as a destination; the source clears but the AR stays, so you can fan out to many destinations quickly. -nei.infopage.reagents.3b=Sneak+right-click anywhere to clear the saved source; sneak+right-click again to clear the held AR. Right-clicking a relay with an empty hand prints its current outgoing routing connections to chat. -nei.infopage.reagents.4=An Alchemic Cleanser clears AR routing connections — right-click a relay to wipe its outgoing links, or sneak+right-click to wipe nearby relays' links pointing AT it. An Alchemic Segmenter may be used to limit how many internal AR tanks a single reagent may occupy; it is attuned in the same way as the Router. +nei.infopage.reagents.3=An Alchemic Router transfers AR. Right-click a block that can hold AR to save it as the source. The first reagent in the source is copied automatically. Right-click the source again to cycle through its other reagents. Right-click a different block to link it as a destination. +nei.infopage.reagents.3b=After making a link, the source is cleared, but the reagent stays, so you can quickly make multiple links for the same reagent. Sneak+right-click anywhere before linking to clear the saved source. Sneak+right-click again to clear the saved reagent. Right-clicking a relay with an empty hand sends its current outgoing routing connections in chat. +nei.infopage.reagents.4=An Alchemic Cleanser clears AR routing connections — right-click a relay to wipe its outgoing links, or sneak+right-click to wipe incoming links. An Alchemic Segmenter may be used to limit how many internal AR tanks a single reagent may occupy. Attune it by shift+right-clicking a block with a stored reagent, then right-click a block to cycle how many tanks that reagent can fill. nei.infopage.reagents.5=The range of AR links is limited to a few blocks. To extend the transfer distance, use Alchemic Relays. Crystal Belljars may be placed to store AR, and they will retain their contents when broken. From b8d187054b0ab1aea5f38a4cbddf80be30b30f80 Mon Sep 17 00:00:00 2001 From: reign Date: Tue, 19 May 2026 10:47:43 -0400 Subject: [PATCH 6/7] Update src/main/resources/assets/alchemicalwizardry/lang/en_US.lang Co-authored-by: koolkrafter5 --- src/main/resources/assets/alchemicalwizardry/lang/en_US.lang | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang index c9a7d122d4..b6bfc45ea6 100644 --- a/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang +++ b/src/main/resources/assets/alchemicalwizardry/lang/en_US.lang @@ -459,8 +459,7 @@ tooltip.demonictelepfocus.desc1=A stronger version of the focus, tooltip.demonictelepfocus.desc2=using a demonic shard tooltip.demonplacer.desc=Used to spawn demons. tooltip.destclearer.desc1=Right-click a relay to clear its outgoing links. -tooltip.destclearer.desc2=Sneak+right-click a relay to clear links -tooltip.destclearer.desc3=pointing AT it from nearby relays. +tooltip.destclearer.desc2=Sneak+right-click a relay to clear incoming links. tooltip.diablokey.desc=Binds other items to the owner's network tooltip.divinationsigil.desc1=Peer into the soul to tooltip.divinationsigil.desc2=get the current essence From 979d846731925523a92af472b2efd109b7fef6c4 Mon Sep 17 00:00:00 2001 From: koolkrafter5 Date: Tue, 19 May 2026 22:31:03 -0400 Subject: [PATCH 7/7] Remove extra line from cleanser --- .../common/items/energy/ItemDestinationClearer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java index 341744d1ad..f80f7ab263 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/items/energy/ItemDestinationClearer.java @@ -40,7 +40,6 @@ public void registerIcons(IIconRegister iconRegister) { public void addInformation(ItemStack item, EntityPlayer player, List tooltip, boolean adv) { tooltip.add(StatCollector.translateToLocal("tooltip.destclearer.desc1")); tooltip.add(StatCollector.translateToLocal("tooltip.destclearer.desc2")); - tooltip.add(StatCollector.translateToLocal("tooltip.destclearer.desc3")); } @Override