block up mishap envs

This commit is contained in:
petrak@ 2023-02-15 00:26:28 -06:00
parent 50554d5bf7
commit 2233c7697d
15 changed files with 146 additions and 89 deletions

View file

@ -2,7 +2,6 @@ package at.petrak.hexcasting.api.casting.eval;
import at.petrak.hexcasting.api.casting.ParticleSpray; import at.petrak.hexcasting.api.casting.ParticleSpray;
import at.petrak.hexcasting.api.casting.PatternShapeMatch; import at.petrak.hexcasting.api.casting.PatternShapeMatch;
import at.petrak.hexcasting.api.casting.eval.SpellCircleContext;
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound; import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
import at.petrak.hexcasting.api.casting.mishaps.Mishap; import at.petrak.hexcasting.api.casting.mishaps.Mishap;
import at.petrak.hexcasting.api.casting.mishaps.MishapDisallowedSpell; import at.petrak.hexcasting.api.casting.mishaps.MishapDisallowedSpell;
@ -10,7 +9,6 @@ import at.petrak.hexcasting.api.casting.mishaps.MishapEntityTooFarAway;
import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway; import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway;
import at.petrak.hexcasting.api.misc.FrozenColorizer; import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.mod.HexConfig; import at.petrak.hexcasting.api.mod.HexConfig;
import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -50,23 +48,22 @@ public abstract class CastingEnvironment {
* Get the caster. Might be null! * Get the caster. Might be null!
* <p> * <p>
* Implementations should NOT rely on this in general, use the methods on this class instead. * Implementations should NOT rely on this in general, use the methods on this class instead.
* This is mostly for things like mishaps. * This is mostly for spells (flight, etc)
*/ */
@Nullable @Nullable
public abstract ServerPlayer getCaster(); public abstract ServerPlayer getCaster();
/**
* Get an interface used to do mishaps
*/
public abstract MishapEnvironment getMishapEnvironment();
/** /**
* Get the sound that this I/O module makes. * Get the sound that this I/O module makes.
* <p> * <p>
*/ */
public abstract EvalSound getSoundType(); public abstract EvalSound getSoundType();
/**
* Get the spell circle running this cast. Might be null if not casting from a spell circle!
*/
@Nullable
public abstract SpellCircleContext getSpellCircle();
/** /**
* If something about this ARE itself is invalid, mishap. * If something about this ARE itself is invalid, mishap.
* <p> * <p>
@ -134,9 +131,11 @@ public abstract class CastingEnvironment {
throw new MishapLocationTooFarAway(vec, "too_far"); throw new MishapLocationTooFarAway(vec, "too_far");
} }
} }
public final void assertVecInRange(BlockPos vec) throws MishapLocationTooFarAway { public final void assertVecInRange(BlockPos vec) throws MishapLocationTooFarAway {
this.assertVecInRange(new Vec3(vec.x(), vec.y(), vec.z())); this.assertVecInRange(new Vec3(vec.getX(), vec.getY(), vec.getZ()));
} }
public final boolean canEditBlockAt(BlockPos vec) { public final boolean canEditBlockAt(BlockPos vec) {
// TODO winfy: fill this in // TODO winfy: fill this in
return false; return false;
@ -200,9 +199,15 @@ public abstract class CastingEnvironment {
} }
public static record HeldItemInfo(ItemStack stack, InteractionHand hand) { public static record HeldItemInfo(ItemStack stack, InteractionHand hand) {
public ItemStack component1() { return stack; } public ItemStack component1() {
public InteractionHand component2() { return hand; } return stack;
} }
public InteractionHand component2() {
return hand;
}
}
/** /**
* Return the slot from which to take blocks and items. * Return the slot from which to take blocks and items.
*/ */

View file

@ -0,0 +1,50 @@
package at.petrak.hexcasting.api.casting.eval;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
/**
* Kinda like {@link CastingEnvironment} but for executing mishaps.
* <p>
* To avoid horrible O(mn) scope problems we offer a set of stock bad effects.
* The player is exposed nullably if you like though.
*/
public abstract class MishapEnvironment {
@Nullable
protected final ServerPlayer caster;
protected final ServerLevel world;
protected MishapEnvironment(ServerLevel world, @Nullable ServerPlayer caster) {
this.caster = caster;
this.world = world;
}
public abstract void yeetHeldItemsTowards(Vec3 targetPos);
public abstract void dropHeldItems();
public abstract void drown();
public abstract void damage(float healthProportion);
public abstract void removeXp(int amount);
public abstract void blind(int ticks);
protected void yeetItem(ItemStack stack, Vec3 srcPos, Vec3 delta) {
var entity = new ItemEntity(
this.world,
srcPos.x, srcPos.y, srcPos.z,
stack,
delta.x + (Math.random() - 0.5) * 0.1,
delta.y + (Math.random() - 0.5) * 0.1,
delta.z + (Math.random() - 0.5) * 0.1
);
entity.setPickUpDelay(40);
this.world.addWithUUID(entity);
}
}

View file

@ -128,7 +128,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
null, null,
listOf( listOf(
OperatorSideEffect.DoMishap( OperatorSideEffect.DoMishap(
MishapError(exception), MishapInternalException(exception),
Mishap.Context( Mishap.Context(
(iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST), (iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST),
null null

View file

@ -13,11 +13,8 @@ import at.petrak.hexcasting.ktxt.*
import net.minecraft.Util import net.minecraft.Util
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionHand
import net.minecraft.world.damagesource.DamageSource import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -69,40 +66,6 @@ abstract class Mishap : Throwable() {
protected fun actionName(name: Component?): Component = protected fun actionName(name: Component?): Component =
name ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple name ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple
protected fun yeetHeldItemsTowards(env: CastingEnvironment, targetPos: Vec3) {
// Knock the player's items out of their hands
val items = mutableListOf<ItemStack>()
val caster = env.caster
if (caster != null) {
// FIXME: handle null caster case
return
}
for (hand in InteractionHand.values()) {
items.add(caster.getItemInHand(hand).copy())
caster.setItemInHand(hand, ItemStack.EMPTY)
}
val pos = caster.position()
val delta = targetPos.subtract(pos).normalize().scale(0.5)
for (item in items) {
yeetItem(env, item, pos, delta)
}
}
protected fun yeetItem(env: CastingEnvironment, stack: ItemStack, pos: Vec3, delta: Vec3) {
val entity = ItemEntity(
env.world,
pos.x, pos.y, pos.z,
stack,
delta.x + (Math.random() - 0.5) * 0.1,
delta.y + (Math.random() - 0.5) * 0.1,
delta.z + (Math.random() - 0.5) * 0.1
)
entity.setPickUpDelay(40)
env.world.addWithUUID(entity)
}
protected fun blockAtPos(ctx: CastingEnvironment, pos: BlockPos): Component { protected fun blockAtPos(ctx: CastingEnvironment, pos: BlockPos): Component {
return ctx.world.getBlockState(pos).block.name return ctx.world.getBlockState(pos).block.name
} }
@ -111,7 +74,7 @@ abstract class Mishap : Throwable() {
companion object { companion object {
@JvmStatic @JvmStatic
public fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) { fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {
entity.setHurtWithStamp(source, entity.level.gameTime) entity.setHurtWithStamp(source, entity.level.gameTime)
val targetHealth = entity.health - amount val targetHealth = entity.health - amount

View file

@ -1,10 +1,10 @@
package at.petrak.hexcasting.api.casting.mishaps package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.casting.ParticleSpray import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.entity.Mob import net.minecraft.world.entity.Mob
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
@ -15,6 +15,7 @@ class MishapBadBrainsweep(val mob: Mob, val pos: BlockPos) : Mishap() {
dyeColor(DyeColor.GREEN) dyeColor(DyeColor.GREEN)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
// TODO: you can just instakill things with this
trulyHurt(mob, HexDamageSources.overcastDamageFrom(ctx.caster), mob.health) trulyHurt(mob, HexDamageSources.overcastDamageFrom(ctx.caster), mob.health)
} }

View file

@ -15,7 +15,7 @@ class MishapBadEntity(val entity: Entity, val wanted: Component) : Mishap() {
dyeColor(DyeColor.BROWN) dyeColor(DyeColor.BROWN)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
yeetHeldItemsTowards(ctx, entity.position()) ctx.mishapEnvironment.yeetHeldItemsTowards(entity.position())
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =

View file

@ -14,8 +14,7 @@ class MishapBadOffhandItem(val item: ItemStack, val hand: InteractionHand, val w
dyeColor(DyeColor.BROWN) dyeColor(DyeColor.BROWN)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
// FIXME: Missing implementation in mishap ctx.mishapEnvironment.dropHeldItems()
//yeetHeldItem(ctx, hand)
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = if (item.isEmpty) override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = if (item.isEmpty)

View file

@ -1,12 +1,11 @@
package at.petrak.hexcasting.api.casting.mishaps package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.DoubleIota import at.petrak.hexcasting.api.casting.iota.DoubleIota
import at.petrak.hexcasting.api.casting.iota.GarbageIota import at.petrak.hexcasting.api.casting.iota.GarbageIota
import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.Vec3Iota import at.petrak.hexcasting.api.casting.iota.Vec3Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.utils.asTranslatedComponent import at.petrak.hexcasting.api.utils.asTranslatedComponent
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
@ -19,11 +18,7 @@ class MishapDivideByZero(val operand1: Component, val operand2: Component, val s
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
stack.add(GarbageIota()) stack.add(GarbageIota())
val caster = ctx.caster ctx.mishapEnvironment.damage(0.5f)
if (caster != null) {
// FIXME case where caster is null
trulyHurt(caster, HexDamageSources.OVERCAST, caster.health / 2)
}
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =

View file

@ -12,8 +12,7 @@ class MishapEntityTooFarAway(val entity: Entity) : Mishap() {
dyeColor(DyeColor.PINK) dyeColor(DyeColor.PINK)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
// Knock the player's items out of their hands ctx.mishapEnvironment.yeetHeldItemsTowards(entity.position())
yeetHeldItemsTowards(ctx, entity.position())
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component =

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.casting.mishaps package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
class MishapEvalTooDeep : Mishap() { class MishapEvalTooDeep : Mishap() {
@ -10,11 +10,7 @@ class MishapEvalTooDeep : Mishap() {
dyeColor(DyeColor.BLUE) dyeColor(DyeColor.BLUE)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
// FIXME what if caster is null ctx.mishapEnvironment.drown()
val caster = ctx.caster
if (caster != null) {
caster.airSupply -= 290
}
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =

View file

@ -5,7 +5,7 @@ import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
class MishapError(val exception: Exception) : Mishap() { class MishapInternalException(val exception: Exception) : Mishap() {
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer = override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.BLACK) dyeColor(DyeColor.BLACK)

View file

@ -13,7 +13,7 @@ class MishapLocationTooFarAway(val location: Vec3, val type: String = "too_far")
dyeColor(DyeColor.MAGENTA) dyeColor(DyeColor.MAGENTA)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
yeetHeldItemsTowards(ctx, location) ctx.mishapEnvironment.yeetHeldItemsTowards(this.location)
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component =

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.casting.mishaps package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
@ -11,11 +11,7 @@ class MishapNoAkashicRecord(val pos: BlockPos) : Mishap() {
dyeColor(DyeColor.PURPLE) dyeColor(DyeColor.PURPLE)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
val caster = ctx.caster ctx.mishapEnvironment.removeXp(100)
if (caster != null) {
// FIXME: handle null case
caster.giveExperiencePoints(-100)
}
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =

View file

@ -1,12 +1,10 @@
package at.petrak.hexcasting.api.casting.mishaps package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.EntityIota import at.petrak.hexcasting.api.casting.iota.EntityIota
import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.ListIota import at.petrak.hexcasting.api.casting.iota.ListIota
import net.minecraft.world.effect.MobEffectInstance import at.petrak.hexcasting.api.misc.FrozenColorizer
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
@ -19,11 +17,7 @@ class MishapOthersName(val confidant: Player) : Mishap() {
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
val seconds = if (this.confidant == ctx.caster) 5 else 60; val seconds = if (this.confidant == ctx.caster) 5 else 60;
val caster = ctx.caster ctx.mishapEnvironment.blind(seconds * 20)
if (caster != null) {
// FIXME: handle null caster case
caster.addEffect(MobEffectInstance(MobEffects.BLINDNESS, seconds * 20))
}
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =

View file

@ -0,0 +1,59 @@
package at.petrak.hexcasting.common.casting.env;
import at.petrak.hexcasting.api.casting.eval.MishapEnvironment;
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
import at.petrak.hexcasting.api.misc.HexDamageSources;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
public class PlayerBasedMishapEnv extends MishapEnvironment {
public PlayerBasedMishapEnv(ServerPlayer player) {
super(player.getLevel(), player);
}
@Override
public void yeetHeldItemsTowards(Vec3 targetPos) {
var pos = this.caster.position();
var delta = targetPos.subtract(pos).normalize().scale(0.5);
for (var hand : InteractionHand.values()) {
var stack = this.caster.getItemInHand(hand);
this.caster.setItemInHand(hand, ItemStack.EMPTY);
this.yeetItem(stack, pos, delta);
}
}
@Override
public void dropHeldItems() {
var delta = this.caster.getLookAngle();
this.yeetHeldItemsTowards(this.caster.position().add(delta));
}
@Override
public void damage(float healthProportion) {
Mishap.trulyHurt(this.caster, HexDamageSources.OVERCAST, this.caster.getHealth() * healthProportion);
}
@Override
public void drown() {
if (this.caster.getAirSupply() < 200) {
this.caster.hurt(DamageSource.DROWN, 2f);
}
this.caster.setAirSupply(0);
}
@Override
public void removeXp(int amount) {
this.caster.giveExperiencePoints(-amount);
}
@Override
public void blind(int ticks) {
this.caster.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, ticks));
}
}