Skip to content
Open
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,17 @@ fun List<Iota>.getLongOrList(idx: Int, argc: Int = 0): Either<Long, SpellList> {
)
}

fun evaluatable(datum: Iota, reverseIdx: Int): Either<Iota, SpellList> =
when (datum) {
fun List<Iota>.getEvaluatable(idx: Int, argc: Int = 0): Either<Iota, SpellList> {
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()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: Iota): OperationResult {
fun exec(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation, newStack: MutableList<Iota>, instrs: Either<Iota, SpellList>): 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ public LootItemFunctionType<? extends LootItemConditionalFunction> 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"})
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand All @@ -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"
},
Expand All @@ -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"
},
Expand Down
Loading