diff --git a/CHANGELOG.md b/CHANGELOG.md index d401546f7..574d066e9 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 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 d67e0693b..6a2b1acc8 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/api/casting/eval/vm/FrameForEach.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt index 6133b2b62..1c8cb2dd5 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,8 @@ 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) + // Only the iotas above the waterline (size of the base stack) are kept. + baseStack to acc.appendedAll(harness.image.stack.drop(baseStack.size)) } // If we still have data to process... 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 e9c9adf2a..a6808ed55 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 f778d8735..c6fe3272f 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 926bce1d8..521886b69 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.getEvaluatable import at.petrak.hexcasting.api.casting.getList import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs import at.petrak.hexcasting.api.utils.TreeList @@ -18,12 +20,14 @@ 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.getEvaluatable(stack.lastIndex, stack.size) 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) 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 eb049a8e7..1fcbf1fdb 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", 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 82585e1a5..1e42a6c36 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[] {"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 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[] {"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"}) ); } 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 528f82646..64ec0d9f9 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 63e7f68c4..f14406e39 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 of patterns, list", + "input": "list, evaluatable", "output": "list", "text": "hexcasting.page.meta.for_each.1" },