From 405882c6cf9b066089ac69844311e06b99837ead Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Sat, 6 Jun 2026 09:28:54 -0700 Subject: [PATCH 01/10] Swap Thoth's Gambit argument order --- .../hexcasting/common/casting/actions/eval/OpForEach.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt index 926bce1d82..a70054e1ee 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt @@ -18,8 +18,8 @@ object OpForEach : Action { if (stack.size < 2) throw MishapNotEnoughArgs(2, stack.size) - val instrs = stack.getList(stack.lastIndex - 1, stack.size) - val datums = stack.getList(stack.lastIndex, stack.size) + val datums = stack.getList(stack.lastIndex - 1, stack.size) + val instrs = stack.getList(stack.lastIndex, stack.size) stack.removeLastOrNull() stack.removeLastOrNull() From 6d6633e47806075238c0d13e249f51b704ce710c Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Sat, 6 Jun 2026 09:33:41 -0700 Subject: [PATCH 02/10] Update Thoth's Gambit pattern shape --- .../java/at/petrak/hexcasting/common/lib/hex/HexActions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java index eb049a8e78..1fcbf1fdb8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java @@ -552,7 +552,7 @@ public class HexActions { public static final ActionRegistryEntry INDEX = make("index", new OperationAction(HexPattern.fromAngles("deeed", HexDir.NORTH_WEST))); public static final ActionRegistryEntry FOR_EACH = make("for_each", - new ActionRegistryEntry(HexPattern.fromAngles("dadad", HexDir.NORTH_EAST), OpForEach.INSTANCE)); + new ActionRegistryEntry(HexPattern.fromAngles("dadaqw", HexDir.NORTH_EAST), OpForEach.INSTANCE)); // public static final ActionRegistryEntry LIST_SIZE = make("list_size", // new ActionRegistryEntry(HexPattern.fromAngles("aqaeaq", HexDir.EAST), OpListSize.INSTANCE)); public static final ActionRegistryEntry SINGLETON = make("singleton", From 8664cdb756fd23880527d4041c38c9f8059739ba Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Sat, 6 Jun 2026 10:02:15 -0700 Subject: [PATCH 03/10] Allow Thoth's Gambit to take single patterns as code --- .../hexcasting/common/casting/actions/eval/OpForEach.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt index a70054e1ee..5ce945ac66 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt @@ -1,11 +1,13 @@ package at.petrak.hexcasting.common.casting.actions.eval +import at.petrak.hexcasting.api.casting.SpellList import at.petrak.hexcasting.api.casting.castables.Action import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.OperationResult import at.petrak.hexcasting.api.casting.eval.vm.CastingImage import at.petrak.hexcasting.api.casting.eval.vm.FrameForEach import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation +import at.petrak.hexcasting.api.casting.evaluatable import at.petrak.hexcasting.api.casting.getList import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs import at.petrak.hexcasting.api.utils.TreeList @@ -19,11 +21,13 @@ object OpForEach : Action { throw MishapNotEnoughArgs(2, stack.size) val datums = stack.getList(stack.lastIndex - 1, stack.size) - val instrs = stack.getList(stack.lastIndex, stack.size) + val instrs = evaluatable(stack[stack.lastIndex], 0) stack.removeLastOrNull() stack.removeLastOrNull() - val frame = FrameForEach(datums, instrs, null, TreeList.empty()) + val instrList = instrs.map({ SpellList.LList(0, listOf(it)) }, { it }) + + val frame = FrameForEach(datums, instrList, null, TreeList.empty()) val image2 = image.withUsedOp().copy(stack = stack) return OperationResult(image2, listOf(), continuation.pushFrame(frame), HexEvalSounds.THOTH) From 5a2910b6e0f5fc59f4021a8334980ac40dcbf394 Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Sat, 6 Jun 2026 14:44:15 -0700 Subject: [PATCH 04/10] Implement waterline behavior --- .../at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt index 6133b2b627..98fac6485e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt @@ -52,7 +52,7 @@ data class FrameForEach( harness.image.stack.toList() to acc } else { // else save the stack to the accumulator and reuse the saved base stack. - baseStack to acc.appendedAll(harness.image.stack) + baseStack to acc.appendedAll(harness.image.stack.drop(baseStack.size)) } // If we still have data to process... From 1ea7d2040a8437dbc4bcda28c2f13e6a76c3c504 Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Sat, 6 Jun 2026 18:40:26 -0700 Subject: [PATCH 05/10] Update notebook entry for Thoth's Gambit --- .../petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt | 1 + .../resources/assets/hexcasting/lang/en_us.flatten.json5 | 6 +++--- .../thehexbook/en_us/entries/patterns/meta.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt index 98fac6485e..1c8cb2dd56 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt @@ -52,6 +52,7 @@ data class FrameForEach( harness.image.stack.toList() to acc } else { // else save the stack to the accumulator and reuse the saved base stack. + // Only the iotas above the waterline (size of the base stack) are kept. baseStack to acc.appendedAll(harness.image.stack.drop(baseStack.size)) } diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index 528f826464..64ec0d9f9e 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -2000,9 +2000,9 @@ meta: { "eval.1": "Remove a pattern or list of patterns from the stack, then cast them as if I had drawn them myself with my $(l:items/staff)$(item)Staff/$ (until a $(l:patterns/meta#hexcasting:halt)$(action)Charon's Gambit/$ is encountered). If an iota is escaped with $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$ or $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)its ilk/$, it will be pushed to the stack. Otherwise, non-patterns will fail.", "eval.2": "This can be very powerful in tandem with $(l:items/focus)$(item)Foci/$, and according to one esoteric scroll I found it also makes the bureaucracy of Nature a \"Turing-complete\" system.$(br2)However, it seems there's a limit to how many times a _Hex can cast itself-- Nature doesn't look kindly on runaway spells!$(br2)In addition, with the energies of the patterns occurring without me to guide them, any mishap will cause the remaining actions to immediately unravel.", - - "for_each.1": "Remove a list of patterns and a list from the stack, then cast the given pattern-list over each element of the second list.", - "for_each.2": "More specifically, for each element in the second list, it will:$(li)Create a new stack, with everything on the current stack plus that element$(li)Draw all the patterns in the first list$(li)Save all the iotas remaining on the stack to a list$(br)Then, after all is said and done, pushes the list of saved iotas onto the main stack.$(br2)No wonder all the practitioners of this art go mad.", + + "for_each.1": "Remove a list of values and pattern/list of patterns from the stack, then cast the pattern(s) over each element of the first list.", + "for_each.2": "More specifically: A copy of the stack is saved at the start. For each value given:$(li)Add the element to the stack$(li)Draw the pattern(s) given$(li)If the current stack's size is larger than the saved stack's size, store the extra iotas to a hidden list.$(li)Restore the stack to match the copy and move on to the next element.$(br)Finally, pushes the list of stored iotas onto the stack.$(br2)No wonder all the practitioners of this art go mad.", "halt.1": "This pattern forcibly halts a _Hex. This is mostly useless on its own, as I could simply just stop writing patterns, or put down my staff.", "halt.2": "But when combined with $(l:patterns/meta#hexcasting:eval)$(action)Hermes'/$ or $(l:patterns/meta#hexcasting:for_each)$(action)Thoth's Gambits/$, it becomes $(italics)far/$ more interesting. Those patterns serve to 'contain' that halting, and rather than ending the entire _Hex, those gambits end instead. This can be used to cause $(l:patterns/meta#hexcasting:for_each)$(action)Thoth's Gambit/$ not to operate on every iota it's given. An escape from the madness, as it were.", diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json index 63e7f68c4a..7dc550aa91 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json @@ -34,7 +34,7 @@ "type": "hexcasting:pattern", "op_id": "hexcasting:for_each", "anchor": "hexcasting:for_each", - "input": "list of patterns, list", + "input": "list, pattern | [pattern]", "output": "list", "text": "hexcasting.page.meta.for_each.1" }, From 4e54acdf0a6abacc9f8e1cc2b4481458ea6ad11a Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:37:09 -0400 Subject: [PATCH 06/10] Update thoth pattern in loot cyphers --- .../hexcasting/common/loot/AddHexToAncientCypherFunc.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java index 82585e1a51..610dfc6f91 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java @@ -75,12 +75,12 @@ public LootItemFunctionType getType() { new Pair<>("hexcasting.loot_hex.ascend", new String[] {"NORTH_EAST qaq","SOUTH_EAST aqaae","WEST qqqqqawwawawd"}), new Pair<>("hexcasting.loot_hex.blink", new String[] {"NORTH_EAST qaq","EAST aadaa","EAST aa","NORTH_EAST qaq","NORTH_EAST wa","EAST wqaawdd","NORTH_EAST qaq","EAST aa","NORTH_WEST wddw","NORTH_EAST wqaqw","SOUTH_EAST aqaaw","NORTH_WEST wddw","SOUTH_WEST awqqqwaq"}), new Pair<>("hexcasting.loot_hex.blastoff", new String[] {"NORTH_EAST qaq","NORTH_WEST qqqqqew","SOUTH_EAST aqaawaa","SOUTH_EAST waqaw","SOUTH_WEST awqqqwaqw"}), - new Pair<>("hexcasting.loot_hex.radar", new String[] {"WEST qqq","EAST aadaa","EAST aa","SOUTH_EAST aqaawa","SOUTH_WEST ewdqdwe","NORTH_EAST de","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaeaqq","SOUTH_EAST qqqqqwdeddwd","NORTH_EAST dadad"}), + new Pair<>("hexcasting.loot_hex.radar", new String[] {"WEST qqq","EAST aadaa","EAST aa","SOUTH_EAST aqaawa","SOUTH_WEST ewdqdwe","NORTH_EAST de","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaeaqq","SOUTH_EAST qqqqqwdeddwd","NORTH_EAST dadaqw"}), new Pair<>("hexcasting.loot_hex.beckon", new String[] {"NORTH_EAST qaq","EAST aa","NORTH_EAST qaq","NORTH_EAST wa","EAST weaqa","EAST aadaa","EAST dd","NORTH_EAST qaq","EAST aa","EAST aawdd","NORTH_WEST wddw","EAST aadaa","NORTH_EAST wqaqw","NORTH_EAST wdedw","SOUTH_EAST aqaawa","SOUTH_EAST waqaw","SOUTH_WEST awqqqwaqw"}), new Pair<>("hexcasting.loot_hex.detonate", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaedwd","EAST ddwddwdd"}), new Pair<>("hexcasting.loot_hex.shockwave", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaawaa","EAST aadaadaa","SOUTH_EAST aqawqadaq","SOUTH_EAST aqaaedwd","EAST aawaawaa","NORTH_EAST qqa","EAST qaqqqqq"}), - new Pair<>("hexcasting.loot_hex.heat_wave", new String[] {"WEST qqq","SOUTH_EAST aaqawawa","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwded","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadad"}), - new Pair<>("hexcasting.loot_hex.wither_wave", new String[] {"WEST qqq","SOUTH_EAST aqaae","SOUTH_EAST aqaaw","SOUTH_WEST qqqqqaewawawe","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwdeddwd","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadad"}), + new Pair<>("hexcasting.loot_hex.heat_wave", new String[] {"WEST qqq","SOUTH_EAST aaqawawa","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwded","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadaqw"}), + new Pair<>("hexcasting.loot_hex.wither_wave", new String[] {"WEST qqq","SOUTH_EAST aqaae","SOUTH_EAST aqaaw","SOUTH_WEST qqqqqaewawawe","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwdeddwd","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadaqw"}), new Pair<>("hexcasting.loot_hex.flight_zone", new String[] {"NORTH_EAST qaq","SOUTH_EAST aqaaq","SOUTH_WEST awawaawq"}) ); } From c0014d99cdf607ffdd64983824ea508d45155a12 Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Sun, 7 Jun 2026 16:37:35 -0700 Subject: [PATCH 07/10] Update Thoth's Gambit usage in ancient cyphers --- .../hexcasting/common/loot/AddHexToAncientCypherFunc.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java index 610dfc6f91..1e42a6c36d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/loot/AddHexToAncientCypherFunc.java @@ -75,12 +75,12 @@ public LootItemFunctionType getType() { new Pair<>("hexcasting.loot_hex.ascend", new String[] {"NORTH_EAST qaq","SOUTH_EAST aqaae","WEST qqqqqawwawawd"}), new Pair<>("hexcasting.loot_hex.blink", new String[] {"NORTH_EAST qaq","EAST aadaa","EAST aa","NORTH_EAST qaq","NORTH_EAST wa","EAST wqaawdd","NORTH_EAST qaq","EAST aa","NORTH_WEST wddw","NORTH_EAST wqaqw","SOUTH_EAST aqaaw","NORTH_WEST wddw","SOUTH_WEST awqqqwaq"}), new Pair<>("hexcasting.loot_hex.blastoff", new String[] {"NORTH_EAST qaq","NORTH_WEST qqqqqew","SOUTH_EAST aqaawaa","SOUTH_EAST waqaw","SOUTH_WEST awqqqwaqw"}), - new Pair<>("hexcasting.loot_hex.radar", new String[] {"WEST qqq","EAST aadaa","EAST aa","SOUTH_EAST aqaawa","SOUTH_WEST ewdqdwe","NORTH_EAST de","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaeaqq","SOUTH_EAST qqqqqwdeddwd","NORTH_EAST dadaqw"}), + new Pair<>("hexcasting.loot_hex.radar", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaeaqq","SOUTH_EAST qqqqqwdeddwd","WEST qqq","EAST aadaa","EAST aa","SOUTH_EAST aqaawa","SOUTH_WEST ewdqdwe","NORTH_EAST de","EAST eee","NORTH_EAST dadaqw"}), new Pair<>("hexcasting.loot_hex.beckon", new String[] {"NORTH_EAST qaq","EAST aa","NORTH_EAST qaq","NORTH_EAST wa","EAST weaqa","EAST aadaa","EAST dd","NORTH_EAST qaq","EAST aa","EAST aawdd","NORTH_WEST wddw","EAST aadaa","NORTH_EAST wqaqw","NORTH_EAST wdedw","SOUTH_EAST aqaawa","SOUTH_EAST waqaw","SOUTH_WEST awqqqwaqw"}), new Pair<>("hexcasting.loot_hex.detonate", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaedwd","EAST ddwddwdd"}), new Pair<>("hexcasting.loot_hex.shockwave", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaawaa","EAST aadaadaa","SOUTH_EAST aqawqadaq","SOUTH_EAST aqaaedwd","EAST aawaawaa","NORTH_EAST qqa","EAST qaqqqqq"}), - new Pair<>("hexcasting.loot_hex.heat_wave", new String[] {"WEST qqq","SOUTH_EAST aaqawawa","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwded","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadaqw"}), - new Pair<>("hexcasting.loot_hex.wither_wave", new String[] {"WEST qqq","SOUTH_EAST aqaae","SOUTH_EAST aqaaw","SOUTH_WEST qqqqqaewawawe","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwdeddwd","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadaqw"}), + new Pair<>("hexcasting.loot_hex.heat_wave", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwded","SOUTH_WEST aaqwqaa","SOUTH_EAST a","WEST qqq","SOUTH_EAST aaqawawa","EAST eee","NORTH_EAST dadaqw"}), + new Pair<>("hexcasting.loot_hex.wither_wave", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwdeddwd","SOUTH_WEST aaqwqaa","SOUTH_EAST a","WEST qqq","SOUTH_EAST aqaae","SOUTH_EAST aqaaw","SOUTH_WEST qqqqqaewawawe","EAST eee","NORTH_EAST dadaqw"}), new Pair<>("hexcasting.loot_hex.flight_zone", new String[] {"NORTH_EAST qaq","SOUTH_EAST aqaaq","SOUTH_WEST awawaawq"}) ); } From 215767158b904a5e29ac1738463ff2a615610c2c Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:57:59 -0700 Subject: [PATCH 08/10] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d401546f73..574d066e92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - Updated to Minecraft 1.21.1 ([#985](https://github.com/FallingColors/HexMod/pull/985)) @SuperKnux @slava110 +### Changed + +- Changed the argument order for Thoth's Gambit to take data first ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid +- Changed Thoth's Gambit to accept single iotas as the loop body ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid +- Changed the pattern shape for Thoth's Gambit ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid +- Changed Thoth's Gambit to use a waterline to determine which iotas are accumulated ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid + ### Fixed - Fixed Entity Iota comparison to use `equals` on entity IDs instead of reference equality ([#1101](https://github.com/FallingColors/HexMod/pull/1101)) @IridescentVoid From 27e727e3fea43e72fed5258cdb6d3dc90bd62e19 Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:53:32 -0700 Subject: [PATCH 09/10] Update meta-evaluation book entry to use "evaluatable" as argument type --- .../thehexbook/en_us/entries/patterns/meta.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json index 7dc550aa91..f14406e392 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/meta.json @@ -10,7 +10,7 @@ "type": "hexcasting:pattern", "op_id": "hexcasting:eval", "anchor": "hexcasting:eval", - "input": "[pattern] | pattern", + "input": "evaluatable", "output": "many", "text": "hexcasting.page.meta.eval.1" }, @@ -22,7 +22,7 @@ "type": "hexcasting:pattern", "op_id": "hexcasting:eval/cc", "anchor": "hexcasting:eval/cc", - "input": "[pattern] | pattern", + "input": "evaluatable", "output": "many", "text": "hexcasting.page.meta.eval/cc.1" }, @@ -34,7 +34,7 @@ "type": "hexcasting:pattern", "op_id": "hexcasting:for_each", "anchor": "hexcasting:for_each", - "input": "list, pattern | [pattern]", + "input": "list, evaluatable", "output": "list", "text": "hexcasting.page.meta.for_each.1" }, From 9092f443a0df983c366f316e8e2374a1d38c8549 Mon Sep 17 00:00:00 2001 From: IridescentVoid <265486018+IridescentVoid@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:23:10 -0700 Subject: [PATCH 10/10] API: change ActionUtils evaluatable to List.getEvaluatable --- .../petrak/hexcasting/api/casting/ActionUtils.kt | 12 +++++++----- .../common/casting/actions/eval/OpEval.kt | 16 +++++++++++----- .../casting/actions/eval/OpEvalBreakable.kt | 11 +++++++++-- .../common/casting/actions/eval/OpForEach.kt | 4 ++-- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt index d67e0693b4..6a2b1acc86 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/ActionUtils.kt @@ -289,15 +289,17 @@ fun List.getLongOrList(idx: Int, argc: Int = 0): Either { ) } -fun evaluatable(datum: Iota, reverseIdx: Int): Either = - when (datum) { +fun List.getEvaluatable(idx: Int, argc: Int = 0): Either { + val datum = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + return when (datum) { is ListIota -> Either.right(datum.list) - else -> if (datum.executable()) Either.left(datum) else throw MishapInvalidIota( + else -> if (datum.executable()) Either.left(datum) else throw MishapInvalidIota.of( datum, - reverseIdx, - "hexcasting.mishap.invalid_value.evaluatable".asTranslatedComponent + if (argc == 0) idx else argc - (idx + 1), + "evaluatable" ) } +} fun Iota?.orNull() = this ?: NullIota() diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEval.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEval.kt index e9c9adf2a1..a6808ed559 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEval.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEval.kt @@ -8,21 +8,27 @@ import at.petrak.hexcasting.api.casting.eval.vm.CastingImage import at.petrak.hexcasting.api.casting.eval.vm.FrameEvaluate import at.petrak.hexcasting.api.casting.eval.vm.FrameFinishEval import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation -import at.petrak.hexcasting.api.casting.evaluatable +import at.petrak.hexcasting.api.casting.getEvaluatable import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs import at.petrak.hexcasting.common.lib.hex.HexEvalSounds +import com.mojang.datafixers.util.Either object OpEval : Action { override fun operate(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation): OperationResult { val stack = image.stack.toMutableList() - val iota = stack.removeLastOrNull() ?: throw MishapNotEnoughArgs(1, 0) - return exec(env, image, continuation, stack, iota) + + if (stack.size < 1) + throw MishapNotEnoughArgs(1, 0) + + val instrs = stack.getEvaluatable(stack.lastIndex, stack.size) + stack.removeLastOrNull() + + return exec(env, image, continuation, stack, instrs) } - fun exec(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation, newStack: MutableList, iota: Iota): OperationResult { + fun exec(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation, newStack: MutableList, instrs: Either): OperationResult { // also, never make a break boundary when evaluating just one pattern - val instrs = evaluatable(iota, 0) val newCont = if (instrs.left().isPresent || (continuation is SpellContinuation.NotDone && continuation.frame is FrameFinishEval)) { continuation diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEvalBreakable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEvalBreakable.kt index f778d87356..c6fe3272f6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEvalBreakable.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpEvalBreakable.kt @@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.OperationResult import at.petrak.hexcasting.api.casting.eval.vm.CastingImage import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation +import at.petrak.hexcasting.api.casting.getEvaluatable import at.petrak.hexcasting.api.casting.iota.ContinuationIota import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs @@ -13,8 +14,14 @@ object OpEvalBreakable : Action { image: CastingImage, continuation: SpellContinuation): OperationResult { val stack = image.stack.toMutableList() - val iota = stack.removeLastOrNull() ?: throw MishapNotEnoughArgs(1, 0) + + if (stack.size < 1) + throw MishapNotEnoughArgs(1, 0) + + val instrs = stack.getEvaluatable(stack.lastIndex, stack.size) + stack.removeLastOrNull() + stack.add(ContinuationIota(continuation)) - return OpEval.exec(env, image, continuation, stack, iota) + return OpEval.exec(env, image, continuation, stack, instrs) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt index 5ce945ac66..521886b69b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/eval/OpForEach.kt @@ -7,7 +7,7 @@ import at.petrak.hexcasting.api.casting.eval.OperationResult import at.petrak.hexcasting.api.casting.eval.vm.CastingImage import at.petrak.hexcasting.api.casting.eval.vm.FrameForEach import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation -import at.petrak.hexcasting.api.casting.evaluatable +import at.petrak.hexcasting.api.casting.getEvaluatable import at.petrak.hexcasting.api.casting.getList import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs import at.petrak.hexcasting.api.utils.TreeList @@ -21,7 +21,7 @@ object OpForEach : Action { throw MishapNotEnoughArgs(2, stack.size) val datums = stack.getList(stack.lastIndex - 1, stack.size) - val instrs = evaluatable(stack[stack.lastIndex], 0) + val instrs = stack.getEvaluatable(stack.lastIndex, stack.size) stack.removeLastOrNull() stack.removeLastOrNull()