diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/ConstMediaAction.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/ConstMediaAction.kt index a907764c7d..276ee73122 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/ConstMediaAction.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/ConstMediaAction.kt @@ -7,6 +7,7 @@ import at.petrak.hexcasting.api.casting.eval.vm.CastingImage import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs +import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughMedia import at.petrak.hexcasting.common.lib.hex.HexEvalSounds /** @@ -27,6 +28,8 @@ interface ConstMediaAction : Action { override fun operate(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation): OperationResult { val stack = image.stack.toMutableList() + if (env.extractMedia(this.mediaCost, true) > 0) + throw MishapNotEnoughMedia(this.mediaCost) if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/SpellAction.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/SpellAction.kt index bcea2cd954..fcf17d08d0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/SpellAction.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/castables/SpellAction.kt @@ -9,6 +9,7 @@ import at.petrak.hexcasting.api.casting.eval.vm.CastingImage import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs +import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughMedia import at.petrak.hexcasting.common.lib.hex.HexEvalSounds import net.minecraft.nbt.CompoundTag @@ -44,6 +45,8 @@ interface SpellAction : Action { val sideEffects = mutableListOf() + if (env.extractMedia(result.cost, true) > 0) + throw MishapNotEnoughMedia(result.cost) if (result.cost > 0) sideEffects.add(OperatorSideEffect.ConsumeMedia(result.cost)) 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 a7a3dd9478..6eaaf765ec 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 @@ -238,12 +238,12 @@ public boolean isEnlightened() { * If there was enough media found, it will return less or equal to zero; if there wasn't, it will be * positive. */ - public long extractMedia(long cost) { + public long extractMedia(long cost, boolean simulate) { for (var extractMediaComponent : preMediaExtract) - cost = extractMediaComponent.onExtractMedia(cost); - cost = extractMediaEnvironment(cost); + cost = extractMediaComponent.onExtractMedia(cost, simulate); + cost = extractMediaEnvironment(cost, simulate); for (var extractMediaComponent : postMediaExtract) - cost = extractMediaComponent.onExtractMedia(cost); + cost = extractMediaComponent.onExtractMedia(cost, simulate); return cost; } @@ -253,7 +253,7 @@ public long extractMedia(long cost) { * If there was enough media found, it will return less or equal to zero; if there wasn't, it will be * positive. */ - protected abstract long extractMediaEnvironment(long cost); + protected abstract long extractMediaEnvironment(long cost, boolean simulate); /** * Get if the vec is close enough, to the player or sentinel ... 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 faee1de0ba..73f7775a44 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 @@ -29,15 +29,15 @@ interface ExtractMedia extends CastingEnvironmentComponent { * remaining cost after deducting whatever cost source this component * is responsible for (should be >= 0) */ - long onExtractMedia(long cost); + long onExtractMedia(long cost, boolean simulate); /** - * ExtractMedia component that extracts media BEFORE the call to {@link CastingEnvironment#extractMediaEnvironment(long)} + * ExtractMedia component that extracts media BEFORE the call to {@link CastingEnvironment#extractMediaEnvironment(long, boolean)} */ interface Pre extends ExtractMedia {} /** - * ExtractMedia component that extracts media AFTER the call to {@link CastingEnvironment#extractMediaEnvironment(long)} + * ExtractMedia component that extracts media AFTER the call to {@link CastingEnvironment#extractMediaEnvironment(long, boolean)} * if the input is <= 0 you should also probably return 0 (since media cost was already paid off) */ interface Post extends ExtractMedia {} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java index 111bf3213f..d1d542780d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/CircleCastEnv.java @@ -111,7 +111,7 @@ public Vec3 mishapSprayPos() { } @Override - public long extractMediaEnvironment(long cost) { + public long extractMediaEnvironment(long cost, boolean simulate) { var entity = this.getImpetus(); if (entity == null) return cost; @@ -122,7 +122,9 @@ public long extractMediaEnvironment(long cost) { long mediaToTake = Math.min(cost, mediaAvailable); cost -= mediaToTake; - entity.setMedia(mediaAvailable - mediaToTake); + if (!simulate) { + entity.setMedia(mediaAvailable - mediaToTake); + } return cost; } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PackagedItemCastEnv.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PackagedItemCastEnv.java index 2a736d55d0..43d0c67d28 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PackagedItemCastEnv.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/env/PackagedItemCastEnv.java @@ -37,7 +37,7 @@ public void postExecution(CastResult result) { } @Override - public long extractMediaEnvironment(long costLeft) { + public long extractMediaEnvironment(long costLeft, boolean simulate) { if (this.caster.isCreative()) return 0; @@ -52,11 +52,11 @@ public long extractMediaEnvironment(long costLeft) { // The contracts on the AD and on this function are different. // ADs return the amount extracted, this wants the amount left if (casterMediaHolder != null) { - long extracted = casterMediaHolder.withdrawMedia((int) costLeft, false); + long extracted = casterMediaHolder.withdrawMedia((int) costLeft, simulate); costLeft -= extracted; } if (canCastFromInv && costLeft > 0) { - costLeft = this.extractMediaFromInventory(costLeft, this.canOvercast()); + costLeft = this.extractMediaFromInventory(costLeft, this.canOvercast(), simulate); } return costLeft; 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 a6cfa19763..10ff3b052b 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 @@ -106,13 +106,13 @@ public boolean hasEditPermissionsAtEnvironment(BlockPos pos) { /** * Search the player's inventory for media ADs and use them. */ - protected long extractMediaFromInventory(long costLeft, boolean allowOvercast) { + protected long extractMediaFromInventory(long costLeft, boolean allowOvercast, boolean simulate) { List sources = MediaHelper.scanPlayerForMediaStuff(this.caster); var startCost = costLeft; for (var source : sources) { - var found = MediaHelper.extractMedia(source, costLeft, false, false); + var found = MediaHelper.extractMedia(source, costLeft, false, simulate); costLeft -= found; if (costLeft <= 0) { break; @@ -122,24 +122,31 @@ protected long extractMediaFromInventory(long costLeft, boolean allowOvercast) { if (costLeft > 0 && allowOvercast) { double mediaToHealth = HexConfig.common().mediaToHealthRate(); double healthToRemove = Math.max(costLeft / mediaToHealth, 0.5); - var mediaAbleToCastFromHP = this.caster.getHealth() * mediaToHealth; + if (simulate) { + long simulatedRemovedMedia = Mth.ceil(Math.min(this.caster.getHealth(), healthToRemove) * mediaToHealth); + costLeft -= simulatedRemovedMedia; + } else { + var mediaAbleToCastFromHP = this.caster.getHealth() * mediaToHealth; - Mishap.trulyHurt(this.caster, this.caster.damageSources().source(HexDamageTypes.OVERCAST), (float) healthToRemove); + Mishap.trulyHurt(this.caster, this.caster.damageSources().source(HexDamageTypes.OVERCAST), (float) healthToRemove); - var actuallyTaken = Mth.ceil(mediaAbleToCastFromHP - (this.caster.getHealth() * mediaToHealth)); + var actuallyTaken = Mth.ceil(mediaAbleToCastFromHP - (this.caster.getHealth() * mediaToHealth)); - HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.caster, actuallyTaken); - this.caster.awardStat(HexStatistics.MEDIA_OVERCAST, actuallyTaken); + HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.caster, actuallyTaken); + this.caster.awardStat(HexStatistics.MEDIA_OVERCAST, actuallyTaken); - costLeft -= actuallyTaken; + costLeft -= actuallyTaken; + } } - this.caster.awardStat(HexStatistics.MEDIA_USED, (int) (startCost - costLeft)); - HexAdvancementTriggers.SPEND_MEDIA_TRIGGER.trigger( - this.caster, - startCost - costLeft, - costLeft < 0 ? -costLeft : 0 - ); + if (!simulate) { + 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 6fbfa7bcf6..29e80d3817 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 @@ -69,16 +69,12 @@ public void postCast(CastingImage image) { } @Override - public long extractMediaEnvironment(long cost) { + public long extractMediaEnvironment(long cost, boolean simulate) { if (this.caster.isCreative()) return 0; var canOvercast = this.canOvercast(); - var remaining = this.extractMediaFromInventory(cost, canOvercast); - if (remaining > 0 && !canOvercast) { - this.caster.sendSystemMessage(Component.translatable("hexcasting.message.cant_overcast")); - } - return remaining; + return this.extractMediaFromInventory(cost, canOvercast, simulate); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/sideeffects/OperatorSideEffect.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/sideeffects/OperatorSideEffect.kt index 9143d54d2c..72226fe291 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/sideeffects/OperatorSideEffect.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/sideeffects/OperatorSideEffect.kt @@ -18,14 +18,11 @@ import net.minecraft.world.item.ItemStack */ sealed class OperatorSideEffect { /** Return whether to cancel all further [OperatorSideEffect] */ - abstract fun performEffect(harness: CastingVM): Boolean + abstract fun performEffect(harness: CastingVM) data class RequiredEnlightenment(val awardStat: Boolean) : OperatorSideEffect() { - override fun performEffect(harness: CastingVM): Boolean { + override fun performEffect(harness: CastingVM) { harness.env.castingEntity?.sendSystemMessage("hexcasting.message.cant_great_spell".asTranslatedComponent) - - - return true } } @@ -36,33 +33,28 @@ sealed class OperatorSideEffect { val awardStat: Boolean = true ) : OperatorSideEffect() { - override fun performEffect(harness: CastingVM): Boolean { + override fun performEffect(harness: CastingVM) { this.spell.cast(harness.env, harness.image)?.let { harness.image = it } if (awardStat) (harness.env.castingEntity as? ServerPlayer)?.awardStat(HexStatistics.SPELLS_CAST) - - return false } } data class ConsumeMedia(val amount: Long) : OperatorSideEffect() { - override fun performEffect(harness: CastingVM): Boolean { - val leftoverMedia = harness.env.extractMedia(this.amount) - return leftoverMedia > 0 + override fun performEffect(harness: CastingVM) { + harness.env.extractMedia(this.amount, false) } } data class Particles(val spray: ParticleSpray) : OperatorSideEffect() { - override fun performEffect(harness: CastingVM): Boolean { + override fun performEffect(harness: CastingVM) { harness.env.produceParticles(this.spray, harness.env.pigment) // this.spray.sprayParticles(harness.env.world, harness.env.colorizer) - - return false } } data class DoMishap(val mishap: Mishap, val errorCtx: Mishap.Context) : OperatorSideEffect() { - override fun performEffect(harness: CastingVM): Boolean { + override fun performEffect(harness: CastingVM) { val spray = mishap.particleSpray(harness.env) val color = mishap.accentColor(harness.env, errorCtx) spray.sprayParticles(harness.env.world, color) @@ -75,8 +67,6 @@ sealed class OperatorSideEffect { ) harness.image = harness.image.copy(stack = mishap.executeReturnStack(harness.env, errorCtx, harness.image.stack.toMutableList())) - - return true } } } 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 caa000676e..587500355b 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 @@ -73,10 +73,10 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { continuation = image2.continuation lastResolutionType = image2.resolutionType try { - performSideEffects(info, image2.sideEffects) + performSideEffects(image2.sideEffects) } catch (e: Exception) { e.printStackTrace() - performSideEffects(info, listOf(OperatorSideEffect.DoMishap(MishapInternalException(e), Mishap.Context(null, null)))) + performSideEffects(listOf(OperatorSideEffect.DoMishap(MishapInternalException(e), Mishap.Context(null, null)))) } info.earlyExit = info.earlyExit || !lastResolutionType.success } @@ -152,13 +152,9 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { /** * Execute the side effects of a pattern, updating our aggregated info. */ - fun performSideEffects(info: TempControllerInfo, sideEffects: List) { + fun performSideEffects(sideEffects: List) { for (haskellProgrammersShakingandCryingRN in sideEffects) { - val mustStop = haskellProgrammersShakingandCryingRN.performEffect(this) - if (mustStop) { - info.earlyExit = true - break - } + haskellProgrammersShakingandCryingRN.performEffect(this) } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNotEnoughMedia.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNotEnoughMedia.kt new file mode 100644 index 0000000000..07d686b56e --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapNotEnoughMedia.kt @@ -0,0 +1,21 @@ +package at.petrak.hexcasting.api.casting.mishaps + +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.pigment.FrozenPigment +import at.petrak.hexcasting.api.utils.asTranslatedComponent +import net.minecraft.world.item.DyeColor + +class MishapNotEnoughMedia(private val cost: Long) : Mishap() { + override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment = + dyeColor(DyeColor.RED) + + override fun resolutionType(ctx: CastingEnvironment) = ResolvedPatternType.ERRORED + + override fun execute(env: CastingEnvironment, errorCtx: Context, stack: MutableList) { + env.extractMedia(cost, false) + } + + override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = "hexcasting.message.cant_overcast".asTranslatedComponent +} \ No newline at end of file