diff --git a/CHANGELOG.md b/CHANGELOG.md index 05c834cd67..0dad54e375 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 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 f87fcfdfae..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,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 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 3d03a9a843..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 @@ -1,19 +1,19 @@ 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 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 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 @@ -113,8 +113,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, @@ -123,8 +124,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.MEDITATION.angles -> "open_n_parens" + else -> "unknown" + })) ) ) ), @@ -177,7 +182,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 @@ -246,6 +251,25 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { } } + // 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.RECOLLECTION.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 +304,23 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { throw MishapTooManyCloseParens() } + SpecialPatterns.MEDITATION.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.RECOLLECTION.angles -> { + throw MishapTooManyCloseParens() + } + else -> { null } 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..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,11 @@ "rawhook.hexcasting:": { open_paren: "Introspection", close_paren: "Retrospection", + open_n_parens: "Meditation", + close_all_parens: "Recollection", escape: "Consideration", undo: "Evanition", + unknown: "Unknown Pattern (this is a bug!)", }, "iota.hexcasting:": { @@ -1960,19 +1963,23 @@ 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.", }, 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.", }, + 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.", }, 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..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" },