From 5593f07ed008877d334e5aa4366b4b0e454d6bce Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Tue, 12 May 2026 14:23:23 -0400 Subject: [PATCH 1/5] Basic big-parens implementation --- .../api/casting/eval/SpecialPatterns.java | 3 +- .../api/casting/eval/vm/CastingVM.kt | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java index f87fcfdfae..12a0c61b6a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java @@ -6,7 +6,8 @@ public final class SpecialPatterns { public static final HexPattern INTROSPECTION = HexPattern.fromAngles("qqq", HexDir.WEST); public static final HexPattern RETROSPECTION = HexPattern.fromAngles("eee", HexDir.EAST); + public static final HexPattern BIG_INTRO = HexPattern.fromAngles("eqqqe", HexDir.EAST); + public static final HexPattern BIG_RETRO = HexPattern.fromAngles("qeeeq", HexDir.EAST); public static final HexPattern CONSIDERATION = HexPattern.fromAngles("qqqaw", HexDir.WEST); - public static final HexPattern EVANITION = HexPattern.fromAngles("eeedw", HexDir.EAST); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index 3d03a9a843..931e580584 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -6,9 +6,11 @@ import at.petrak.hexcasting.api.casting.SpellList import at.petrak.hexcasting.api.casting.eval.* import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect import at.petrak.hexcasting.api.casting.eval.vm.CastingImage.ParenthesizedIota +import at.petrak.hexcasting.api.casting.getPositiveInt import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.IotaType import at.petrak.hexcasting.api.casting.iota.ListIota +import at.petrak.hexcasting.api.casting.iota.DoubleIota import at.petrak.hexcasting.api.casting.iota.PatternIota import at.petrak.hexcasting.api.casting.math.HexDir import at.petrak.hexcasting.api.casting.math.HexPattern @@ -246,6 +248,22 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { } } + SpecialPatterns.BIG_INTRO.angles -> { + throw MishapTooManyCloseParens() + } + + SpecialPatterns.BIG_RETRO.angles -> { + displayDepth = 0 + val newStack = this.image.stack.toMutableList() + newStack.add(DoubleIota(this.image.parenCount.toDouble())) + newStack.add(ListIota(this.image.parenthesized.toList().map { it.iota })) + this.image.copy( + stack = newStack, + parenCount = 0, + parenthesized = listOf() + ) to ResolvedPatternType.EVALUATED + } + else -> { val newParens = this.image.parenthesized.toMutableList() newParens.add(ParenthesizedIota(iota, false)) @@ -280,6 +298,23 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { throw MishapTooManyCloseParens() } + SpecialPatterns.BIG_INTRO.angles -> { + val newStack = this.image.stack.toMutableList() + val layers = when (val topIota = newStack.removeLastOrNull()) { + null -> throw MishapNotEnoughArgs(1, 0) + else -> listOf(topIota).getPositiveInt(0) + } + + this.image.copy( + stack = newStack, + parenCount = this.image.parenCount + layers + ) to ResolvedPatternType.EVALUATED + } + + SpecialPatterns.BIG_RETRO.angles -> { + throw MishapTooManyCloseParens() + } + else -> { null } From 8e7341dc8e38ccc2b66abe29283aad54d2536635 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Tue, 12 May 2026 15:34:44 -0400 Subject: [PATCH 2/5] Paren mishap handling --- .../api/casting/eval/SpecialPatterns.java | 4 ++-- .../api/casting/eval/vm/CastingVM.kt | 15 ++++++++++----- .../casting/mishaps/MishapBigIntroInParens.kt | 19 +++++++++++++++++++ .../hexcasting/lang/en_us.flatten.json5 | 4 ++++ 4 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBigIntroInParens.kt diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java index 12a0c61b6a..31da4844e1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java @@ -6,8 +6,8 @@ public final class SpecialPatterns { public static final HexPattern INTROSPECTION = HexPattern.fromAngles("qqq", HexDir.WEST); public static final HexPattern RETROSPECTION = HexPattern.fromAngles("eee", HexDir.EAST); - public static final HexPattern BIG_INTRO = HexPattern.fromAngles("eqqqe", HexDir.EAST); - public static final HexPattern BIG_RETRO = HexPattern.fromAngles("qeeeq", HexDir.EAST); + public static final HexPattern BIG_INTRO = HexPattern.fromAngles("eqqqe", HexDir.SOUTH_WEST); + public static final HexPattern BIG_RETRO = HexPattern.fromAngles("qeeeq", HexDir.SOUTH_EAST); public static final HexPattern CONSIDERATION = HexPattern.fromAngles("qqqaw", HexDir.WEST); public static final HexPattern EVANITION = HexPattern.fromAngles("eeedw", HexDir.EAST); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index 931e580584..5ca255dec8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -115,8 +115,9 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { this.handleParentheses(iota)?.let { (data, resolutionType) -> return@executeInner CastResult(iota, continuation, data, listOf(), resolutionType, HexEvalSounds.NORMAL_EXECUTE) } - } catch (e: MishapTooManyCloseParens) { + } catch (e: Mishap) { // This is ridiculous and needs to be fixed + val pattern = (iota as? PatternIota)?.pattern return CastResult( iota, continuation, @@ -125,8 +126,12 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { OperatorSideEffect.DoMishap( e, Mishap.Context( - (iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST), - HexAPI.instance().getRawHookI18n(HexAPI.modLoc("close_paren")) + pattern ?: HexPattern(HexDir.WEST), + HexAPI.instance().getRawHookI18n(HexAPI.modLoc(when (pattern?.angles) { + SpecialPatterns.RETROSPECTION.angles -> "close_paren" + SpecialPatterns.BIG_INTRO.angles -> "open_n_parens" + else -> "unknown" + })) ) ) ), @@ -179,7 +184,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { * Return a non-null value if we handled this in some sort of parenthesey way, * either escaping it onto the stack or changing the parenthese-handling state. */ - @Throws(MishapTooManyCloseParens::class) + @Throws(Mishap::class) private fun handleParentheses(iota: Iota): Pair? { val sig = (iota as? PatternIota)?.pattern?.angles @@ -249,7 +254,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { } SpecialPatterns.BIG_INTRO.angles -> { - throw MishapTooManyCloseParens() + throw MishapBigIntroInParens() } SpecialPatterns.BIG_RETRO.angles -> { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBigIntroInParens.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBigIntroInParens.kt new file mode 100644 index 0000000000..b9ab81c0fd --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBigIntroInParens.kt @@ -0,0 +1,19 @@ +package at.petrak.hexcasting.api.casting.mishaps + +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.casting.iota.PatternIota +import at.petrak.hexcasting.api.pigment.FrozenPigment +import net.minecraft.world.item.DyeColor + +class MishapBigIntroInParens : Mishap() { + override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment = + dyeColor(DyeColor.ORANGE) + + override fun execute(env: CastingEnvironment, errorCtx: Context, stack: MutableList) { + // no-op + } + + override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = + error("big_intro_in_parens") +} 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 dd39d0e0c5..2cefea5e28 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 @@ -990,8 +990,11 @@ "rawhook.hexcasting:": { open_paren: "Introspection", close_paren: "Retrospection", + open_n_parens: "[BIG_INTRO]", + close_all_parens: "[BIG_RETRO]", escape: "Consideration", undo: "Evanition", + unknown: "Unknown Pattern (this is a bug!)", }, "iota.hexcasting:": { @@ -1043,6 +1046,7 @@ not_enough_args: "expected %s or more arguments but the stack was only %s tall", no_args: "expected %s or more arguments but the stack was empty", too_many_close_parens: "Did not first use Introspection", + big_intro_in_parens: "Tried to use [BIG_INTRO] after Introspection", wrong_dimension: "cannot see %s from %s", entity_too_far: "%s is out of range", From 154f06a06db9eec1a4a3d88bee0074f2101aa9ff Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Tue, 12 May 2026 21:05:21 -0400 Subject: [PATCH 3/5] Proper names and book entry --- .../api/casting/eval/SpecialPatterns.java | 4 ++-- .../api/casting/eval/vm/CastingVM.kt | 14 +++++------- ...troInParens.kt => MishapNestedBigParen.kt} | 5 ++--- .../hexcasting/lang/en_us.flatten.json5 | 12 ++++++---- .../entries/patterns/patterns_as_iotas.json | 22 +++++++++++++++++++ 5 files changed, 40 insertions(+), 17 deletions(-) rename Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/{MishapBigIntroInParens.kt => MishapNestedBigParen.kt} (81%) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java index 31da4844e1..65a8ec0f85 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java @@ -6,8 +6,8 @@ public final class SpecialPatterns { public static final HexPattern INTROSPECTION = HexPattern.fromAngles("qqq", HexDir.WEST); public static final HexPattern RETROSPECTION = HexPattern.fromAngles("eee", HexDir.EAST); - public static final HexPattern BIG_INTRO = HexPattern.fromAngles("eqqqe", HexDir.SOUTH_WEST); - public static final HexPattern BIG_RETRO = HexPattern.fromAngles("qeeeq", HexDir.SOUTH_EAST); + public static final HexPattern INTROSPECTION_II = HexPattern.fromAngles("eqqqe", HexDir.SOUTH_WEST); + public static final HexPattern RETROSPECTION_II = HexPattern.fromAngles("qeeeq", HexDir.SOUTH_EAST); public static final HexPattern CONSIDERATION = HexPattern.fromAngles("qqqaw", HexDir.WEST); public static final HexPattern EVANITION = HexPattern.fromAngles("eeedw", HexDir.EAST); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index 5ca255dec8..d6bed9446f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -1,7 +1,6 @@ package at.petrak.hexcasting.api.casting.eval.vm import at.petrak.hexcasting.api.HexAPI -import at.petrak.hexcasting.api.casting.PatternShapeMatch.* import at.petrak.hexcasting.api.casting.SpellList import at.petrak.hexcasting.api.casting.eval.* import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect @@ -15,7 +14,6 @@ import at.petrak.hexcasting.api.casting.iota.PatternIota import at.petrak.hexcasting.api.casting.math.HexDir import at.petrak.hexcasting.api.casting.math.HexPattern import at.petrak.hexcasting.api.casting.mishaps.* -import at.petrak.hexcasting.api.utils.* import at.petrak.hexcasting.common.lib.hex.HexEvalSounds import net.minecraft.nbt.CompoundTag import net.minecraft.server.level.ServerLevel @@ -129,7 +127,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { pattern ?: HexPattern(HexDir.WEST), HexAPI.instance().getRawHookI18n(HexAPI.modLoc(when (pattern?.angles) { SpecialPatterns.RETROSPECTION.angles -> "close_paren" - SpecialPatterns.BIG_INTRO.angles -> "open_n_parens" + SpecialPatterns.INTROSPECTION_II.angles -> "open_n_parens" else -> "unknown" })) ) @@ -253,11 +251,11 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { } } - SpecialPatterns.BIG_INTRO.angles -> { - throw MishapBigIntroInParens() + SpecialPatterns.INTROSPECTION_II.angles -> { + throw MishapNestedBigParen() } - SpecialPatterns.BIG_RETRO.angles -> { + SpecialPatterns.RETROSPECTION_II.angles -> { displayDepth = 0 val newStack = this.image.stack.toMutableList() newStack.add(DoubleIota(this.image.parenCount.toDouble())) @@ -303,7 +301,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { throw MishapTooManyCloseParens() } - SpecialPatterns.BIG_INTRO.angles -> { + SpecialPatterns.INTROSPECTION_II.angles -> { val newStack = this.image.stack.toMutableList() val layers = when (val topIota = newStack.removeLastOrNull()) { null -> throw MishapNotEnoughArgs(1, 0) @@ -316,7 +314,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { ) to ResolvedPatternType.EVALUATED } - SpecialPatterns.BIG_RETRO.angles -> { + SpecialPatterns.RETROSPECTION_II.angles -> { throw MishapTooManyCloseParens() } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBigIntroInParens.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNestedBigParen.kt similarity index 81% rename from Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBigIntroInParens.kt rename to Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNestedBigParen.kt index b9ab81c0fd..783f0d3585 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBigIntroInParens.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNestedBigParen.kt @@ -2,11 +2,10 @@ package at.petrak.hexcasting.api.casting.mishaps import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.api.casting.iota.PatternIota import at.petrak.hexcasting.api.pigment.FrozenPigment import net.minecraft.world.item.DyeColor -class MishapBigIntroInParens : Mishap() { +class MishapNestedBigParen : Mishap() { override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment = dyeColor(DyeColor.ORANGE) @@ -15,5 +14,5 @@ class MishapBigIntroInParens : Mishap() { } override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = - error("big_intro_in_parens") + error("open_n_while_nested") } 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 2cefea5e28..306ecc3c47 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 @@ -990,8 +990,8 @@ "rawhook.hexcasting:": { open_paren: "Introspection", close_paren: "Retrospection", - open_n_parens: "[BIG_INTRO]", - close_all_parens: "[BIG_RETRO]", + open_n_parens: "Introspection II", + close_all_parens: "Retrospection II", escape: "Consideration", undo: "Evanition", unknown: "Unknown Pattern (this is a bug!)", @@ -1046,7 +1046,7 @@ not_enough_args: "expected %s or more arguments but the stack was only %s tall", no_args: "expected %s or more arguments but the stack was empty", too_many_close_parens: "Did not first use Introspection", - big_intro_in_parens: "Tried to use [BIG_INTRO] after Introspection", + open_n_while_nested: "Tried to use Introspection II after Introspection", wrong_dimension: "cannot see %s from %s", entity_too_far: "%s is out of range", @@ -1970,7 +1970,7 @@ "2": "One may find it helpful to think of this as \"escaping\" the pattern onto the stack, if they happen to be familiar with the science of computers.$(br2)The usual use for this is to copy the pattern to a $(l:items/scroll)$(item)Scroll/$ or $(l:items/slate)$(item)Slate/$ using $(l:patterns/readwrite#hexcasting:write)$(action)Scribe's Gambit/$, and then perhaps decorating with them.", }, parens: { - "1": "Drawing $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$ makes my drawing of patterns act differently, for a time. Until I draw $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Retrospection/$, the patterns I draw are saved. Then, when I draw $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, they are added to the stack as a list iota.", + "1": "Drawing $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$ makes my drawing of patterns act differently, for a time. Until I draw $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, the patterns I draw are saved. Then, when I draw $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, they are added to the stack as a list iota.", "2": "If I draw another $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Introspection/$, it'll still be saved to the list, but I'll then have to draw $(italic)two/$ $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospections/$ to get back to normal casting.", }, undo: "Finally, if I make a mistake while drawing patterns inside $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Intro-/$ and $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$ I can draw $(l:patterns/patterns_as_iotas#hexcasting:undo)$(action)Evanition/$ to remove the last pattern that I drew from the pattern list that is being constructed.", @@ -1980,6 +1980,10 @@ "2": "If an iota other than a pattern is present in a list to be executed by $(l:patterns/meta#hexcasting:eval)$(action)Hermes' Gambit/$ or any other meta-evaluation pattern, it will normally result in a mishap. However, this can be avoided using the patterns described in this section.$(br2)Just as with pattern iotas, the patterns described here can be used to \"escape\" $(o)any other$() kind of iota, causing it to be pushed to the stack when something tries to evaluate it instead of causing a mishap.", "3": "This technique may be useful if I want a _Hex to be able to reference a specific iota, such as a complicated vector or an entity reference, without having to construct or obtain it each time.$(br2)The process of getting such an iota into a list of patterns in the first place may be somewhat involved. The simplest method would be to draw a placeholder pattern when assembling the list, and then make use of $(l:patterns/lists#hexcasting:replace)$(action)Surgeon's Exaltation/$ to replace it with my desired iota.", }, + advanced_parens: { + "1": "Works like $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$, but also removes a number from the stack. I can then draw patterns as though I'd drawn $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$ that many times. Fails if inside $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$.", + "2": "Works like $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, but closes $(italic)all/$ open $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspections/$ at once. The number of layers closed, along with the list of saved patterns, are then added to the stack.", + } }, readwrite: { diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json index 1f8cc778af..9bb82ef1a3 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json @@ -70,6 +70,28 @@ { "type": "patchouli:text", "text": "hexcasting.page.patterns_as_iotas.further_notes.3" + }, + { + "type": "hexcasting:manual_pattern", + "header": "hexcasting.rawhook.hexcasting:open_n_parens", + "anchor": "hexcasting:open_n_parens", + "text": "hexcasting.page.patterns_as_iotas.advanced_parens.1", + "input": "num", + "patterns": { + "startdir": "SOUTH_WEST", + "signature": "eqqqe" + } + }, + { + "type": "hexcasting:manual_pattern", + "header": "hexcasting.rawhook.hexcasting:close_all_parens", + "anchor": "hexcasting:close_all_parens", + "text": "hexcasting.page.patterns_as_iotas.advanced_parens.2", + "output": "num, [pattern]", + "patterns": { + "startdir": "SOUTH_EAST", + "signature": "qeeeq" + } } ] } From 4622ff887072452f61b9d36886cacb49d3cc267b Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Tue, 12 May 2026 21:14:59 -0400 Subject: [PATCH 4/5] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05c834cd67..3c0263100d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - Added the `cannot_modify_cost` tag for patterns that should ignore the `media_consumption` attribute when calculating cost, by Robotgiggle in [987](https://github.com/FallingColors/HexMod/pull/987). +- Added Introspection II and Retrospection II for advanced pattern-list creation, by Robotgiggle in [#1046](https://github.com/FallingColors/HexMod/pull/1046). ### Changed From c702660ad485718e94aaf763430fc27594ceb375 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Wed, 13 May 2026 00:07:02 -0400 Subject: [PATCH 5/5] Better names, remove mishap --- CHANGELOG.md | 2 +- .../api/casting/eval/SpecialPatterns.java | 4 +- .../api/casting/eval/vm/CastingVM.kt | 17 ++++--- .../casting/mishaps/MishapNestedBigParen.kt | 18 -------- .../hexcasting/lang/en_us.flatten.json5 | 17 ++++--- .../entries/patterns/patterns_as_iotas.json | 45 ++++++++++--------- 6 files changed, 44 insertions(+), 59 deletions(-) delete mode 100644 Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNestedBigParen.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c0263100d..0dad54e375 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - Added the `cannot_modify_cost` tag for patterns that should ignore the `media_consumption` attribute when calculating cost, by Robotgiggle in [987](https://github.com/FallingColors/HexMod/pull/987). -- Added Introspection II and Retrospection II for advanced pattern-list creation, by Robotgiggle in [#1046](https://github.com/FallingColors/HexMod/pull/1046). +- Added Meditation and Recollection for advanced pattern-list creation, by Robotgiggle in [#1046](https://github.com/FallingColors/HexMod/pull/1046). ### Changed diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java index 65a8ec0f85..703bc8dd40 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/SpecialPatterns.java @@ -6,8 +6,8 @@ public final class SpecialPatterns { public static final HexPattern INTROSPECTION = HexPattern.fromAngles("qqq", HexDir.WEST); public static final HexPattern RETROSPECTION = HexPattern.fromAngles("eee", HexDir.EAST); - public static final HexPattern INTROSPECTION_II = HexPattern.fromAngles("eqqqe", HexDir.SOUTH_WEST); - public static final HexPattern RETROSPECTION_II = HexPattern.fromAngles("qeeeq", HexDir.SOUTH_EAST); + public static final HexPattern MEDITATION = HexPattern.fromAngles("eqqqe", HexDir.SOUTH_WEST); + public static final HexPattern RECOLLECTION = HexPattern.fromAngles("qeeeq", HexDir.SOUTH_EAST); public static final HexPattern CONSIDERATION = HexPattern.fromAngles("qqqaw", HexDir.WEST); public static final HexPattern EVANITION = HexPattern.fromAngles("eeedw", HexDir.EAST); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index d6bed9446f..d68c47dcf8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -127,7 +127,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { pattern ?: HexPattern(HexDir.WEST), HexAPI.instance().getRawHookI18n(HexAPI.modLoc(when (pattern?.angles) { SpecialPatterns.RETROSPECTION.angles -> "close_paren" - SpecialPatterns.INTROSPECTION_II.angles -> "open_n_parens" + SpecialPatterns.MEDITATION.angles -> "open_n_parens" else -> "unknown" })) ) @@ -251,11 +251,14 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { } } - SpecialPatterns.INTROSPECTION_II.angles -> { - throw MishapNestedBigParen() - } + // Meditation is treated as a normal pattern while nested since there's + // no way to determine how many layers it should open + // + // SpecialPatterns.MEDITATION.angles -> { + // throw MishapTooManyCloseParens() + // } - SpecialPatterns.RETROSPECTION_II.angles -> { + SpecialPatterns.RECOLLECTION.angles -> { displayDepth = 0 val newStack = this.image.stack.toMutableList() newStack.add(DoubleIota(this.image.parenCount.toDouble())) @@ -301,7 +304,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { throw MishapTooManyCloseParens() } - SpecialPatterns.INTROSPECTION_II.angles -> { + SpecialPatterns.MEDITATION.angles -> { val newStack = this.image.stack.toMutableList() val layers = when (val topIota = newStack.removeLastOrNull()) { null -> throw MishapNotEnoughArgs(1, 0) @@ -314,7 +317,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { ) to ResolvedPatternType.EVALUATED } - SpecialPatterns.RETROSPECTION_II.angles -> { + SpecialPatterns.RECOLLECTION.angles -> { throw MishapTooManyCloseParens() } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNestedBigParen.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNestedBigParen.kt deleted file mode 100644 index 783f0d3585..0000000000 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNestedBigParen.kt +++ /dev/null @@ -1,18 +0,0 @@ -package at.petrak.hexcasting.api.casting.mishaps - -import at.petrak.hexcasting.api.casting.eval.CastingEnvironment -import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.api.pigment.FrozenPigment -import net.minecraft.world.item.DyeColor - -class MishapNestedBigParen : Mishap() { - override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment = - dyeColor(DyeColor.ORANGE) - - override fun execute(env: CastingEnvironment, errorCtx: Context, stack: MutableList) { - // no-op - } - - override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = - error("open_n_while_nested") -} 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 306ecc3c47..5cde25b74f 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 @@ -990,8 +990,8 @@ "rawhook.hexcasting:": { open_paren: "Introspection", close_paren: "Retrospection", - open_n_parens: "Introspection II", - close_all_parens: "Retrospection II", + open_n_parens: "Meditation", + close_all_parens: "Recollection", escape: "Consideration", undo: "Evanition", unknown: "Unknown Pattern (this is a bug!)", @@ -1046,7 +1046,6 @@ not_enough_args: "expected %s or more arguments but the stack was only %s tall", no_args: "expected %s or more arguments but the stack was empty", too_many_close_parens: "Did not first use Introspection", - open_n_while_nested: "Tried to use Introspection II after Introspection", wrong_dimension: "cannot see %s from %s", entity_too_far: "%s is out of range", @@ -1964,7 +1963,7 @@ patterns_as_iotas: { "1": "One of the many peculiarities of this art is that $(italic)patterns themselves/$ can act as iotas-- I can even put them onto my stack when casting.$(br2)This raises a fairly obvious question: how do I express them? If I simply drew a pattern, it would hardly tell Nature to add it to my stack-- rather, it would simply be matched to an action.", - "2": "Fortunately, Nature has provided me with a set of $(l:casting/influences)influences/$ that I can use to work with patterns directly.$(br2)In short, $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$ lets me add one pattern to the stack, and $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$ and $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$ let me add a whole list.", + "2": "Fortunately, Nature has provided me with a set of $(l:casting/influences)influences/$ that I can use to work with patterns directly.$(br2)To summarize, $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$ lets me add one pattern to the stack, $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$ and $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$ let me add a whole list, $(l:patterns/patterns_as_iotas#hexcasting:open_n_parens)$(action)Meditation/$ and $(l:patterns/patterns_as_iotas#hexcasting:close_all_parens)$(action)Recollection/$ allow for more advanced list creation, and $(l:patterns/patterns_as_iotas#hexcasting:undo)$(action)Evanition/$ lets me undo mistakes made with the others.", escape: { "1": "To use $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$, I draw it, then another arbitrary pattern. That second pattern is added to the stack.", "2": "One may find it helpful to think of this as \"escaping\" the pattern onto the stack, if they happen to be familiar with the science of computers.$(br2)The usual use for this is to copy the pattern to a $(l:items/scroll)$(item)Scroll/$ or $(l:items/slate)$(item)Slate/$ using $(l:patterns/readwrite#hexcasting:write)$(action)Scribe's Gambit/$, and then perhaps decorating with them.", @@ -1973,17 +1972,17 @@ "1": "Drawing $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$ makes my drawing of patterns act differently, for a time. Until I draw $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, the patterns I draw are saved. Then, when I draw $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, they are added to the stack as a list iota.", "2": "If I draw another $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Introspection/$, it'll still be saved to the list, but I'll then have to draw $(italic)two/$ $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospections/$ to get back to normal casting.", }, + advanced_parens: { + "1": "Removes a number from the stack, then acts as though I'd drawn that many $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspections/$. Treated as a normal pattern while $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)introspecting/$, so nesting this may require $(l:patterns/patterns_as_iotas#further_notes)$(action)tricks/$ to draw extra $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospections/$.", + "2": "Works like $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, but closes $(italic)all/$ open $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspections/$ at once. The number of layers closed, along with the list of saved patterns, are then added to the stack.", + }, undo: "Finally, if I make a mistake while drawing patterns inside $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Intro-/$ and $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$ I can draw $(l:patterns/patterns_as_iotas#hexcasting:undo)$(action)Evanition/$ to remove the last pattern that I drew from the pattern list that is being constructed.", further_notes: { title: "Further Notes", - "1": "I can escape the special behavior of $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Intro-/$ and $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$ by drawing a $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$ before them, which will simply add them to the list without affecting which the number of $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospections/$ I need to return to casting.$(br2)If I draw two $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Considerations/$ in a row while $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)introspecting/$, it will add a single $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$ to the list.", + "1": "I can escape the special behavior of patterns like $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Intro-/$ and $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$ by drawing a $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$ before them, which will simply add them to the list without affecting which the number of $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospections/$ I need to return to casting.$(br2)If I draw two $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Considerations/$ in a row while $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)introspecting/$, it will add a single $(l:patterns/patterns_as_iotas#hexcasting:escape)$(action)Consideration/$ to the list.", "2": "If an iota other than a pattern is present in a list to be executed by $(l:patterns/meta#hexcasting:eval)$(action)Hermes' Gambit/$ or any other meta-evaluation pattern, it will normally result in a mishap. However, this can be avoided using the patterns described in this section.$(br2)Just as with pattern iotas, the patterns described here can be used to \"escape\" $(o)any other$() kind of iota, causing it to be pushed to the stack when something tries to evaluate it instead of causing a mishap.", "3": "This technique may be useful if I want a _Hex to be able to reference a specific iota, such as a complicated vector or an entity reference, without having to construct or obtain it each time.$(br2)The process of getting such an iota into a list of patterns in the first place may be somewhat involved. The simplest method would be to draw a placeholder pattern when assembling the list, and then make use of $(l:patterns/lists#hexcasting:replace)$(action)Surgeon's Exaltation/$ to replace it with my desired iota.", }, - advanced_parens: { - "1": "Works like $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$, but also removes a number from the stack. I can then draw patterns as though I'd drawn $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$ that many times. Fails if inside $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspection/$.", - "2": "Works like $(l:patterns/patterns_as_iotas#hexcasting:close_paren)$(action)Retrospection/$, but closes $(italic)all/$ open $(l:patterns/patterns_as_iotas#hexcasting:open_paren)$(action)Introspections/$ at once. The number of layers closed, along with the list of saved patterns, are then added to the stack.", - } }, readwrite: { diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json index 9bb82ef1a3..cd04ccb065 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/patterns_as_iotas.json @@ -48,6 +48,28 @@ "signature": "eee" } }, + { + "type": "hexcasting:manual_pattern", + "header": "hexcasting.rawhook.hexcasting:open_n_parens", + "anchor": "hexcasting:open_n_parens", + "text": "hexcasting.page.patterns_as_iotas.advanced_parens.1", + "input": "num", + "patterns": { + "startdir": "SOUTH_WEST", + "signature": "eqqqe" + } + }, + { + "type": "hexcasting:manual_pattern", + "header": "hexcasting.rawhook.hexcasting:close_all_parens", + "anchor": "hexcasting:close_all_parens", + "text": "hexcasting.page.patterns_as_iotas.advanced_parens.2", + "output": "num, [pattern]", + "patterns": { + "startdir": "SOUTH_EAST", + "signature": "qeeeq" + } + }, { "type": "hexcasting:manual_pattern", "header": "hexcasting.rawhook.hexcasting:undo", @@ -60,6 +82,7 @@ }, { "type": "patchouli:text", + "anchor": "further_notes", "title": "hexcasting.page.patterns_as_iotas.further_notes.title", "text": "hexcasting.page.patterns_as_iotas.further_notes.1" }, @@ -70,28 +93,6 @@ { "type": "patchouli:text", "text": "hexcasting.page.patterns_as_iotas.further_notes.3" - }, - { - "type": "hexcasting:manual_pattern", - "header": "hexcasting.rawhook.hexcasting:open_n_parens", - "anchor": "hexcasting:open_n_parens", - "text": "hexcasting.page.patterns_as_iotas.advanced_parens.1", - "input": "num", - "patterns": { - "startdir": "SOUTH_WEST", - "signature": "eqqqe" - } - }, - { - "type": "hexcasting:manual_pattern", - "header": "hexcasting.rawhook.hexcasting:close_all_parens", - "anchor": "hexcasting:close_all_parens", - "text": "hexcasting.page.patterns_as_iotas.advanced_parens.2", - "output": "num, [pattern]", - "patterns": { - "startdir": "SOUTH_EAST", - "signature": "qeeeq" - } } ] }