diff --git a/Common/src/main/java/at/petrak/hexcasting/api/addldata/ADIotaHolder.java b/Common/src/main/java/at/petrak/hexcasting/api/addldata/ADIotaHolder.java index 45e3e404f2..7b8fcc1c95 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/addldata/ADIotaHolder.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/addldata/ADIotaHolder.java @@ -29,4 +29,9 @@ default Iota emptyIota() { * @return if the writing succeeded/would succeed */ boolean writeIota(@Nullable Iota iota, boolean simulate); + + /** + * @return whether it is possible to write to this IotaHolder + */ + boolean writeable(); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/addldata/ItemDelegatingEntityIotaHolder.java b/Common/src/main/java/at/petrak/hexcasting/api/addldata/ItemDelegatingEntityIotaHolder.java index 390ce0dc9f..5af67a99ab 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/addldata/ItemDelegatingEntityIotaHolder.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/addldata/ItemDelegatingEntityIotaHolder.java @@ -29,6 +29,12 @@ public ItemDelegatingEntityIotaHolder(Supplier stackSupplier, Consume return delegate == null ? null : delegate.readIotaTag(); } + @Override + public boolean writeable() { + var delegate = IXplatAbstractions.INSTANCE.findDataHolder(this.stackSupplier.get()); + return delegate != null && delegate.writeable(); + } + @Override public boolean writeIota(@Nullable Iota datum, boolean simulate) { var stacc = this.stackSupplier.get(); diff --git a/Common/src/main/java/at/petrak/hexcasting/api/advancements/MinMaxLongs.java b/Common/src/main/java/at/petrak/hexcasting/api/advancements/MinMaxLongs.java new file mode 100644 index 0000000000..0be502c86e --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/advancements/MinMaxLongs.java @@ -0,0 +1,85 @@ +package at.petrak.hexcasting.api.advancements; + +import com.google.gson.JsonElement; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.BuiltInExceptionProvider; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.advancements.critereon.MinMaxBounds; +import net.minecraft.util.GsonHelper; + +import javax.annotation.Nullable; +import java.util.Objects; +import java.util.function.Function; + +public class MinMaxLongs extends MinMaxBounds { + public static final MinMaxLongs ANY = new MinMaxLongs(null, null); + @Nullable + private final Long minSq; + @Nullable + private final Long maxSq; + + private static MinMaxLongs create(StringReader reader, @Nullable Long min, @Nullable Long max) throws CommandSyntaxException { + if (min != null && max != null && min > max) { + throw ERROR_SWAPPED.createWithContext(reader); + } else { + return new MinMaxLongs(min, max); + } + } + + @Nullable + private static Long squareOpt(@Nullable Long l) { + return l == null ? null : l * l; + } + + private MinMaxLongs(@Nullable Long min, @Nullable Long max) { + super(min, max); + this.minSq = squareOpt(min); + this.maxSq = squareOpt(max); + } + + public static MinMaxLongs exactly(long l) { + return new MinMaxLongs(l, l); + } + + public static MinMaxLongs between(long min, long max) { + return new MinMaxLongs(min, max); + } + + public static MinMaxLongs atLeast(long min) { + return new MinMaxLongs(min, null); + } + + public static MinMaxLongs atMost(long max) { + return new MinMaxLongs(null, max); + } + + public boolean matches(long l) { + if (this.min != null && this.min > l) { + return false; + } else { + return this.max == null || this.max >= l; + } + } + + public boolean matchesSqr(long l) { + if (this.minSq != null && this.minSq > l) { + return false; + } else { + return this.maxSq == null || this.maxSq >= l; + } + } + + public static MinMaxLongs fromJson(@Nullable JsonElement json) { + return fromJson(json, ANY, GsonHelper::convertToLong, MinMaxLongs::new); + } + + public static MinMaxLongs fromReader(StringReader reader) throws CommandSyntaxException { + return fromReader(reader, (l) -> l); + } + + public static MinMaxLongs fromReader(StringReader reader, Function map) throws CommandSyntaxException { + BuiltInExceptionProvider builtInExceptions = CommandSyntaxException.BUILT_IN_EXCEPTIONS; + Objects.requireNonNull(builtInExceptions); + return fromReader(reader, MinMaxLongs::create, Long::parseLong, builtInExceptions::readerInvalidInt, map); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java b/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java index aa12d472cf..d610807f59 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/advancements/SpendMediaTrigger.java @@ -20,20 +20,20 @@ public ResourceLocation getId() { protected Instance createInstance(JsonObject json, ContextAwarePredicate predicate, DeserializationContext context) { return new Instance(predicate, - MinMaxBounds.Ints.fromJson(json.get(TAG_MEDIA_SPENT)), - MinMaxBounds.Ints.fromJson(json.get(TAG_MEDIA_WASTED))); + MinMaxLongs.fromJson(json.get(TAG_MEDIA_SPENT)), + MinMaxLongs.fromJson(json.get(TAG_MEDIA_WASTED))); } - public void trigger(ServerPlayer player, int mediaSpent, int mediaWasted) { + public void trigger(ServerPlayer player, long mediaSpent, long mediaWasted) { super.trigger(player, inst -> inst.test(mediaSpent, mediaWasted)); } public static class Instance extends AbstractCriterionTriggerInstance { - protected final MinMaxBounds.Ints mediaSpent; - protected final MinMaxBounds.Ints mediaWasted; + protected final MinMaxLongs mediaSpent; + protected final MinMaxLongs mediaWasted; - public Instance(ContextAwarePredicate predicate, MinMaxBounds.Ints mediaSpent, - MinMaxBounds.Ints mediaWasted) { + public Instance(ContextAwarePredicate predicate, MinMaxLongs mediaSpent, + MinMaxLongs mediaWasted) { super(SpendMediaTrigger.ID, predicate); this.mediaSpent = mediaSpent; this.mediaWasted = mediaWasted; @@ -56,7 +56,7 @@ public JsonObject serializeToJson(SerializationContext ctx) { return json; } - private boolean test(int mediaSpentIn, int mediaWastedIn) { + private boolean test(long mediaSpentIn, long mediaWastedIn) { return this.mediaSpent.matches(mediaSpentIn) && this.mediaWasted.matches(mediaWastedIn); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java index 7918d90812..f95fa84f01 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/circles/CircleExecutionState.java @@ -237,6 +237,9 @@ public boolean tick(BlockEntityAbstractImpetus impetus) { var ctrl = executor.acceptControlFlow(this.currentImage, env, this.enteredFrom, this.currentPos, executorBlockState, world); + if (env.getImpetus() == null) + return false; //the impetus got removed during the cast and no longer exists in the world. stop casting + if (ctrl instanceof ICircleComponent.ControlFlow.Stop) { // acceptControlFlow should have already posted the error halt = true; diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java index d1f447cf85..f03011ad98 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironment.java @@ -2,6 +2,7 @@ import at.petrak.hexcasting.api.casting.ParticleSpray; import at.petrak.hexcasting.api.casting.PatternShapeMatch; +import at.petrak.hexcasting.api.casting.eval.vm.CastingImage; import at.petrak.hexcasting.api.casting.mishaps.Mishap; import at.petrak.hexcasting.api.casting.mishaps.MishapBadLocation; import at.petrak.hexcasting.api.casting.mishaps.MishapDisallowedSpell; @@ -66,6 +67,8 @@ public final void triggerCreateEvent() { protected Map, @NotNull CastingEnvironmentComponent> componentMap = new HashMap<>(); private final List postExecutions = new ArrayList<>(); + + private final List postCasts = new ArrayList<>(); private final List preMediaExtract = new ArrayList<>(); private final List postMediaExtract = new ArrayList<>(); @@ -113,6 +116,8 @@ public void addExtension(@NotNull T exte componentMap.put(extension.getKey(), extension); if (extension instanceof PostExecution postExecution) postExecutions.add(postExecution); + if (extension instanceof PostCast postCast) + postCasts.add(postCast); if (extension instanceof ExtractMedia extractMedia) if (extension instanceof ExtractMedia.Pre pre) { preMediaExtract.add(pre); @@ -132,6 +137,8 @@ public void removeExtension(@NotNull CastingEnvironmentComponent.Key key) { if (extension instanceof PostExecution postExecution) postExecutions.remove(postExecution); + if (extension instanceof PostCast postCast) + postCasts.remove(postCast); if (extension instanceof ExtractMedia extractMedia) if (extension instanceof ExtractMedia.Pre pre) { preMediaExtract.remove(pre); @@ -188,6 +195,14 @@ public void postExecution(CastResult result) { postExecutionComponent.onPostExecution(result); } + /** + * Do things after the whole cast is finished (i.e. every pattern to be executed has been executed). + */ + public void postCast(CastingImage image) { + for (var postCastComponent : postCasts) + postCastComponent.onPostCast(image); + } + public abstract Vec3 mishapSprayPos(); /** diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironmentComponent.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironmentComponent.java index c5aac3eacc..faee1de0ba 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironmentComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/CastingEnvironmentComponent.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.api.casting.eval; +import at.petrak.hexcasting.api.casting.eval.vm.CastingImage; import net.minecraft.core.BlockPos; import net.minecraft.world.phys.Vec3; @@ -15,6 +16,13 @@ interface PostExecution extends CastingEnvironmentComponent { void onPostExecution(CastResult result); } + interface PostCast extends CastingEnvironmentComponent { + /** + * Do things after the whole cast is finished (i.e. every pattern to be executed has been executed). + */ + void onPostCast(CastingImage image); + } + interface ExtractMedia extends CastingEnvironmentComponent { /** * Receives the cost that is being extracted, should return the diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java index 9932ba7b3c..c137930071 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PlayerBasedCastEnv.java @@ -223,6 +223,11 @@ protected long extractMediaFromInventory(long costLeft, boolean allowOvercast) { } this.caster.awardStat(HexStatistics.MEDIA_USED, (int) (startCost - costLeft)); + HexAdvancementTriggers.SPEND_MEDIA_TRIGGER.trigger( + this.caster, + startCost - costLeft, + costLeft < 0 ? -costLeft : 0 + ); return costLeft; } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/StaffCastEnv.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/StaffCastEnv.java index 9b63ece8de..6fbfa7bcf6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/StaffCastEnv.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/StaffCastEnv.java @@ -5,8 +5,10 @@ import at.petrak.hexcasting.api.casting.eval.CastResult; import at.petrak.hexcasting.api.casting.eval.ExecutionClientView; import at.petrak.hexcasting.api.casting.eval.ResolvedPattern; +import at.petrak.hexcasting.api.casting.eval.vm.CastingImage; import at.petrak.hexcasting.api.casting.iota.PatternIota; import at.petrak.hexcasting.api.casting.math.HexCoord; +import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.mod.HexStatistics; import at.petrak.hexcasting.api.pigment.FrozenPigment; import at.petrak.hexcasting.common.msgs.*; @@ -19,10 +21,14 @@ import java.util.HashSet; import java.util.List; +import java.util.Set; public class StaffCastEnv extends PlayerBasedCastEnv { private final InteractionHand castingHand; + private final Set castPatterns = new HashSet<>(); + private int soundsPlayed = 0; + public StaffCastEnv(ServerPlayer caster, InteractionHand castingHand) { super(caster, castingHand); @@ -35,22 +41,33 @@ public void postExecution(CastResult result) { super.postExecution(result); if (result.component1() instanceof PatternIota patternIota) { - var packet = new MsgNewSpiralPatternsS2C( - this.caster.getUUID(), List.of(patternIota.getPattern()), Integer.MAX_VALUE - ); - IXplatAbstractions.INSTANCE.sendPacketToPlayer(this.caster, packet); - IXplatAbstractions.INSTANCE.sendPacketTracking(this.caster, packet); + castPatterns.add(patternIota.getPattern()); } // we always want to play this sound one at a time var sound = result.getSound().sound(); - if (sound != null) { + if (soundsPlayed < 100 && sound != null) { // TODO: Make configurable var soundPos = this.caster.position(); this.world.playSound(null, soundPos.x, soundPos.y, soundPos.z, sound, SoundSource.PLAYERS, 1f, 1f); + soundsPlayed++; } } + @Override + public void postCast(CastingImage image) { + super.postCast(image); + + var packet = new MsgNewSpiralPatternsS2C( + this.caster.getUUID(), castPatterns.stream().toList(), Integer.MAX_VALUE + ); + IXplatAbstractions.INSTANCE.sendPacketToPlayer(this.caster, packet); + IXplatAbstractions.INSTANCE.sendPacketTracking(this.caster, packet); + + castPatterns.clear(); + soundsPlayed = 0; + } + @Override public long extractMediaEnvironment(long cost) { if (this.caster.isCreative()) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index 8cbd8d51e6..849a43ba20 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -76,6 +76,8 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { val (stackDescs, ravenmind) = generateDescs() val isStackClear = image.stack.isEmpty() && image.parenCount == 0 && !image.escapeNext && ravenmind == null + + this.env.postCast(image) return ExecutionClientView(isStackClear, lastResolutionType, stackDescs, ravenmind) } @@ -161,7 +163,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { */ @Throws(MishapTooManyCloseParens::class) private fun handleParentheses(iota: Iota): Pair? { - val sig = (iota as? PatternIota)?.pattern?.anglesSignature() + val sig = (iota as? PatternIota)?.pattern?.angles var displayDepth = this.image.parenCount @@ -176,13 +178,13 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { } else { when (sig) { - SpecialPatterns.CONSIDERATION.anglesSignature() -> { + SpecialPatterns.CONSIDERATION.angles -> { this.image.copy( escapeNext = true, ) to ResolvedPatternType.EVALUATED } - SpecialPatterns.EVANITION.anglesSignature() -> { + SpecialPatterns.EVANITION.angles -> { val newParens = this.image.parenthesized.toMutableList() val last = newParens.removeLastOrNull() val newParenCount = this.image.parenCount + if (last == null || last.escaped || last.iota !is PatternIota) 0 else when (last.iota.pattern) { @@ -193,7 +195,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { this.image.copy(parenthesized = newParens, parenCount = newParenCount) to if (last == null) ResolvedPatternType.ERRORED else ResolvedPatternType.UNDONE } - SpecialPatterns.INTROSPECTION.anglesSignature() -> { + SpecialPatterns.INTROSPECTION.angles -> { // we have escaped the parens onto the stack; we just also record our count. val newParens = this.image.parenthesized.toMutableList() newParens.add(ParenthesizedIota(iota, false)) @@ -203,7 +205,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { ) to if (this.image.parenCount == 0) ResolvedPatternType.EVALUATED else ResolvedPatternType.ESCAPED } - SpecialPatterns.RETROSPECTION.anglesSignature() -> { + SpecialPatterns.RETROSPECTION.angles -> { val newParenCount = this.image.parenCount - 1 displayDepth-- if (newParenCount == 0) { @@ -246,19 +248,19 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { ) to ResolvedPatternType.ESCAPED } else { when (sig) { - SpecialPatterns.CONSIDERATION.anglesSignature() -> { + SpecialPatterns.CONSIDERATION.angles -> { this.image.copy( escapeNext = true ) to ResolvedPatternType.EVALUATED } - SpecialPatterns.INTROSPECTION.anglesSignature() -> { + SpecialPatterns.INTROSPECTION.angles -> { this.image.copy( parenCount = this.image.parenCount + 1 ) to ResolvedPatternType.EVALUATED } - SpecialPatterns.RETROSPECTION.anglesSignature() -> { + SpecialPatterns.RETROSPECTION.angles -> { throw MishapTooManyCloseParens() } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java index 7fae3f5e79..b86e8541ce 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Objects; +import java.util.function.Supplier; import static at.petrak.hexcasting.api.utils.HexUtils.isOfTag; @@ -58,7 +59,7 @@ public boolean isTruthy() { public boolean toleratesOther(Iota that) { return typesMatch(this, that) && that instanceof PatternIota piota - && this.getPattern().anglesSignature().equals(piota.getPattern().anglesSignature()); + && this.getPattern().getAngles().equals(piota.getPattern().getAngles()); } @Override @@ -68,7 +69,7 @@ public boolean toleratesOther(Iota that) { @Override public @NotNull CastResult execute(CastingVM vm, ServerLevel world, SpellContinuation continuation) { - @Nullable Component castedName = null; + Supplier<@Nullable Component> castedName = () -> null; try { var lookup = PatternRegistryManifest.matchPattern(this.getPattern(), vm.getEnv(), false); vm.getEnv().precheckAction(lookup); @@ -86,7 +87,7 @@ public boolean toleratesOther(Iota that) { var reqsEnlightenment = isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), key, HexTags.Actions.REQUIRES_ENLIGHTENMENT); - castedName = HexAPI.instance().getActionI18n(key, reqsEnlightenment); + castedName = () -> HexAPI.instance().getActionI18n(key, reqsEnlightenment); action = Objects.requireNonNull(IXplatAbstractions.INSTANCE.getActionRegistry().get(key)).action(); if (reqsEnlightenment && !vm.getEnv().isEnlightened()) { @@ -94,7 +95,7 @@ public boolean toleratesOther(Iota that) { throw new MishapUnenlightened(); } } else if (lookup instanceof PatternShapeMatch.Special special) { - castedName = special.handler.getName(); + castedName = special.handler::getName; action = special.handler.act(); } else if (lookup instanceof PatternShapeMatch.Nothing) { throw new MishapInvalidPattern(); @@ -128,7 +129,7 @@ public boolean toleratesOther(Iota that) { this, continuation, null, - List.of(new OperatorSideEffect.DoMishap(mishap, new Mishap.Context(this.getPattern(), castedName))), + List.of(new OperatorSideEffect.DoMishap(mishap, new Mishap.Context(this.getPattern(), castedName.get()))), mishap.resolutionType(vm.getEnv()), HexEvalSounds.MISHAP); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt index c55cbb23d9..001cfdeab4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/math/HexPattern.kt @@ -13,7 +13,7 @@ import net.minecraft.world.phys.Vec2 /** * Sequence of angles to define a pattern traced. */ -data class HexPattern(public val startDir: HexDir, public val angles: MutableList = arrayListOf()) { +data class HexPattern(val startDir: HexDir, val angles: MutableList = arrayListOf()) { /** * @return True if it successfully appended, false if not. */ @@ -115,7 +115,7 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis fun toLines(hexSize: Float, origin: Vec2): List = this.positions().map { coordToPx(it, hexSize, origin) } - fun sigsEqual(that: HexPattern) = this.anglesSignature() == that.anglesSignature() + fun sigsEqual(that: HexPattern) = this.angles == that.angles override fun toString(): String = buildString { append("HexPattern[") diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadOffhandItem.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadOffhandItem.kt index 1de584503c..d35104dab4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadOffhandItem.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapBadOffhandItem.kt @@ -9,7 +9,7 @@ import net.minecraft.world.InteractionHand import net.minecraft.world.item.DyeColor import net.minecraft.world.item.ItemStack -class MishapBadOffhandItem(val item: ItemStack, val hand: InteractionHand?, val wanted: Component) : Mishap() { +class MishapBadOffhandItem(val item: ItemStack?, val wanted: Component) : Mishap() { override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment = dyeColor(DyeColor.BROWN) @@ -17,15 +17,15 @@ class MishapBadOffhandItem(val item: ItemStack, val hand: InteractionHand?, val env.mishapEnvironment.dropHeldItems() } - override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = if (item.isEmpty) - error("no_item.offhand", wanted) - else + override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = if (item?.isEmpty == false) error("bad_item.offhand", wanted, item.count, item.displayName) + else + error("no_item.offhand", wanted) companion object { @JvmStatic - fun of(item: ItemStack, hand: InteractionHand?, stub: String, vararg args: Any): MishapBadOffhandItem { - return MishapBadOffhandItem(item, hand, "hexcasting.mishap.bad_item.$stub".asTranslatedComponent(*args)) + fun of(item: ItemStack?, stub: String, vararg args: Any): MishapBadOffhandItem { + return MishapBadOffhandItem(item, "hexcasting.mishap.bad_item.$stub".asTranslatedComponent(*args)) } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java b/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java index 46f4074fc8..c312383129 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java @@ -54,8 +54,6 @@ default Iota readIota(ItemStack stack, ServerLevel world) { /** * What is this considered to contain when nothing can be read? - *

- * TODO i'm not sure what this isCastable for */ @Nullable default Iota emptyIota(ItemStack stack) { @@ -87,6 +85,11 @@ default int getColor(ItemStack stack) { return IotaType.getColor(tag); } + /** + * @return whether it is possible to write to this IotaHolder + */ + boolean writeable(ItemStack stack); + /** * Write {@code null} to indicate erasing */ diff --git a/Common/src/main/java/at/petrak/hexcasting/api/item/MediaHolderItem.java b/Common/src/main/java/at/petrak/hexcasting/api/item/MediaHolderItem.java index 51dad5b8ff..a4aa3cfc0a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/item/MediaHolderItem.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/item/MediaHolderItem.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.api.item; +import at.petrak.hexcasting.api.addldata.ADMediaHolder; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.ApiStatus; @@ -59,4 +60,8 @@ default long insertMedia(ItemStack stack, long amount, boolean simulate) { } return inserting; } + + default int getConsumptionPriority(ItemStack stack) { + return ADMediaHolder.BATTERY_PRIORITY; + } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpRead.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpRead.kt index fceb1a1af1..51791b6d26 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpRead.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpRead.kt @@ -3,7 +3,6 @@ package at.petrak.hexcasting.common.casting.actions.rw import at.petrak.hexcasting.api.casting.castables.ConstMediaAction import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.api.casting.iota.NullIota import at.petrak.hexcasting.api.casting.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.xplat.IXplatAbstractions @@ -11,17 +10,23 @@ object OpRead : ConstMediaAction { override val argc = 0 override fun execute(args: List, env: CastingEnvironment): List { - val (handStack, hand) = env.getHeldItemToOperateOn { + val (handStack) = env.getHeldItemToOperateOn { val dataHolder = IXplatAbstractions.INSTANCE.findDataHolder(it) dataHolder != null && (dataHolder.readIota(env.world) != null || dataHolder.emptyIota() != null) - } ?: return listOf(NullIota()) + } + // If there are no data holders that are readable, find a data holder that isn't readable + // so that the error message is more helpful. + ?: env.getHeldItemToOperateOn { + val dataHolder = IXplatAbstractions.INSTANCE.findDataHolder(it) + dataHolder != null + } ?: throw MishapBadOffhandItem.of(null, "iota.read") val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack) - ?: throw MishapBadOffhandItem.of(handStack, hand, "iota.read") + ?: throw MishapBadOffhandItem.of(handStack, "iota.read") val datum = datumHolder.readIota(env.world) ?: datumHolder.emptyIota() - ?: throw MishapBadOffhandItem.of(handStack, hand, "iota.read") + ?: throw MishapBadOffhandItem.of(handStack, "iota.read") return listOf(datum) } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt index 8b4cee8524..d368b9d87b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt @@ -17,9 +17,9 @@ object OpReadable : ConstMediaAction { val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack) ?: return false.asActionResult + // If the datum contains no iota, return whether it has a default empty iota. datumHolder.readIota(env.world) - ?: datumHolder.emptyIota() - ?: return false.asActionResult + ?: return (datumHolder.emptyIota() != null).asActionResult return true.asActionResult } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt index 6912f7f692..f0a3d0da10 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt @@ -4,7 +4,6 @@ import at.petrak.hexcasting.api.casting.asActionResult import at.petrak.hexcasting.api.casting.castables.ConstMediaAction import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.api.casting.iota.NullIota import at.petrak.hexcasting.xplat.IXplatAbstractions object OpWritable : ConstMediaAction { @@ -18,7 +17,7 @@ object OpWritable : ConstMediaAction { } ?: return false.asActionResult val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack) ?: return false.asActionResult - val success = datumHolder.writeIota(NullIota(), true) + val success = datumHolder.writeable() return success.asActionResult } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWrite.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWrite.kt index 211f74a30f..317dbc0453 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWrite.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWrite.kt @@ -9,7 +9,6 @@ import at.petrak.hexcasting.api.casting.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.api.casting.mishaps.MishapOthersName import at.petrak.hexcasting.xplat.IXplatAbstractions import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.item.ItemStack // we make this a spell cause imo it's a little ... anticlimactic for it to just make no noise object OpWrite : SpellAction { @@ -20,17 +19,23 @@ object OpWrite : SpellAction { ): SpellAction.Result { val datum = args[0] - val (handStack, hand) = env.getHeldItemToOperateOn { + val (handStack) = env.getHeldItemToOperateOn { val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(it) datumHolder != null && datumHolder.writeIota(datum, true) - } ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), null, "iota.write") // TODO: hack + } + // If there are no data holders that are writeable, find a data holder that isn't writeable + // so that the error message is more helpful. + ?: env.getHeldItemToOperateOn { + val dataHolder = IXplatAbstractions.INSTANCE.findDataHolder(it) + dataHolder != null + } ?: throw MishapBadOffhandItem.of(null, "iota.write") val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack) - ?: throw MishapBadOffhandItem.of(handStack, hand, "iota.write") + ?: throw MishapBadOffhandItem.of(handStack, "iota.write") if (!datumHolder.writeIota(datum, true)) - throw MishapBadOffhandItem.of(handStack, hand, "iota.readonly", datum.display()) + throw MishapBadOffhandItem.of(handStack, "iota.readonly", datum.display()) val trueName = MishapOthersName.getTrueNameFromDatum(datum, env.castingEntity as? ServerPlayer) if (trueName != null) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBreakBlock.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBreakBlock.kt index 93d1301977..6031adb0b7 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBreakBlock.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpBreakBlock.kt @@ -10,6 +10,7 @@ import at.petrak.hexcasting.api.misc.MediaConstants import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.xplat.IXplatAbstractions import net.minecraft.core.BlockPos +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.phys.Vec3 object OpBreakBlock : SpellAction { @@ -40,6 +41,12 @@ object OpBreakBlock : SpellAction { !blockstate.isAir && blockstate.getDestroySpeed(env.world, pos) >= 0f // fix being able to break bedrock &c && IXplatAbstractions.INSTANCE.isCorrectTierForDrops(tier, blockstate) + && IXplatAbstractions.INSTANCE.isBreakingAllowed( + env.world, + pos, + blockstate, + env.castingEntity as? ServerPlayer + ) ) { env.world.destroyBlock(pos, true, env.castingEntity) } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt index d4cdff836b..ba4c407c4a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpColorize.kt @@ -18,13 +18,12 @@ object OpColorize : SpellAction { args: List, env: CastingEnvironment ): SpellAction.Result { - val (handStack, hand) = env.getHeldItemToOperateOn(IXplatAbstractions.INSTANCE::isPigment) - ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY, null, "colorizer") // TODO: hack + val (handStack) = env.getHeldItemToOperateOn(IXplatAbstractions.INSTANCE::isPigment) + ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY, "colorizer") // TODO: hack if (!IXplatAbstractions.INSTANCE.isPigment(handStack)) { throw MishapBadOffhandItem.of( handStack, - hand, "colorizer" ) } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpCycleVariant.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpCycleVariant.kt index 557f29e27c..e49e6e70af 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpCycleVariant.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpCycleVariant.kt @@ -13,12 +13,12 @@ object OpCycleVariant : SpellAction { override val argc = 0 override fun execute(args: List, env: CastingEnvironment): SpellAction.Result { - val (handStack, hand) = env.getHeldItemToOperateOn { + val (handStack) = env.getHeldItemToOperateOn { IXplatAbstractions.INSTANCE.findVariantHolder(it) != null - } ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), null, "variant") // TODO: hack + } ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), "variant") // TODO: hack val variantHolder = IXplatAbstractions.INSTANCE.findVariantHolder(handStack) - ?: throw MishapBadOffhandItem.of(handStack, hand, "variant") + ?: throw MishapBadOffhandItem.of(handStack, "variant") return SpellAction.Result( Spell(variantHolder), diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpErase.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpErase.kt index f1c810ccfb..85fc913276 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpErase.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpErase.kt @@ -16,13 +16,13 @@ object OpErase : SpellAction { args: List, env: CastingEnvironment ): SpellAction.Result { - val (handStack, hand) = env.getHeldItemToOperateOn { + val (handStack) = env.getHeldItemToOperateOn { val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(it) val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(it) (hexHolder?.hasHex() == true) || (datumHolder?.writeIota(null, true) == true) - } ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), null, "eraseable") // TODO: hack + } ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), "eraseable") // TODO: hack val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(handStack) val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack) @@ -30,7 +30,7 @@ object OpErase : SpellAction { if ((hexHolder?.hasHex() != true) && (datumHolder?.writeIota(null, true) != true) ) { - throw MishapBadOffhandItem.of(handStack, hand, "eraseable") + throw MishapBadOffhandItem.of(handStack, "eraseable") } return SpellAction.Result( diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakeBattery.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakeBattery.kt index 7b60cf4769..5e86b23504 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakeBattery.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakeBattery.kt @@ -29,19 +29,17 @@ object OpMakeBattery : SpellAction { val entity = args.getItemEntity(0, argc) val (handStack, hand) = env.getHeldItemToOperateOn { it.`is`(HexTags.Items.PHIAL_BASE) } - ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), null, "bottle") // TODO: hack + ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), "bottle") // TODO: hack if (!handStack.`is`(HexTags.Items.PHIAL_BASE)) { throw MishapBadOffhandItem.of( handStack, - hand, "bottle" ) } if (handStack.count != 1) { throw MishapBadOffhandItem.of( handStack, - hand, "only_one" ) } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakePackagedSpell.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakePackagedSpell.kt index 8101af64b7..2601a70696 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakePackagedSpell.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpMakePackagedSpell.kt @@ -28,17 +28,17 @@ class OpMakePackagedSpell(val itemType: T, val cost: Long) val entity = args.getItemEntity(0, argc) val patterns = args.getList(1, argc).toList() - val (handStack, hand) = env.getHeldItemToOperateOn { + val (handStack) = env.getHeldItemToOperateOn { val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(it) it.`is`(itemType) && hexHolder != null && !hexHolder.hasHex() } - ?: throw MishapBadOffhandItem(ItemStack.EMPTY.copy(), null, itemType.description) // TODO: hack + ?: throw MishapBadOffhandItem(ItemStack.EMPTY.copy(), itemType.description) // TODO: hack val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(handStack) if (!handStack.`is`(itemType)) { - throw MishapBadOffhandItem(handStack, hand, itemType.description) + throw MishapBadOffhandItem(handStack, itemType.description) } else if (hexHolder == null || hexHolder.hasHex()) { - throw MishapBadOffhandItem.of(handStack, hand, "iota.write") + throw MishapBadOffhandItem.of(handStack, "iota.write") } env.assertEntityInRange(entity) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt index dcbe77844a..e71a3df9bd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPlaceBlock.kt @@ -39,9 +39,9 @@ object OpPlaceBlock : SpellAction { Vec3.atCenterOf(pos), env.castingEntity?.direction ?: Direction.NORTH, pos, false ) val itemUseCtx = env - .getHeldItemToOperateOn { it.item is BlockItem } - ?.stack?.let { UseOnContext(env.world, env.castingEntity as? ServerPlayer, env.castingHand, it, blockHit) } - ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY, env.castingHand, "placeable") + .queryForMatchingStack { it.item is BlockItem } + ?.let { UseOnContext(env.world, env.castingEntity as? ServerPlayer, env.castingHand, it, blockHit) } + ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY, "placeable") val placeContext = BlockPlaceContext(itemUseCtx) val worldState = env.world.getBlockState(pos) @@ -64,7 +64,7 @@ object OpPlaceBlock : SpellAction { ) val bstate = env.world.getBlockState(pos) - val placeeStack = env.getHeldItemToOperateOn { it.item is BlockItem }?.stack + val placeeStack = env.queryForMatchingStack { it.item is BlockItem } if (placeeStack != null) { if (!IXplatAbstractions.INSTANCE.isPlacingAllowed(env.world, pos, placeeStack, caster as? ServerPlayer)) return diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt index cea6c99faf..6f7dc5a05e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpPotionEffect.kt @@ -24,7 +24,7 @@ class OpPotionEffect( val target = args.getLivingEntityButNotArmorStand(0, argc) val duration = args.getPositiveDouble(1, argc) val potency = if (this.allowPotency) - args.getPositiveDoubleUnderInclusive(2, 127.0, argc) + args.getDoubleBetween(2, 1.0, 127.0, argc) else 1.0 env.assertEntityInRange(target) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpRecharge.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpRecharge.kt index 675dc4996f..0b7fcb6dfd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpRecharge.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/spells/OpRecharge.kt @@ -23,18 +23,17 @@ object OpRecharge : SpellAction { ): SpellAction.Result { val entity = args.getItemEntity(0, argc) - val (handStack, hand) = env.getHeldItemToOperateOn { + val (handStack) = env.getHeldItemToOperateOn { val media = IXplatAbstractions.INSTANCE.findMediaHolder(it) media != null && media.canRecharge() && media.insertMedia(-1, true) != 0L } - ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), null, "rechargable") // TODO: hack + ?: throw MishapBadOffhandItem.of(ItemStack.EMPTY.copy(), "rechargable") // TODO: hack val media = IXplatAbstractions.INSTANCE.findMediaHolder(handStack) if (media == null || !media.canRecharge()) throw MishapBadOffhandItem.of( handStack, - hand, "rechargable" ) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt index 57917c2279..075a17a76f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/arithmetic/DoubleArithmetic.kt @@ -57,7 +57,8 @@ object DoubleArithmetic : Arithmetic { MUL -> make2 { a, b -> a * b } DIV -> make2 { a, b -> if (b == 0.0) throw MishapDivideByZero.of(a, b) else a / b } ABS -> make1 { a -> abs(a) } - POW -> make2 { a, b -> a.pow(b) } + // throw MishapDivideByZero if raising a negative number to a fractional power (ie. sqrt(-1) etc) + POW -> make2 { a, b -> if (a < 0 && !DoubleIota.tolerates(floor(b), b)) throw MishapDivideByZero.of(a, b, "exponent") else a.pow(b) } FLOOR -> make1 { a -> floor(a) } CEIL -> make1 { a -> ceil(a) } SIN -> make1 { a -> sin(a) } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java index 3ecb220bf0..ad8527581f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemAbacus.java @@ -33,6 +33,11 @@ CompoundTag readIotaTag(ItemStack stack) { return IotaType.serialize(datum); } + @Override + public boolean writeable(ItemStack stack) { + return false; + } + @Override public boolean canWrite(ItemStack stack, Iota datum) { return false; diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java index 27c6a8c8ee..8d08c9923f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemFocus.java @@ -2,7 +2,6 @@ import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.iota.IotaType; -import at.petrak.hexcasting.api.casting.iota.NullIota; import at.petrak.hexcasting.api.item.IotaHolderItem; import at.petrak.hexcasting.api.item.VariantItem; import at.petrak.hexcasting.api.utils.NBTHelper; @@ -45,13 +44,13 @@ public String getDescriptionId(ItemStack stack) { } @Override - public @Nullable Iota emptyIota(ItemStack stack) { - return new NullIota(); + public boolean writeable(ItemStack stack) { + return !isSealed(stack); } @Override public boolean canWrite(ItemStack stack, Iota datum) { - return datum == null || !NBTHelper.getBoolean(stack, TAG_SEALED); + return datum == null || !isSealed(stack); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java index d1bed2504f..036e5129b4 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemScroll.java @@ -64,6 +64,11 @@ CompoundTag readIotaTag(ItemStack stack) { return out; } + @Override + public boolean writeable(ItemStack stack) { + return true; + } + @Override public boolean canWrite(ItemStack stack, Iota datum) { return datum instanceof PatternIota || datum == null; diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java index cd2454e9e1..98227d1eab 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSlate.java @@ -96,6 +96,11 @@ CompoundTag readIotaTag(ItemStack stack) { return out; } + @Override + public boolean writeable(ItemStack stack) { + return true; + } + @Override public boolean canWrite(ItemStack stack, Iota datum) { return datum instanceof PatternIota || datum == null; diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java index 2b2eb98d77..b7521f7619 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemSpellbook.java @@ -2,7 +2,6 @@ import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.iota.IotaType; -import at.petrak.hexcasting.api.casting.iota.NullIota; import at.petrak.hexcasting.api.item.IotaHolderItem; import at.petrak.hexcasting.api.item.VariantItem; import at.petrak.hexcasting.api.utils.NBTHelper; @@ -130,9 +129,8 @@ CompoundTag readIotaTag(ItemStack stack) { } @Override - public @Nullable - Iota emptyIota(ItemStack stack) { - return new NullIota(); + public boolean writeable(ItemStack stack) { + return !isSealed(stack); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemThoughtKnot.java b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemThoughtKnot.java index 518917b0b9..9e867cc250 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemThoughtKnot.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/storage/ItemThoughtKnot.java @@ -32,9 +32,14 @@ public ItemThoughtKnot(Properties properties) { return NBTHelper.getCompound(stack, TAG_DATA); } + @Override + public boolean writeable(ItemStack stack) { + return !NBTHelper.contains(stack, TAG_DATA); + } + @Override public boolean canWrite(ItemStack stack, @Nullable Iota iota) { - return iota != null && !NBTHelper.contains(stack, TAG_DATA); + return iota != null && writeable(stack); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java b/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java index 19956a7db8..28012e0da5 100644 --- a/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java +++ b/Common/src/main/java/at/petrak/hexcasting/datagen/HexAdvancements.java @@ -2,6 +2,7 @@ import at.petrak.hexcasting.api.HexAPI; import at.petrak.hexcasting.api.advancements.FailToCastGreatSpellTrigger; +import at.petrak.hexcasting.api.advancements.MinMaxLongs; import at.petrak.hexcasting.api.advancements.OvercastTrigger; import at.petrak.hexcasting.api.advancements.SpendMediaTrigger; import at.petrak.hexcasting.api.misc.MediaConstants; @@ -57,15 +58,15 @@ public void generate(HolderLookup.Provider provider, Consumer consu .display(simpleDisplay(Items.GLISTERING_MELON_SLICE, "wasteful_cast", FrameType.TASK)) .parent(root) .addCriterion("waste_amt", new SpendMediaTrigger.Instance(ContextAwarePredicate.ANY, - MinMaxBounds.Ints.ANY, - MinMaxBounds.Ints.atLeast((int) (89 * MediaConstants.DUST_UNIT / 10)))) + MinMaxLongs.ANY, + MinMaxLongs.atLeast(89 * MediaConstants.DUST_UNIT / 10))) .save(consumer, prefix("aaa_wasteful_cast")); Advancement.Builder.advancement() .display(simpleDisplay(HexItems.CHARGED_AMETHYST, "big_cast", FrameType.TASK)) .parent(root) .addCriterion("cast_amt", new SpendMediaTrigger.Instance(ContextAwarePredicate.ANY, - MinMaxBounds.Ints.atLeast((int) (64 * MediaConstants.CRYSTAL_UNIT)), - MinMaxBounds.Ints.ANY)) + MinMaxLongs.atLeast(64 * MediaConstants.CRYSTAL_UNIT), + MinMaxLongs.ANY)) .save(consumer, prefix("aab_big_cast")); var impotence = Advancement.Builder.advancement() diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index f845247f79..fa28c123d1 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -1426,7 +1426,7 @@ }, phials: { - "1": "I find it quite ... irritating, how Nature refuses to give me change for my work. If all I have on hand is $(l:items/amethyst)$(item)Charged Amethyst/$, even the tiniest $(l:patterns/basics#hexcasting:raycast)$(action)Archer's Purification/$ will consume the entire crystal, wasting the remaining _media.$(br2)Fortunately, it seems I've found a way to somewhat allay this problem.", + "1": "I find it quite ... irritating, how Nature refuses to give me change for my work. If all I have on hand is $(l:items/amethyst)$(item)Charged Amethyst/$, even the tiniest $(l:patterns/basics#hexcasting:raycast)$(action)Archer's Distillation/$ will consume the entire crystal, wasting the remaining _media.$(br2)Fortunately, it seems I've found a way to somewhat allay this problem.", "2": "I've found old scrolls describing a $(item)Glass Bottle/$ infused with _media. When casting _Hexes, my spells would then draw _media out of the phial. The liquid form of the _media would let me take exact change, so to speak; nothing would be wasted. It's quite like the internal battery of a $(l:items/hexcasting)$(item)Trinket/$, or similar; I can even $(l:patterns/spells/hexcasting#hexcasting:recharge)$(action)Recharge/$ them in the same manner.", "3": "Unfortunately, the art of actually $(italic)making/$ the things seems to have been lost to time. I've found a $(l:patterns/great_spells/make_battery#hexcasting:craft/battery)$(thing)hint at the pattern used to craft it/$, but the technique is irritatingly elusive, and I can't seem to do it successfully. I suspect I will figure it out with study and practice, though. For now, I will simply deal with the wasted _media...$(br2)But I won't settle for it forever.", desc: "$(italic)Drink the milk./$", diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCEntityIotaHolder.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCEntityIotaHolder.java index ae794ad913..81998b9e69 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCEntityIotaHolder.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCEntityIotaHolder.java @@ -31,6 +31,11 @@ public Wrapper(ItemDelegatingEntityIotaHolder inner) { return inner.readIotaTag(); } + @Override + public boolean writeable() { + return inner.writeable(); + } + @Override public boolean writeIota(@Nullable Iota iota, boolean simulate) { return inner.writeIota(iota, simulate); diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCItemIotaHolder.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCItemIotaHolder.java index c0f8993ff9..10e9566594 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCItemIotaHolder.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCItemIotaHolder.java @@ -32,6 +32,11 @@ public ItemBased(ItemStack stack) { return this.iotaHolder.readIotaTag(this.stack); } + @Override + public boolean writeable() { + return this.iotaHolder.writeable(this.stack); + } + @Override public boolean writeIota(@Nullable Iota iota, boolean simulate) { var canWrite = this.iotaHolder.canWrite(this.stack, iota); @@ -59,6 +64,11 @@ public Static(ItemStack stack, Function provider) { return iota == null ? null : IotaType.serialize(iota); } + @Override + public boolean writeable() { + return false; + } + @Override public boolean writeIota(@Nullable Iota datum, boolean simulate) { return false; diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCMediaHolder.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCMediaHolder.java index 539c5e5edd..b4ff6ed091 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCMediaHolder.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/cc/adimpl/CCMediaHolder.java @@ -51,7 +51,7 @@ public boolean canProvide() { @Override public int getConsumptionPriority() { - return ADMediaHolder.BATTERY_PRIORITY; + return this.mediaHolder.getConsumptionPriority(this.stack); } @Override diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapEntityIotaHolder.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapEntityIotaHolder.java index 8ad61fd00a..a8623e6249 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapEntityIotaHolder.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapEntityIotaHolder.java @@ -21,6 +21,11 @@ public Wrapper(ItemDelegatingEntityIotaHolder inner) { return inner.readIotaTag(); } + @Override + public boolean writeable() { + return inner.writeable(); + } + @Override public boolean writeIota(@Nullable Iota iota, boolean simulate) { return inner.writeIota(iota, simulate); diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemIotaHolder.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemIotaHolder.java index a1937c0ce3..29caaeb0d0 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemIotaHolder.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemIotaHolder.java @@ -39,4 +39,9 @@ public boolean writeIota(@Nullable Iota iota, boolean simulate) { } return true; } + + @Override + public boolean writeable() { + return holder.writeable(stack); + } } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemMediaHolder.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemMediaHolder.java index b595891118..7f84f1d154 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemMediaHolder.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapItemMediaHolder.java @@ -37,7 +37,7 @@ public boolean canProvide() { @Override public int getConsumptionPriority() { - return ADMediaHolder.BATTERY_PRIORITY; + return holder.getConsumptionPriority(stack); } @Override diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapStaticIotaHolder.java b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapStaticIotaHolder.java index 1eb438a191..f94cd93455 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapStaticIotaHolder.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/cap/adimpl/CapStaticIotaHolder.java @@ -26,6 +26,11 @@ Iota readIota(ServerLevel world) { return provider.apply(stack); } + @Override + public boolean writeable() { + return false; + } + @Override public boolean writeIota(@Nullable Iota iota, boolean simulate) { return false;