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.PatternShapeMatch;
import at.petrak.hexcasting.api.casting.eval.SpellCircleContext;
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
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.misc.FrozenColorizer;
import at.petrak.hexcasting.api.mod.HexConfig;
import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
@ -50,23 +48,22 @@ public abstract class CastingEnvironment {
* Get the caster. Might be null!
* <p>
* 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
public abstract ServerPlayer getCaster();
/**
* Get an interface used to do mishaps
*/
public abstract MishapEnvironment getMishapEnvironment();
/**
* Get the sound that this I/O module makes.
* <p>
*/
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.
* <p>
@ -134,9 +131,11 @@ public abstract class CastingEnvironment {
throw new MishapLocationTooFarAway(vec, "too_far");
}
}
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) {
// TODO winfy: fill this in
return false;
@ -200,9 +199,15 @@ public abstract class CastingEnvironment {
}
public static record HeldItemInfo(ItemStack stack, InteractionHand hand) {
public ItemStack component1() { return stack; }
public InteractionHand component2() { return hand; }
public ItemStack component1() {
return stack;
}
public InteractionHand component2() {
return hand;
}
}
/**
* 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,
listOf(
OperatorSideEffect.DoMishap(
MishapError(exception),
MishapInternalException(exception),
Mishap.Context(
(iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST),
null

View file

@ -13,11 +13,8 @@ import at.petrak.hexcasting.ktxt.*
import net.minecraft.Util
import net.minecraft.core.BlockPos
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.entity.LivingEntity
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
@ -69,40 +66,6 @@ abstract class Mishap : Throwable() {
protected fun actionName(name: Component?): Component =
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 {
return ctx.world.getBlockState(pos).block.name
}
@ -111,7 +74,7 @@ abstract class Mishap : Throwable() {
companion object {
@JvmStatic
public fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {
fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {
entity.setHurtWithStamp(source, entity.level.gameTime)
val targetHealth = entity.health - amount

View file

@ -1,10 +1,10 @@
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.eval.CastingEnvironment
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.world.entity.Mob
import net.minecraft.world.item.DyeColor
@ -15,6 +15,7 @@ class MishapBadBrainsweep(val mob: Mob, val pos: BlockPos) : Mishap() {
dyeColor(DyeColor.GREEN)
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)
}

View file

@ -15,7 +15,7 @@ class MishapBadEntity(val entity: Entity, val wanted: Component) : Mishap() {
dyeColor(DyeColor.BROWN)
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) =

View file

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

View file

@ -1,12 +1,11 @@
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.iota.DoubleIota
import at.petrak.hexcasting.api.casting.iota.GarbageIota
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.Vec3Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import net.minecraft.network.chat.Component
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>) {
stack.add(GarbageIota())
val caster = ctx.caster
if (caster != null) {
// FIXME case where caster is null
trulyHurt(caster, HexDamageSources.OVERCAST, caster.health / 2)
}
ctx.mishapEnvironment.damage(0.5f)
}
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =

View file

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

View file

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

View file

@ -13,7 +13,7 @@ class MishapLocationTooFarAway(val location: Vec3, val type: String = "too_far")
dyeColor(DyeColor.MAGENTA)
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 =

View file

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

View file

@ -1,12 +1,10 @@
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.iota.EntityIota
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.ListIota
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import at.petrak.hexcasting.api.misc.FrozenColorizer
import net.minecraft.world.entity.player.Player
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>) {
val seconds = if (this.confidant == ctx.caster) 5 else 60;
val caster = ctx.caster
if (caster != null) {
// FIXME: handle null caster case
caster.addEffect(MobEffectInstance(MobEffects.BLINDNESS, seconds * 20))
}
ctx.mishapEnvironment.blind(seconds * 20)
}
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));
}
}