add Huginn's Gambit, Muninn's Reflection, and Surgeon's Exaltation

no patterns for huginn and muninn (yet)
This commit is contained in:
yrsegal@gmail.com 2022-05-06 22:16:28 -04:00
parent 6698e8096e
commit fe7051301b
28 changed files with 290 additions and 75 deletions

View file

@ -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));

View file

@ -14,7 +14,7 @@ interface ConstManaOperator : Operator {
fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>>
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, 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>(OperatorSideEffect.ConsumeMana(this.manaCost))
return OperationResult(stack, sideEffects)
return OperationResult(stack, local, sideEffects)
}
}

View file

@ -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<SpellDatum<*>>, val sideEffects: List<OperatorSideEffect>)
data class OperationResult(val newStack: List<SpellDatum<*>>, val newLocalIota: SpellDatum<*>, val sideEffects: List<OperatorSideEffect>)

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): OperationResult
fun operate(stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult
/**
* Do you need to be enlightened to use this operator?

View file

@ -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<T : Any> 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<SpellDatum<*>>(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<T : Any> 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))

View file

@ -16,12 +16,12 @@ interface SpellOperator : Operator {
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>?
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, 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)
}
}

View file

@ -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<SpellDatum<*>>,
var localIota: SpellDatum<*>,
var parenCount: Int,
var parenthesized: List<HexPattern>,
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<SpellDatum<*>>()
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<HexPattern>()
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)
}

View file

@ -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<SpellDatum<*>>) {
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("unknown", actionName(errorCtx.action), exception)
}

View file

@ -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

View file

@ -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<Pair<ItemStack, List<FormattedText>>> actualLines = Lists.newArrayList();
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;
ps.pushPose();
ps.translate(x, y, 0);
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);
}
}
if (!lines.isEmpty()) {
var x = window.getGuiScaledWidth() / 2f + 8f;
var y = window.getGuiScaledHeight() / 2f - totalHeight;
ps.pushPose();
ps.translate(x, y, 0);
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);
}

View file

@ -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();

View file

@ -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

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
val instrs: List<SpellDatum<*>> = stack.getChecked(stack.lastIndex)
stack.removeLastOrNull()
ctx.incDepth()
val harness = CastingHarness(ctx)
harness.stack.addAll(stack)
harness.localIota = local
val sideEffects = mutableListOf<OperatorSideEffect>()
@ -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)
}
}

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): OperationResult {
return OperationResult(stack, listOf())
override fun operate(stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
return OperationResult(stack, local, listOf())
}
}

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
if (stack.size < 2)
throw MishapNotEnoughArgs(2, stack.size)
@ -25,11 +25,14 @@ object OpForEach : Operator {
val out = mutableListOf<SpellDatum<*>>()
val sideEffects = mutableListOf<OperatorSideEffect>()
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)
}
}

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
if (stack.isEmpty())
throw MishapNotEnoughArgs(1, 0)
val arg = stack.takeLast(1).getChecked<Double>(0)
@ -35,6 +34,6 @@ object OpLastNToList : Operator {
}
stack.addAll(spellListOf(output))
return OperationResult(stack, listOf())
return OperationResult(stack, local, listOf())
}
}

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val list = args.getChecked<List<SpellDatum<*>>>(0)
val index = args.getChecked<Double>(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)
}
}

View file

@ -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<SpellDatum<*>>,
local: SpellDatum<*>,
ctx: CastingContext
): OperationResult {
stack.add(local)
return OperationResult(stack, local, listOf())
}
}

View file

@ -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<SpellDatum<*>>,
local: SpellDatum<*>,
ctx: CastingContext
): OperationResult {
if (stack.isEmpty())
throw MishapNotEnoughArgs(1, 0)
val newLocal = stack.removeLast()
return OperationResult(stack, newLocal, listOf())
}
}

View file

@ -10,13 +10,13 @@ import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
import net.minecraft.Util
object OpPrint : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, 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)
)
)

View file

@ -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,
@ -95,6 +100,7 @@ object OpFlight : SpellOperator {
)
)
}
}
}
}

View file

@ -17,7 +17,7 @@ import kotlin.math.roundToInt
// "lehmer code"
object OpAlwinfyHasAscendedToABeingOfPureMath : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, 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))
)
}

View file

@ -12,7 +12,7 @@ import kotlin.math.abs
import kotlin.math.roundToInt
object OpFisherman : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
if (stack.isEmpty())
throw MishapNotEnoughArgs(1, 0)
val arg = stack.getChecked<Double>(stack.lastIndex)
@ -31,6 +31,6 @@ object OpFisherman : Operator {
)
}
return OperationResult(stack, listOf())
return OperationResult(stack, local, listOf())
}
}

View file

@ -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<SpellDatum<*>>, ctx: CastingContext): OperationResult {
override fun operate(stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult {
stack.add(SpellDatum.make(stack.size.toDouble()))
return OperationResult(stack, listOf())
return OperationResult(stack, local, listOf())
}
}

View file

@ -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<Boolean> cir) {
var self = (Villager) (Object) this;
if (Brainsweeping.isBrainswept(self)) {
cir.setReturnValue(false);
}
}
}

View file

@ -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.",

View file

@ -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"
}
]
}

View file

@ -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"
}
]
}