From fe7051301b83d6ef0880e9e3eacb039309eacf06 Mon Sep 17 00:00:00 2001 From: "yrsegal@gmail.com" Date: Fri, 6 May 2022 22:16:28 -0400 Subject: [PATCH] add Huginn's Gambit, Muninn's Reflection, and Surgeon's Exaltation no patterns for huginn and muninn (yet) --- .../circle/BlockEntityAbstractImpetus.java | 2 +- .../hexcasting/api/spell/ConstManaOperator.kt | 4 +- .../hexcasting/api/spell/OperationResult.kt | 2 +- .../petrak/hexcasting/api/spell/Operator.kt | 2 +- .../petrak/hexcasting/api/spell/SpellDatum.kt | 5 +- .../hexcasting/api/spell/SpellOperator.kt | 6 +- .../api/spell/casting/CastingHarness.kt | 33 +++++++--- .../api/spell/mishaps/MishapError.kt | 18 +++++ .../petrak/hexcasting/api/utils/NBTHelper.kt | 66 ++++++++++++++++++- .../client/HexAdditionalRenderers.java | 62 ++++++++++++----- .../common/casting/RegisterPatterns.java | 2 + .../operators/akashic/OpAkashicRead.kt | 6 +- .../common/casting/operators/eval/OpEval.kt | 8 +-- .../casting/operators/eval/OpEvalDelay.kt | 4 +- .../casting/operators/eval/OpForEach.kt | 10 ++- .../casting/operators/lists/OpLastNToList.kt | 5 +- .../operators/lists/OpModifyInPlace.kt | 29 ++++++++ .../casting/operators/local/OpPeekLocal.kt | 17 +++++ .../casting/operators/local/OpPushLocal.kt | 20 ++++++ .../casting/operators/spells/OpPrint.kt | 4 +- .../operators/spells/great/OpFlight.kt | 10 ++- .../OpAlwinfyHasAscendedToABeingOfPureMath.kt | 3 +- .../casting/operators/stack/OpFisherman.kt | 4 +- .../casting/operators/stack/OpStackSize.kt | 11 +--- .../hexcasting/mixin/MixinVillager.java | 9 +++ .../assets/hexcasting/lang/en_us.json | 11 +++- .../en_us/entries/casting/mishaps.json | 4 +- .../en_us/entries/patterns/lists.json | 8 +++ 28 files changed, 290 insertions(+), 75 deletions(-) create mode 100644 src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapError.kt create mode 100644 src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpModifyInPlace.kt create mode 100644 src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt create mode 100644 src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt diff --git a/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java b/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java index 38f97c5f..cd15d519 100644 --- a/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java +++ b/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java @@ -177,7 +177,7 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple if (tag.contains(TAG_ACTIVATOR, Tag.TAG_INT_ARRAY) && tag.contains(TAG_COLORIZER, Tag.TAG_COMPOUND) && tag.contains(TAG_NEXT_BLOCK, Tag.TAG_COMPOUND) && - tag.contains(TAG_TRACKED_BLOCKS, Tag.TAG_COMPOUND)) { + tag.contains(TAG_TRACKED_BLOCKS, Tag.TAG_LIST)) { this.activator = tag.getUUID(TAG_ACTIVATOR); this.colorizer = FrozenColorizer.deserialize(tag.getCompound(TAG_COLORIZER)); this.nextBlock = NbtUtils.readBlockPos(tag.getCompound(TAG_NEXT_BLOCK)); diff --git a/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt b/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt index 65b30c1b..ddd0de65 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt @@ -14,7 +14,7 @@ interface ConstManaOperator : Operator { fun execute(args: List>, ctx: CastingContext): List> - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) @@ -24,6 +24,6 @@ interface ConstManaOperator : Operator { val sideEffects = mutableListOf(OperatorSideEffect.ConsumeMana(this.manaCost)) - return OperationResult(stack, sideEffects) + return OperationResult(stack, local, sideEffects) } } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt b/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt index 6494d92e..09845dbb 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/OperationResult.kt @@ -5,4 +5,4 @@ import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect /** * What happens when an operator is through? */ -data class OperationResult(val newStack: List>, val sideEffects: List) +data class OperationResult(val newStack: List>, val newLocalIota: SpellDatum<*>, val sideEffects: List) diff --git a/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt b/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt index 0b6abb1d..ed134a2f 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt @@ -23,7 +23,7 @@ interface Operator { * * A particle effect at the cast site and various messages and advancements are done automagically. */ - fun operate(stack: MutableList>, ctx: CastingContext): OperationResult + fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult /** * Do you need to be enlightened to use this operator? diff --git a/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt b/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt index 0058c9d0..d1be7c6d 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/SpellDatum.kt @@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.api.utils.HexUtils.serializeToNBT +import at.petrak.hexcasting.api.utils.getList import net.minecraft.ChatFormatting import net.minecraft.nbt.* import net.minecraft.network.chat.Component @@ -144,7 +145,7 @@ class SpellDatum private constructor(val payload: T) { TAG_DOUBLE -> SpellDatum(nbt.getDouble(key)) TAG_VEC3 -> SpellDatum(HexUtils.DeserializeVec3FromNBT(nbt.getLongArray(key))) TAG_LIST -> { - val arr = nbt.getList(key, Tag.TAG_COMPOUND.toInt()) + val arr = nbt.getList(key, Tag.TAG_COMPOUND) val out = ArrayList>(arr.size) for (subtag in arr) { // this is safe because otherwise we wouldn't have been able to get the list before @@ -188,7 +189,7 @@ class SpellDatum private constructor(val payload: T) { TAG_LIST -> { val out = TextComponent("[").withStyle(ChatFormatting.WHITE) - val arr = nbt.getList(key, Tag.TAG_COMPOUND.toInt()) + val arr = nbt.getList(key, Tag.TAG_COMPOUND) for ((i, subtag) in arr.withIndex()) { // this is safe because otherwise we wouldn't have been able to get the list before out.append(DisplayFromTag(subtag as CompoundTag)) diff --git a/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt b/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt index 0f8d31fa..aedfea12 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/SpellOperator.kt @@ -16,12 +16,12 @@ interface SpellOperator : Operator { ctx: CastingContext ): Triple>? - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) for (_i in 0 until this.argc) stack.removeLast() - val executeResult = this.execute(args, ctx) ?: return OperationResult(stack, listOf()) + val executeResult = this.execute(args, ctx) ?: return OperationResult(stack, local, listOf()) val (spell, mana, particles) = executeResult val sideEffects = mutableListOf( @@ -32,7 +32,7 @@ interface SpellOperator : Operator { sideEffects.add(OperatorSideEffect.Particles(spray)) } - return OperationResult(stack, sideEffects) + return OperationResult(stack, local, sideEffects) } } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt b/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt index 2bc36f70..a6331c04 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt @@ -16,9 +16,12 @@ import at.petrak.hexcasting.api.spell.Widget import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.mishaps.Mishap import at.petrak.hexcasting.api.spell.mishaps.MishapDisallowedSpell +import at.petrak.hexcasting.api.spell.mishaps.MishapError import at.petrak.hexcasting.api.spell.mishaps.MishapTooManyCloseParens import at.petrak.hexcasting.api.utils.HexDamageSources import at.petrak.hexcasting.api.utils.ManaHelper +import at.petrak.hexcasting.api.utils.asCompound +import at.petrak.hexcasting.api.utils.getList import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.nbt.Tag @@ -34,6 +37,7 @@ import kotlin.math.min */ class CastingHarness private constructor( var stack: MutableList>, + var localIota: SpellDatum<*>, var parenCount: Int, var parenthesized: List, var escapeNext: Boolean, @@ -45,7 +49,7 @@ class CastingHarness private constructor( constructor( ctx: CastingContext, prepackagedColorizer: FrozenColorizer? = null - ) : this(mutableListOf(), 0, mutableListOf(), false, ctx, prepackagedColorizer) + ) : this(mutableListOf(), SpellDatum.make(Widget.NULL), 0, mutableListOf(), false, ctx, prepackagedColorizer) /** * Given a pattern, do all the updating/side effects/etc required. @@ -81,7 +85,8 @@ class CastingHarness private constructor( if (HexConfig.Server.actionDenyList.get().contains(operatorIdPair.second.toString())) { throw MishapDisallowedSpell() } - val (stack2, sideEffectsUnmut) = operatorIdPair.first.operate(this.stack.toMutableList(), this.ctx) + val (stack2, local2, sideEffectsUnmut) = operatorIdPair.first.operate(this.stack.toMutableList(), this.localIota, this.ctx) + this.localIota = local2 // Stick a poofy particle effect at the caster position val sideEffects = sideEffectsUnmut.toMutableList() if (this.ctx.spellCircle == null) @@ -108,6 +113,12 @@ class CastingHarness private constructor( this.getFunctionalData(), listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.second))), ) + } catch (exception: Exception) { + exception.printStackTrace() + return CastResult( + this.getFunctionalData(), + listOf(OperatorSideEffect.DoMishap(MishapError(exception), Mishap.Context(newPat, operatorIdPair?.second))) + ) } } @@ -340,6 +351,8 @@ class CastingHarness private constructor( stackTag.add(datum.serializeToNBT()) out.put(TAG_STACK, stackTag) + out.put(TAG_LOCAL, localIota.serializeToNBT()) + out.putInt(TAG_PAREN_COUNT, this.parenCount) out.putBoolean(TAG_ESCAPE_NEXT, this.escapeNext) @@ -358,25 +371,29 @@ class CastingHarness private constructor( companion object { const val TAG_STACK = "stack" + const val TAG_LOCAL = "local" const val TAG_PAREN_COUNT = "open_parens" const val TAG_PARENTHESIZED = "parenthesized" const val TAG_ESCAPE_NEXT = "escape_next" const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer" @JvmStatic - fun DeserializeFromNBT(nbt: Tag, ctx: CastingContext): CastingHarness { + fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness { return try { val stack = mutableListOf>() - val stackTag = (nbt as CompoundTag).getList(TAG_STACK, Tag.TAG_COMPOUND.toInt()) + val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND) for (subtag in stackTag) { - val datum = SpellDatum.DeserializeFromNBT(subtag as CompoundTag, ctx.world) + val datum = SpellDatum.DeserializeFromNBT(subtag.asCompound, ctx.world) stack.add(datum) } + val localTag = nbt.getCompound(TAG_LOCAL) + val localIota = SpellDatum.DeserializeFromNBT(localTag, ctx.world) + val parenthesized = mutableListOf() - val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND.toInt()) + val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND) for (subtag in parenTag) { - parenthesized.add(HexPattern.DeserializeFromNBT(subtag as CompoundTag)) + parenthesized.add(HexPattern.DeserializeFromNBT(subtag.asCompound)) } val parenCount = nbt.getInt(TAG_PAREN_COUNT) @@ -388,7 +405,7 @@ class CastingHarness private constructor( null } - CastingHarness(stack, parenCount, parenthesized, escapeNext, ctx, colorizer) + CastingHarness(stack, localIota, parenCount, parenthesized, escapeNext, ctx, colorizer) } catch (exn: Exception) { CastingHarness(ctx) } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapError.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapError.kt new file mode 100644 index 00000000..0b9b55ff --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapError.kt @@ -0,0 +1,18 @@ +package at.petrak.hexcasting.api.spell.mishaps + +import at.petrak.hexcasting.api.misc.FrozenColorizer +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.casting.CastingContext +import net.minecraft.network.chat.Component +import net.minecraft.world.item.DyeColor + +class MishapError(val exception: Exception) : Mishap() { + override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer = + dyeColor(DyeColor.BLACK) + + override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList>) { + } + + override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component = + error("unknown", actionName(errorCtx.action), exception) +} diff --git a/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt b/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt index 8cea576c..fc5dc92d 100644 --- a/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt +++ b/src/main/java/at/petrak/hexcasting/api/utils/NBTHelper.kt @@ -1,9 +1,7 @@ @file:JvmName("NBTHelper") package at.petrak.hexcasting.api.utils -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.nbt.Tag +import net.minecraft.nbt.* import net.minecraft.world.item.ItemStack import java.util.* @@ -85,14 +83,76 @@ fun CompoundTag?.getIntArray(key: String) = getIf(key, CompoundTag?::hasIntArray fun CompoundTag?.getByteArray(key: String) = getIf(key, CompoundTag?::hasByteArray, CompoundTag::getByteArray) fun CompoundTag?.getCompound(key: String): CompoundTag? = getIf(key, CompoundTag?::hasCompound, CompoundTag::getCompound) fun CompoundTag?.getString(key: String) = getIf(key, CompoundTag?::hasString, CompoundTag::getString) +fun CompoundTag?.getList(key: String, objType: Byte) = getList(key, objType.toInt()) fun CompoundTag?.getList(key: String, objType: Int) = getIf(key, { hasList(key, objType) }) { getList(it, objType) } fun CompoundTag?.getUUID(key: String) = getIf(key, CompoundTag?::hasUUID, CompoundTag::getUUID) fun CompoundTag?.get(key: String) = getIf(key, CompoundTag?::contains, CompoundTag::get) +@JvmSynthetic +@JvmName("getListByByte") +fun CompoundTag.getList(key: String, objType: Byte): ListTag = getList(key, objType.toInt()) + // Get-or-create fun CompoundTag.getOrCreateCompound(key: String) = getCompound(key) ?: CompoundTag().also { putCompound(key, this) } +// ================================================================================================================ Tag + +val Tag.asBoolean get() = asByte == 0.toByte() +val Tag.asByte get() = (this as? NumericTag)?.asByte ?: 0.toByte() +val Tag.asShort get() = (this as? NumericTag)?.asShort ?: 0.toShort() +val Tag.asInt get() = (this as? NumericTag)?.asInt ?: 0 +val Tag.asLong get() = (this as? NumericTag)?.asLong ?: 0L +val Tag.asFloat get() = (this as? NumericTag)?.asFloat ?: 0F +val Tag.asDouble get() = (this as? NumericTag)?.asDouble ?: 0.0 + +val Tag.asLongArray: LongArray + get() = when (this) { + is LongArrayTag -> this.asLongArray + is IntArrayTag -> { + val array = this.asIntArray + LongArray(array.size) { array[it].toLong() } + } + is ByteArrayTag -> { + val array = this.asByteArray + LongArray(array.size) { array[it].toLong() } + } + else -> LongArray(0) + } + +val Tag.asIntArray: IntArray + get() = when (this) { + is IntArrayTag -> this.asIntArray + is LongArrayTag -> { + val array = this.asLongArray + IntArray(array.size) { array[it].toInt() } + } + is ByteArrayTag -> { + val array = this.asByteArray + IntArray(array.size) { array[it].toInt() } + } + else -> IntArray(0) + } + +val Tag.asByteArray: ByteArray + get() = when (this) { + is ByteArrayTag -> this.asByteArray + is LongArrayTag -> { + val array = this.asLongArray + ByteArray(array.size) { array[it].toByte() } + } + is IntArrayTag -> { + val array = this.asIntArray + ByteArray(array.size) { array[it].toByte() } + } + else -> ByteArray(0) + } + +val Tag.asCompound get() = this as? CompoundTag ?: CompoundTag() +// asString is defined in Tag +val Tag.asList get() = this as? ListTag ?: ListTag() +val Tag.asUUID: UUID get() = if (this is IntArrayTag && this.size == 4) NbtUtils.loadUUID(this) else UUID(0, 0) + // ========================================================================================================== ItemStack // Checks for containment diff --git a/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java b/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java index 05677af5..92e5c6e6 100644 --- a/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java +++ b/src/main/java/at/petrak/hexcasting/client/HexAdditionalRenderers.java @@ -1,24 +1,29 @@ package at.petrak.hexcasting.client; import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry; +import at.petrak.hexcasting.api.player.HexPlayerDataHelper; import at.petrak.hexcasting.api.player.Sentinel; import at.petrak.hexcasting.common.items.HexItems; -import at.petrak.hexcasting.api.player.HexPlayerDataHelper; +import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.datafixers.util.Pair; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.locale.Language; +import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.Style; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; @@ -26,6 +31,7 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderLevelLastEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; +import java.util.List; import java.util.function.BiConsumer; public class HexAdditionalRenderers { @@ -43,7 +49,7 @@ public class HexAdditionalRenderers { @SubscribeEvent public static void overlayGui(RenderGameOverlayEvent.Post evt) { if (evt.getType() == RenderGameOverlayEvent.ElementType.ALL) { - tryRenderScryingLensOverlay(evt.getMatrixStack(), evt.getPartialTicks()); + tryRenderScryingLensOverlay(evt.getMatrixStack()); } } @@ -149,19 +155,24 @@ public class HexAdditionalRenderers { // My internet is really shaky right now but thank god Patchi already does this exact thing // cause it's a dependency so i have the .class files downloaded - private static void tryRenderScryingLensOverlay(PoseStack ps, float partialTicks) { + private static void tryRenderScryingLensOverlay(PoseStack ps) { var mc = Minecraft.getInstance(); + LocalPlayer player = mc.player; + ClientLevel level = mc.level; + if (player == null || level == null) + return; + boolean foundLens = false; InteractionHand lensHand = null; for (var hand : InteractionHand.values()) { - if (mc.player.getItemInHand(hand).is(HexItems.SCRYING_LENS.get())) { + if (player.getItemInHand(hand).is(HexItems.SCRYING_LENS.get())) { lensHand = hand; foundLens = true; break; } } - if (!foundLens && mc.player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS.get())) { + if (!foundLens && player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS.get())) { foundLens = true; } @@ -170,22 +181,38 @@ public class HexAdditionalRenderers { } var hitRes = mc.hitResult; - if (hitRes.getType() == HitResult.Type.BLOCK) { + if (hitRes != null && hitRes.getType() == HitResult.Type.BLOCK) { var bhr = (BlockHitResult) hitRes; var pos = bhr.getBlockPos(); - var bs = mc.level.getBlockState(pos); + var bs = level.getBlockState(pos); + + var lines = ScryingLensOverlayRegistry.getLines(bs, pos, player, level, bhr.getDirection(), lensHand); + + int totalHeight = 8; + List>> actualLines = Lists.newArrayList(); + + var window = mc.getWindow(); + var maxWidth = (int) (window.getGuiScaledWidth() / 2f * 0.8f); + + for (var pair : lines) { + totalHeight += mc.font.lineHeight + 6; + var text = pair.getSecond(); + var textLines = mc.font.getSplitter().splitLines(text, maxWidth, Style.EMPTY); + + actualLines.add(Pair.of(pair.getFirst(), textLines)); + + if (textLines.size() > 1) { + totalHeight += mc.font.lineHeight * (textLines.size() - 1); + } + } - var lines = ScryingLensOverlayRegistry.getLines(bs, pos, mc.player, mc.level, bhr.getDirection(), lensHand); if (!lines.isEmpty()) { - var window = mc.getWindow(); var x = window.getGuiScaledWidth() / 2f + 8f; - var y = window.getGuiScaledHeight() / 2f; + var y = window.getGuiScaledHeight() / 2f - totalHeight; ps.pushPose(); ps.translate(x, y, 0); - var maxWidth = (int) (window.getGuiScaledWidth() / 2f * 0.8f); - - for (var pair : lines) { + for (var pair : actualLines) { var stack = pair.getFirst(); if (!stack.isEmpty()) { // this draws centered in the Y ... @@ -195,15 +222,14 @@ public class HexAdditionalRenderers { float ty = 5; // but this draws where y=0 is the baseline var text = pair.getSecond(); - var textLines = mc.font.getSplitter().splitLines(text, maxWidth, Style.EMPTY); - for (var line : textLines) { + for (var line : text) { var actualLine = Language.getInstance().getVisualOrder(line); mc.font.drawShadow(ps, actualLine, tx, ty, 0xffffffff); - ps.translate(0, 9, 0); + ps.translate(0, mc.font.lineHeight, 0); } - if (textLines.isEmpty()) - ps.translate(0, 9, 0); + if (text.isEmpty()) + ps.translate(0, mc.font.lineHeight, 0); ps.translate(0, 6, 0); } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java b/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java index 6ad5e252..996547f9 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java +++ b/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java @@ -452,6 +452,8 @@ public class RegisterPatterns { OpRemove.INSTANCE); PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaeaqwded", HexDir.NORTH_WEST), prefix("slice"), OpSlice.INSTANCE); + PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaeaqw", HexDir.NORTH_WEST), prefix("modify_in_place"), + OpModifyInPlace.INSTANCE); } catch (PatternRegistry.RegisterPatternException exn) { exn.printStackTrace(); diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/akashic/OpAkashicRead.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/akashic/OpAkashicRead.kt index 29876367..c12655a5 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/akashic/OpAkashicRead.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/akashic/OpAkashicRead.kt @@ -4,11 +4,11 @@ import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked import at.petrak.hexcasting.api.spell.SpellDatum -import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicRecord -import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.Widget -import at.petrak.hexcasting.api.spell.mishaps.MishapNoAkashicRecord +import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.math.HexPattern +import at.petrak.hexcasting.api.spell.mishaps.MishapNoAkashicRecord +import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicRecord import net.minecraft.core.BlockPos import net.minecraft.world.phys.Vec3 diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt index aa79e33f..e29a59ac 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt @@ -7,18 +7,19 @@ import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingHarness import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect -import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.math.HexPattern +import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import net.minecraft.network.chat.TranslatableComponent object OpEval : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { val instrs: List> = stack.getChecked(stack.lastIndex) stack.removeLastOrNull() ctx.incDepth() val harness = CastingHarness(ctx) harness.stack.addAll(stack) + harness.localIota = local val sideEffects = mutableListOf() @@ -35,8 +36,7 @@ object OpEval : Operator { } harness.applyFunctionalData(res.newData) } - stack.addAll(harness.stack) - return OperationResult(harness.stack, sideEffects) + return OperationResult(harness.stack, harness.localIota, sideEffects) } } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt index 1c44f774..d48a9845 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEvalDelay.kt @@ -6,7 +6,7 @@ import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext object OpEvalDelay : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { - return OperationResult(stack, listOf()) + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { + return OperationResult(stack, local, listOf()) } } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt index 15d438cb..2dffda08 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt @@ -13,7 +13,7 @@ import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import net.minecraft.network.chat.TranslatableComponent object OpForEach : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.size < 2) throw MishapNotEnoughArgs(2, stack.size) @@ -25,11 +25,14 @@ object OpForEach : Operator { val out = mutableListOf>() val sideEffects = mutableListOf() + var localIota = local + for (subdatum in datums) { ctx.incDepth() val harness = CastingHarness(ctx) harness.stack.addAll(stack) harness.stack.add(subdatum) + harness.localIota = localIota for (pat in instrs) { val pattern = if (pat.payload is HexPattern) { pat.payload @@ -43,14 +46,15 @@ object OpForEach : Operator { val res = harness.getUpdate(pattern, ctx.world) sideEffects.addAll(res.sideEffects) if (res.sideEffects.any { it is OperatorSideEffect.DoMishap }) { - return OperationResult(harness.stack, sideEffects) + return OperationResult(harness.stack, harness.localIota, sideEffects) } harness.applyFunctionalData(res.newData) } out.addAll(harness.stack) + localIota = harness.localIota } stack.add(SpellDatum.make(out)) - return OperationResult(stack, sideEffects) + return OperationResult(stack, localIota, sideEffects) } } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt index b871f62d..7cef17ac 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpLastNToList.kt @@ -6,7 +6,6 @@ import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import net.minecraft.network.chat.TranslatableComponent @@ -14,7 +13,7 @@ import kotlin.math.abs import kotlin.math.roundToInt object OpLastNToList : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) throw MishapNotEnoughArgs(1, 0) val arg = stack.takeLast(1).getChecked(0) @@ -35,6 +34,6 @@ object OpLastNToList : Operator { } stack.addAll(spellListOf(output)) - return OperationResult(stack, listOf()) + return OperationResult(stack, local, listOf()) } } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpModifyInPlace.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpModifyInPlace.kt new file mode 100644 index 00000000..7b142d97 --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/lists/OpModifyInPlace.kt @@ -0,0 +1,29 @@ +package at.petrak.hexcasting.common.casting.operators.lists + +import at.petrak.hexcasting.api.spell.ConstManaOperator +import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked +import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.casting.CastingContext +import kotlin.math.roundToInt + +object OpModifyInPlace : ConstManaOperator { + override val argc = 3 + override fun execute(args: List>, ctx: CastingContext): List> { + val list = args.getChecked>>(0) + val index = args.getChecked(1).roundToInt() + val iota = args[2] + + if (0 > index || index > list.size) + return spellListOf(list) + + + val newList = list.toMutableList() + if (index == list.size) + newList.add(iota) + else + newList[index] = iota + + return spellListOf(newList) + } +} diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt new file mode 100644 index 00000000..5a0eb86f --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPeekLocal.kt @@ -0,0 +1,17 @@ +package at.petrak.hexcasting.common.casting.operators.local + +import at.petrak.hexcasting.api.spell.OperationResult +import at.petrak.hexcasting.api.spell.Operator +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.casting.CastingContext + +object OpPeekLocal : Operator { + override fun operate( + stack: MutableList>, + local: SpellDatum<*>, + ctx: CastingContext + ): OperationResult { + stack.add(local) + return OperationResult(stack, local, listOf()) + } +} diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt new file mode 100644 index 00000000..d97986f8 --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/local/OpPushLocal.kt @@ -0,0 +1,20 @@ +package at.petrak.hexcasting.common.casting.operators.local + +import at.petrak.hexcasting.api.spell.OperationResult +import at.petrak.hexcasting.api.spell.Operator +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.casting.CastingContext +import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs + +object OpPushLocal : Operator { + override fun operate( + stack: MutableList>, + local: SpellDatum<*>, + ctx: CastingContext + ): OperationResult { + if (stack.isEmpty()) + throw MishapNotEnoughArgs(1, 0) + val newLocal = stack.removeLast() + return OperationResult(stack, newLocal, listOf()) + } +} diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt index 9ce43330..c3babeca 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPrint.kt @@ -10,13 +10,13 @@ import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import net.minecraft.Util object OpPrint : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) { throw MishapNotEnoughArgs(1, 0) } val datum = stack[stack.lastIndex] return OperationResult( - stack, listOf( + stack, local, listOf( OperatorSideEffect.AttemptSpell(Spell(datum), false) ) ) diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpFlight.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpFlight.kt index f1ad8d0e..21f74d52 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpFlight.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpFlight.kt @@ -84,8 +84,13 @@ object OpFlight : SpellOperator { abilities.mayfly = false entity.onUpdateAbilities() } - } else - HexPlayerDataHelper.setFlight(entity, + } else { + if (!entity.abilities.mayfly) { + entity.abilities.mayfly = true + entity.onUpdateAbilities() + } + HexPlayerDataHelper.setFlight( + entity, FlightAbility( true, flightTime, @@ -94,6 +99,7 @@ object OpFlight : SpellOperator { flight.radius ) ) + } } } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt index d4377ba4..c4c74064 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpAlwinfyHasAscendedToABeingOfPureMath.kt @@ -17,7 +17,7 @@ import kotlin.math.roundToInt // "lehmer code" object OpAlwinfyHasAscendedToABeingOfPureMath : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) throw MishapNotEnoughArgs(1, 0) // todo: better message? @@ -56,6 +56,7 @@ object OpAlwinfyHasAscendedToABeingOfPureMath : Operator { return OperationResult( stack, + local, listOf(OperatorSideEffect.ConsumeMana(cost)) ) } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt index a305652b..b3ea4f63 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpFisherman.kt @@ -12,7 +12,7 @@ import kotlin.math.abs import kotlin.math.roundToInt object OpFisherman : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { if (stack.isEmpty()) throw MishapNotEnoughArgs(1, 0) val arg = stack.getChecked(stack.lastIndex) @@ -31,6 +31,6 @@ object OpFisherman : Operator { ) } - return OperationResult(stack, listOf()) + return OperationResult(stack, local, listOf()) } } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt index 0190db53..0bfc664f 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpStackSize.kt @@ -2,19 +2,12 @@ package at.petrak.hexcasting.common.casting.operators.stack import at.petrak.hexcasting.api.spell.OperationResult import at.petrak.hexcasting.api.spell.Operator -import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect -import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota -import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs -import net.minecraft.network.chat.TranslatableComponent -import kotlin.math.abs -import kotlin.math.roundToInt object OpStackSize : Operator { - override fun operate(stack: MutableList>, ctx: CastingContext): OperationResult { + override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { stack.add(SpellDatum.make(stack.size.toDouble())) - return OperationResult(stack, listOf()) + return OperationResult(stack, local, listOf()) } } diff --git a/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java b/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java index 0cbc8b59..f9084bc3 100644 --- a/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java +++ b/src/main/java/at/petrak/hexcasting/mixin/MixinVillager.java @@ -6,6 +6,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; // Prevents the villager from any of its brain goals @Mixin(Villager.class) @@ -17,4 +18,12 @@ public class MixinVillager { ci.cancel(); } } + + @Inject(method = "canBreed", at = @At("HEAD"), cancellable = true) + private void preventBreeding(CallbackInfoReturnable cir) { + var self = (Villager) (Object) this; + if (Brainsweeping.isBrainswept(self)) { + cir.setReturnValue(false); + } + } } diff --git a/src/main/resources/assets/hexcasting/lang/en_us.json b/src/main/resources/assets/hexcasting/lang/en_us.json index 9775adeb..42dc69e7 100644 --- a/src/main/resources/assets/hexcasting/lang/en_us.json +++ b/src/main/resources/assets/hexcasting/lang/en_us.json @@ -197,6 +197,7 @@ "hexcasting.spell.hexcasting:index_of": "Locator's Distillation", "hexcasting.spell.hexcasting:list_remove": "Excisor's Distillation", "hexcasting.spell.hexcasting:slice": "Selection Exaltation", + "hexcasting.spell.hexcasting:modify_in_place": "Surgeon's Exaltation", "hexcasting.spell.hexcasting:get_entity": "Entity Purification", "hexcasting.spell.hexcasting:get_entity/animal": "Entity Prfn.: Animal", "hexcasting.spell.hexcasting:get_entity/monster": "Entity Prfn.: Monster", @@ -306,6 +307,8 @@ "hexcasting.spell.hexcasting:escape": "Consideration", "hexcasting.spell.hexcasting:eval": "Hermes' Gambit", "hexcasting.spell.hexcasting:eval/delay": "Secret Gambit!", + "hexcasting.spell.hexcasting:read_local": "Muginn's Reflection", + "hexcasting.spell.hexcasting:write_local": "Huginn's Gambit", "hexcasting.spell.hexcasting:read": "Scribe's Reflection", "hexcasting.spell.hexcasting:write": "Scribe's Gambit", "hexcasting.spell.hexcasting:readable": "Auditor's Reflection", @@ -332,7 +335,6 @@ "hexcasting.spell.unknown": "Special Handler", "hexcasting.mishap.invalid_pattern": "That pattern isn't associated with any action", - "hexcasting.mishap.invalid_spell_datum_type": "Tried to use a value of invalid type as a SpellDatum: %s (class %s). This is a bug in the mod.", "hexcasting.mishap.invalid_value": "%s expected %s at index %s of the stack, but got %s", "hexcasting.mishap.invalid_value.class.double": "a number", "hexcasting.mishap.invalid_value.class.vector": "a vector", @@ -390,6 +392,8 @@ "hexcasting.mishap.divide_by_zero.cos": "the cosine of %s", "hexcasting.mishap.no_akashic_record": "No Akashic Record at %s", "hexcasting.mishap.disallowed": "%s has been disallowed by the server admins", + "hexcasting.mishap.invalid_spell_datum_type": "Tried to use a value of invalid type as a SpellDatum: %s (class %s). This is a bug in the mod.", + "hexcasting.mishap.unknown": "%s threw an exception (%s). This is a bug in the mod.", "hexcasting.landing": "I seem to have discovered a new method of magical arts, in which one draws patterns strange and wild onto a hexagonal grid. It fascinates me. I've decided to start a journal of my thoughts and findings.$(br2)$(l:https://discord.gg/4xxHGYteWk)Discord Server Link/$", @@ -499,8 +503,8 @@ "hexcasting.page.mishaps.true_name": "I attempted to $(l:patterns/readwrite#hexcasting:write)$(action)save a reference/$ to another player to a permanent medium.$(br2)Causes black sparks, and robs me of my sight for approximately one minute.", "hexcasting.page.mishaps.disabled.title": "Disallowed Action", "hexcasting.page.mishaps.disabled": "I tried to cast an action that has been disallowed by a server administrator.$(br2)Causes black sparks.", - "hexcasting.page.mishaps.invalid_iota.title": "Invalid Iota Type", - "hexcasting.page.mishaps.invalid_iota": "A bug in the mod caused an iota of an invalid type. $(l:https://https://github.com/gamma-delta/HexMod/issues)Please open a bug report!/$$(br2)Causes black sparks.", + "hexcasting.page.mishaps.other.title": "Catastrophic Failure", + "hexcasting.page.mishaps.other": "A bug in the mod caused an iota of an invalid type or otherwise caused the spell to crash. $(l:https://https://github.com/gamma-delta/HexMod/issues)Please open a bug report!/$$(br2)Causes black sparks.", "hexcasting.entry.stack": "Stacks", "hexcasting.page.stack.1": "A $(thing)Stack/$, also known as a \"LIFO\", is a concept borrowed from computer science. In short, it's a collection of things designed so that you can only interact with the most recently used thing.$(br2)Think of a stack of plates, where new plates are added to the top: if you want to interact with a plate halfway down the stack, you have to remove the plates above it in order to get ahold of it.", @@ -796,6 +800,7 @@ "hexcasting.page.lists.reverse_list": "Reverse the list at the top of the stack.", "hexcasting.page.lists.index_of": "Remove the iota at the top of the stack, then replace the list at the top with the first index of that iota within the list (starting from 0). Replaces the list with -1 if the iota doesn't exist in the list.", "hexcasting.page.lists.list_remove": "Remove the number at the top of the stack, then remove the nth element of the list at the top of the stack (where n is the number you removed).", + "hexcasting.page.lists.modify_in_place": "Remove the top iota of the stack and the number at the top, then set the nth element of the list at the top of the stack to that iota (where n is the number you removed). Does nothing if the number is out of bounds.", "hexcasting.entry.patterns_as_iotas": "Patterns as Iotas", "hexcasting.page.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.", diff --git a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/casting/mishaps.json b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/casting/mishaps.json index 4970170b..a5b59840 100644 --- a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/casting/mishaps.json +++ b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/casting/mishaps.json @@ -85,8 +85,8 @@ }, { "type": "patchouli:text", - "title": "hexcasting.page.mishaps.invalid_iota.title", - "text": "hexcasting.page.mishaps.invalid_iota" + "title": "hexcasting.page.mishaps.other.title", + "text": "hexcasting.page.mishaps.other" } ] } diff --git a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json index 7410770f..b61edaf1 100644 --- a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json +++ b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/lists.json @@ -85,6 +85,14 @@ "input": "list, num", "output": "list", "text": "hexcasting.page.lists.list_remove" + }, + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:modify_in_place", + "anchor": "hexcasting:modify_in_place", + "input": "list, num, any", + "output": "list", + "text": "hexcasting.page.lists.modify_in_place" } ] }