ridiculous bug where it can't find a class I MADE

This commit is contained in:
gamma-delta 2022-03-26 16:33:04 -05:00
parent c499469941
commit 9ef0b4fa72
52 changed files with 348 additions and 338 deletions

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.api
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidPattern
import at.petrak.hexcasting.hexmath.EulerPathFinder
import at.petrak.hexcasting.hexmath.HexDir
import at.petrak.hexcasting.hexmath.HexPattern
@ -68,28 +68,39 @@ object PatternRegistry {
* Internal use only.
*/
@JvmStatic
fun matchPattern(pat: HexPattern, overworld: ServerLevel): Operator {
fun matchPattern(pat: HexPattern, overworld: ServerLevel): Operator =
matchPatternAndID(pat, overworld).first
/**
* Internal use only.
*/
@JvmStatic
fun matchPatternAndID(pat: HexPattern, overworld: ServerLevel): Pair<Operator, ResourceLocation?> {
// Pipeline:
// patterns are registered here every time the game boots
// when we try to look
for (handler in specialHandlers) {
val op = handler.handlePattern(pat)
if (op != null) return op
if (op != null) return Pair(op, null)
}
// Is it global?
val sig = pat.anglesSignature()
this.regularPatternLookup[sig]?.let {
return this.operatorLookup[it.opId] ?: throw CastException(CastException.Reason.INVALID_PATTERN, pat)
val op = this.operatorLookup[it.opId] ?: throw MishapInvalidPattern()
return Pair(op, it.opId)
}
// Look it up in the world?
val ds = overworld.dataStorage
val perWorldPatterns: Save =
ds.computeIfAbsent(Save.Companion::load, { Save.create(overworld.seed) }, TAG_SAVED_DATA)
perWorldPatterns.lookup[sig]?.let { return this.operatorLookup[it.first]!! }
perWorldPatterns.lookup[sig]?.let {
val op = this.operatorLookup[it.first]!!
return Pair(op, it.first)
}
throw CastException(CastException.Reason.INVALID_PATTERN, pat)
throw MishapInvalidPattern()
}
/**

View file

@ -28,6 +28,7 @@ import net.minecraft.tags.BlockTags;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
@ -364,7 +365,8 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple
var spray = new ParticleSpray(vpos, vecOutDir.scale(success ? 1.0 : 1.5), success ? 0.1 : 0.5,
Mth.PI / (success ? 4 : 2), success ? 30 : 100);
spray.sprayParticles(serverLevel,
success ? this.colorizer : new FrozenColorizer(HexItems.DYE_COLORIZERS[14].get(), this.activator));
success ? this.colorizer : new FrozenColorizer(HexItems.DYE_COLORIZERS.get(DyeColor.RED).get(),
this.activator));
}
var pitch = 1f;

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.OperatorSideEffect
import at.petrak.hexcasting.common.casting.mishaps.MishapNotEnoughArgs
/**
* A SimpleOperator that always costs the same amount of mana.
@ -16,7 +16,7 @@ interface ConstManaOperator : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
if (this.argc > stack.size)
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, this.argc, stack.size)
throw MishapNotEnoughArgs(this.argc, stack.size)
val args = stack.takeLast(this.argc)
for (_i in 0 until this.argc) stack.removeLast()
val newData = this.execute(args, ctx)

View file

@ -1,7 +1,8 @@
package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidIota
import at.petrak.hexcasting.common.casting.mishaps.MishapNotEnoughArgs
import net.minecraft.world.phys.Vec3
/**
@ -43,16 +44,11 @@ interface Operator {
*/
@JvmStatic
inline fun <reified T : Any> List<SpellDatum<*>>.getChecked(idx: Int): T {
val x = this.getOrElse(idx) { throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, idx, this.size) }
return x.tryGet()
}
/**
* Check if the value at the given index is OK. Will throw an error otherwise.
*/
@JvmStatic
inline fun <reified T : Any> List<SpellDatum<*>>.assertChecked(idx: Int) {
this.getChecked<T>(idx)
val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) }
if (x.payload is T)
return x.payload
else
throw MishapInvalidIota.ofClass(x, idx, T::class.java)
}
@JvmStatic

View file

@ -2,9 +2,9 @@ package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.HexUtils
import at.petrak.hexcasting.HexUtils.serializeToNBT
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.Widget
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidSpellDatumType
import at.petrak.hexcasting.hexmath.HexPattern
import net.minecraft.ChatFormatting
import net.minecraft.nbt.*
@ -32,13 +32,6 @@ import net.minecraft.world.phys.Vec3
class SpellDatum<T : Any> private constructor(val payload: T) {
val clazz: Class<T> = payload.javaClass
inline fun <reified U> tryGet(): U =
if (payload is U) {
payload
} else {
throw CastException(CastException.Reason.OP_WRONG_TYPE, U::class.java, this.payload)
}
fun serializeToNBT(): CompoundTag {
val out = CompoundTag()
when (val pl = this.payload) {
@ -113,7 +106,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
val num = payload.toDouble()
SpellDatum(HexUtils.FixNANs(num))
} else {
throw CastException(CastException.Reason.INVALID_TYPE, payload)
throw MishapInvalidSpellDatumType(payload)
}

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.OperatorSideEffect
import at.petrak.hexcasting.common.casting.mishaps.MishapNotEnoughArgs
interface SpellOperator : Operator {
val argc: Int
@ -14,7 +14,7 @@ interface SpellOperator : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
if (this.argc > stack.size)
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, this.argc, stack.size)
throw MishapNotEnoughArgs(this.argc, stack.size)
val args = stack.takeLast(this.argc)
for (_i in 0 until this.argc) stack.removeLast()
val (spell, mana, particles) = this.execute(args, ctx)

View file

@ -1,136 +0,0 @@
package at.petrak.hexcasting.common.casting
import at.petrak.hexcasting.hexmath.HexPattern
import net.minecraft.core.BlockPos
import net.minecraft.world.item.Item
import net.minecraft.world.phys.Vec3
class CastException(val reason: Reason, vararg val data: Any) : Exception() {
enum class Reason {
// Compilation
/**
* We couldn't match this pattern to an operator.
*
* `pattern: HexPattern`
*/
INVALID_PATTERN,
/**
* Completely invalid type for spellcasting.
* If you're seeing this error I messed up really bad
*
* `perpetrator: Any`
*/
INVALID_TYPE,
/**
* We need an argument with these properties, but didn't get it.
* Maddy put this in because Fisherman's needed it.
*
* `expected: Natural Number (1, 2, 3, n), got: -1`
*/
INVALID_VALUE,
// Pre-execution
/**
* When executing an operator we expected a different type.
*
* `expected: Class<*>, got: Any`
*/
OP_WRONG_TYPE,
/**
* We need at least this much on the stack to cast the spell but only got this much.
*
* `requiredArgc: Int, gotArgc: Int`
*/
NOT_ENOUGH_ARGS,
/**
* There are too many close parentheses.
*
* `no args`
*/
TOO_MANY_CLOSE_PARENS,
// Execution
/**
* Tried to interact with a vector that was too far away
*
* `vec: Vec3`
*/
TOO_FAR,
/**
* We went too deep!
*
* `maxDepth: Int, gotDepth: Int`
*/
TOO_MANY_RECURSIVE_EVALS,
/**
* Bad item in offhand
*
* `Class<Item> expected, ItemStack got`
*/
BAD_OFFHAND_ITEM,
/**
* Bad item in offhand except it uses items and not classes
*
* `Item expected, ItemStack got`
*/
BAD_OFFHAND_ITEM_ITEM,
/**
* Needs exactly X items in the offhand
*
* `Int needed, Int got`
*/
BAD_OFFHAND_COUNT,
/**
* Required an inventory at the given position.
*
* `BlockPos pos`
*/
REQUIRES_INVENTORY,
/**
* Extracting sentience didn't work
*
* for fucks sake i need to just implement mishaps already
*/
RECIPE_DIDNT_WORK,
/**
* No spell circles??
*/
NO_SPELL_CIRCLE,
/**
* No writing someone else's name!
*/
NO_WRITING_OTHER_NAMES
}
override val message: String
get() = when (this.reason) {
Reason.INVALID_PATTERN -> "could not match pattern to operator: ${this.data[0] as HexPattern}"
Reason.INVALID_TYPE -> "cannot use ${this.data[0]} as a SpellDatum (type ${this.data[0].javaClass.typeName})"
Reason.INVALID_VALUE -> "operator expected ${this.data[0]} but got ${this.data[1]}"
Reason.OP_WRONG_TYPE -> "operator expected ${(this.data[0] as Class<*>).typeName} but got ${this.data[1]} (type ${this.data[1].javaClass.typeName})"
Reason.NOT_ENOUGH_ARGS -> "required at least ${this.data[0] as Int} args on the stack but only had ${this.data[1] as Int}"
Reason.TOO_MANY_CLOSE_PARENS -> "too many close parentheses"
Reason.TOO_FAR -> "tried to interact with something too far away at ${this.data[0] as Vec3}"
Reason.TOO_MANY_RECURSIVE_EVALS -> "can only recursively call OpEval ${this.data[0] as Int} times but called it ${this.data[1] as Int} times"
Reason.BAD_OFFHAND_ITEM -> "operator expected ${(this.data[0] as Class<*>).typeName} in offhand but got ${this.data[1]}"
Reason.BAD_OFFHAND_ITEM_ITEM -> "operator expected ${(this.data[0] as Item).registryName} in offhand but got ${this.data[1]}"
Reason.BAD_OFFHAND_COUNT -> "operator expected ${this.data[0]} items in the offhand but got ${this.data[1]}"
Reason.REQUIRES_INVENTORY -> "required an inventory at ${this.data[0] as BlockPos}"
Reason.RECIPE_DIDNT_WORK -> "bad recipe"
Reason.NO_SPELL_CIRCLE -> "requires a spell circle to cast"
Reason.NO_WRITING_OTHER_NAMES -> "can't write someone else's Name"
}
}

View file

@ -3,8 +3,11 @@ package at.petrak.hexcasting.common.casting
import at.petrak.hexcasting.HexConfig
import at.petrak.hexcasting.HexUtils
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.casting.mishaps.MishapEntityTooFarAway
import at.petrak.hexcasting.common.casting.mishaps.MishapEvalTooDeep
import at.petrak.hexcasting.common.casting.mishaps.MishapLocationTooFarAway
import at.petrak.hexcasting.common.items.ItemDataHolder
import at.petrak.hexcasting.common.items.ItemSpellbook
import at.petrak.hexcasting.common.lib.HexCapabilities
import at.petrak.hexcasting.common.lib.RegisterHelper.prefix
import net.minecraft.server.level.ServerLevel
@ -34,23 +37,13 @@ data class CastingContext(
val position: Vec3 get() = caster.position()
fun getSpellbook(): ItemStack {
val handItem =
caster.getItemInHand(this.otherHand)
return if (handItem.item is ItemSpellbook) {
handItem
} else {
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, ItemSpellbook::class.java, handItem)
}
}
fun getDataHolder(): ItemStack {
val handItem =
caster.getItemInHand(this.otherHand)
return if (handItem.item is ItemDataHolder) {
handItem
} else {
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, ItemDataHolder::class.java, handItem)
throw MishapBadOffhandItem.of(handItem, "iota")
}
}
@ -61,7 +54,7 @@ data class CastingContext(
this.depth++
val maxAllowedDepth = HexConfig.maxRecurseDepth.get()
if (this.depth > maxAllowedDepth) {
throw CastException(CastException.Reason.TOO_MANY_RECURSIVE_EVALS, maxAllowedDepth, this.depth)
throw MishapEvalTooDeep()
}
}
@ -69,14 +62,14 @@ data class CastingContext(
* Check to make sure a vec is in range
*/
fun assertVecInRange(vec: Vec3) {
if (!isVecInRange(vec)) throw CastException(CastException.Reason.TOO_FAR, vec)
if (!isVecInRange(vec)) throw MishapLocationTooFarAway(vec)
}
/**
* Check to make sure an entity is in range
*/
fun assertEntityInRange(entity: Entity) {
if (!isEntityInRange(entity)) throw CastException(CastException.Reason.TOO_FAR, entity.position())
if (!isEntityInRange(entity)) throw MishapEntityTooFarAway(entity)
}
fun isVecInRange(vec: Vec3): Boolean {

View file

@ -4,9 +4,12 @@ import at.petrak.hexcasting.HexConfig
import at.petrak.hexcasting.HexMod
import at.petrak.hexcasting.api.PatternRegistry
import at.petrak.hexcasting.api.circle.BlockEntityAbstractImpetus
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import at.petrak.hexcasting.common.casting.mishaps.Mishap
import at.petrak.hexcasting.common.casting.mishaps.MishapTooManyCloseParens
import at.petrak.hexcasting.common.items.ItemWand
import at.petrak.hexcasting.common.items.magic.ItemPackagedSpell
import at.petrak.hexcasting.common.lib.HexCapabilities
@ -18,6 +21,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.phys.Vec3
import kotlin.math.min
@ -57,6 +61,8 @@ class CastingHarness private constructor(
fun getUpdate(newPat: HexPattern, world: ServerLevel): CastResult {
if (this.ctx.spellCircle == null)
this.ctx.caster.awardStat(HexStatistics.PATTERNS_DRAWN)
var operatorIdPair: Pair<Operator, ResourceLocation?>? = null
try {
// wouldn't it be nice to be able to go paren'
// i guess i'll call it paren2
@ -69,8 +75,8 @@ class CastingHarness private constructor(
}
// Don't catch this one
val operator = PatternRegistry.matchPattern(newPat, world)
val (stack2, sideEffectsUnmut) = operator.operate(this.stack.toMutableList(), this.ctx)
operatorIdPair = PatternRegistry.matchPatternAndID(newPat, world)
val (stack2, sideEffectsUnmut) = operatorIdPair.first.operate(this.stack.toMutableList(), this.ctx)
// Stick a poofy particle effect at the caster position
val sideEffects = sideEffectsUnmut.toMutableList()
if (this.ctx.spellCircle == null)
@ -92,10 +98,10 @@ class CastingHarness private constructor(
fd,
sideEffects,
)
} catch (exn: CastException) {
} catch (mishap: Mishap) {
return CastResult(
this.getFunctionalData(),
listOf(OperatorSideEffect.Mishap(exn)),
listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.second))),
)
}
}
@ -159,7 +165,7 @@ class CastingHarness private constructor(
private fun handleParentheses(newPat: HexPattern): FunctionalData? {
val operator = try {
PatternRegistry.matchPattern(newPat, this.ctx.world)
} catch (e: CastException) {
} catch (mishap: Mishap) {
null
}
@ -194,7 +200,7 @@ class CastingHarness private constructor(
parenthesized = listOf()
)
} else if (newParenCount < 0) {
throw CastException(CastException.Reason.TOO_MANY_CLOSE_PARENS)
throw MishapTooManyCloseParens()
} else {
// we have this situation: "(()"
// we need to add the close paren
@ -228,7 +234,7 @@ class CastingHarness private constructor(
parenCount = this.parenCount + 1
)
} else if (operator == Widget.CLOSE_PAREN) {
throw CastException(CastException.Reason.TOO_MANY_CLOSE_PARENS)
throw MishapTooManyCloseParens()
} else {
null
}

View file

@ -2,14 +2,14 @@ package at.petrak.hexcasting.common.casting
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import at.petrak.hexcasting.common.casting.mishaps.Mishap
import at.petrak.hexcasting.common.items.HexItems
import at.petrak.hexcasting.common.lib.HexStatistics
import at.petrak.hexcasting.datagen.HexAdvancements
import net.minecraft.Util
import net.minecraft.network.chat.TextComponent
import net.minecraft.network.chat.TranslatableComponent
import kotlin.random.Random
import kotlin.random.nextInt
import net.minecraft.world.item.DyeColor
/**
* Things that happen after a spell is cast.
@ -59,20 +59,20 @@ sealed class OperatorSideEffect {
}
}
data class Mishap(val exn: CastException) : OperatorSideEffect() {
data class DoMishap(val mishap: Mishap, val errorCtx: Mishap.Context) : OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
harness.ctx.caster.sendMessage(
TextComponent(exn.message),
Util.NIL_UUID
// for now
harness.ctx.caster.sendMessage(mishap.errorMessage(harness.ctx, errorCtx), Util.NIL_UUID)
val spray = mishap.particleSpray(harness.ctx)
val color = mishap.accentColor(harness.ctx, errorCtx)
spray.sprayParticles(harness.ctx.world, color)
spray.sprayParticles(
harness.ctx.world,
FrozenColorizer(HexItems.DYE_COLORIZERS[DyeColor.RED]!!.get(), Util.NIL_UUID)
)
when (exn.reason) {
CastException.Reason.INVALID_PATTERN -> {
val idx = Random.nextInt(0..harness.stack.size)
harness.stack.add(idx, SpellDatum.make(Widget.GARBAGE))
}
else -> {}
}
mishap.execute(harness.ctx, errorCtx, harness.stack)
return true
}

View file

@ -23,9 +23,7 @@ import at.petrak.hexcasting.common.casting.operators.spells.sentinel.OpCreateSen
import at.petrak.hexcasting.common.casting.operators.spells.sentinel.OpDestroySentinel;
import at.petrak.hexcasting.common.casting.operators.spells.sentinel.OpGetSentinelPos;
import at.petrak.hexcasting.common.casting.operators.spells.sentinel.OpGetSentinelWayfind;
import at.petrak.hexcasting.common.items.magic.ItemArtifact;
import at.petrak.hexcasting.common.items.magic.ItemCypher;
import at.petrak.hexcasting.common.items.magic.ItemTrinket;
import at.petrak.hexcasting.common.items.HexItems;
import at.petrak.hexcasting.hexmath.HexDir;
import at.petrak.hexcasting.hexmath.HexPattern;
import net.minecraft.world.effect.MobEffects;
@ -164,14 +162,14 @@ public class RegisterPatterns {
new OpErase());
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waqqqqq", HexDir.EAST), prefix("craft/cypher"),
new OpMakePackagedSpell<>(ItemCypher.class, 100_000));
new OpMakePackagedSpell<>(HexItems.CYPHER.get(), 100_000));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wwaqqqqqeaqeaeqqqeaeq", HexDir.EAST),
prefix("craft/trinket"),
new OpMakePackagedSpell<>(ItemTrinket.class, 500_000));
new OpMakePackagedSpell<>(HexItems.TRINKET.get(), 500_000));
PatternRegistry.mapPattern(
HexPattern.FromAnglesSig("wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq", HexDir.EAST),
prefix("craft/artifact"),
new OpMakePackagedSpell<>(ItemArtifact.class, 1_000_000));
new OpMakePackagedSpell<>(HexItems.ARTIFACT.get(), 1_000_000));
PatternRegistry.mapPattern(
HexPattern.FromAnglesSig("aqqqaqwwaqqqqqeqaqqqawwqwqwqwqwqw", HexDir.SOUTH_WEST),
prefix("craft/battery"),

View file

@ -5,19 +5,22 @@ import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import at.petrak.hexcasting.common.items.HexItems
import at.petrak.hexcasting.hexmath.HexPattern
import net.minecraft.Util
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.DyeColor
import java.util.regex.Pattern
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
sealed class Mishap : Throwable() {
/** Mishaps spray half-red, half-this-color. */
abstract fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer
open fun particleSpray(ctx: CastingContext): ParticleSpray {
return ParticleSpray.Burst(ctx.position, 0.5)
return ParticleSpray(ctx.position.add(0.0, 0.2, 0.0), Vec3(0.0, 2.0, 0.0), 0.2, Math.PI / 4, 40)
}
/**
@ -35,8 +38,21 @@ sealed class Mishap : Throwable() {
protected fun error(stub: String, vararg args: Any): Component =
TranslatableComponent("hexcasting.mishap.$stub", *args)
protected fun actionName(action: ResourceLocation): Component =
TranslatableComponent("hexcasting.spell.$action")
protected fun actionName(action: ResourceLocation?): Component =
TranslatableComponent("hexcasting.spell.${action ?: "unknown"}")
data class Context(val pattern: Pattern, val action: ResourceLocation?)
protected fun yeetItem(stack: ItemStack, ctx: CastingContext, delta: Vec3) {
val entity = ItemEntity(
ctx.world,
ctx.position.x, ctx.position.y, ctx.position.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)
ctx.world.addWithUUID(entity)
}
data class Context(val pattern: HexPattern, val action: ResourceLocation?)
}

View file

@ -0,0 +1,27 @@
package at.petrak.hexcasting.common.casting.mishaps
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import at.petrak.hexcasting.common.lib.HexDamageSources
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.item.DyeColor
class MishapAlreadyBrainswept(val villager: Villager) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.LIME)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<SpellDatum<*>>) {
villager.hurt(HexDamageSources.OVERCAST, villager.health)
}
override fun particleSpray(ctx: CastingContext): ParticleSpray {
return ParticleSpray.Burst(villager.eyePosition, 1.0)
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("already_brainswept")
}

View file

@ -1,5 +1,6 @@
package at.petrak.hexcasting.common.casting.mishaps
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
@ -8,6 +9,7 @@ import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.item.DyeColor
import net.minecraft.world.phys.Vec3
class MishapBadBrainsweep(val villager: Villager, val pos: BlockPos) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
@ -17,6 +19,10 @@ class MishapBadBrainsweep(val villager: Villager, val pos: BlockPos) : Mishap()
villager.hurt(HexDamageSources.OVERCAST, villager.health)
}
override fun particleSpray(ctx: CastingContext): ParticleSpray {
return ParticleSpray.Burst(Vec3.atCenterOf(pos), 1.0)
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component {
val bs = ctx.world.getBlockState(this.pos)
return error("bad_brainsweep", bs.block.name)

View file

@ -17,7 +17,7 @@ class MishapBadItem(val item: ItemStack, val wanted: Component) : Mishap() {
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("bad_item", actionName(errorCtx.action!!), wanted, item)
error("bad_item", actionName(errorCtx.action), wanted, item)
companion object {
@JvmStatic

View file

@ -5,7 +5,6 @@ import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack
@ -17,16 +16,12 @@ class MishapBadOffhandItem(val item: ItemStack, val wanted: Component) : Mishap(
val item = ctx.caster.getItemInHand(ctx.otherHand).copy()
ctx.caster.setItemInHand(ctx.otherHand, ItemStack.EMPTY.copy())
val delta = ctx.caster.lookAngle
val entity = ItemEntity(
ctx.world, ctx.caster.x, ctx.caster.eyeY, ctx.caster.z, item,
delta.x, delta.y, delta.z
)
ctx.world.addWithUUID(entity)
val delta = ctx.caster.lookAngle.scale(0.5)
yeetItem(item, ctx, delta)
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("bad_item.offhand", actionName(errorCtx.action!!), wanted, item)
error("bad_item.offhand", actionName(errorCtx.action), wanted, item.count, item.displayName)
companion object {
@JvmStatic

View file

@ -6,7 +6,6 @@ import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import net.minecraft.network.chat.Component
import net.minecraft.world.InteractionHand
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack
@ -24,19 +23,13 @@ class MishapEntityTooFarAway(val entity: Entity) : Mishap() {
ctx.caster.setItemInHand(hand, ItemStack.EMPTY.copy())
}
val delta = entity.position().subtract(ctx.position).normalize().scale(2.0)
val delta = entity.position().subtract(ctx.position).normalize().scale(0.5)
for (item in items) {
val entity = ItemEntity(
ctx.world,
ctx.position.x, ctx.position.y, ctx.position.z,
item,
delta.x, delta.y, delta.z
)
ctx.world.addWithUUID(entity)
yeetItem(item, ctx, delta)
}
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("entity_too_far", SpellDatum.make(entity).display(), actionName(errorCtx.action!!))
error("entity_too_far", SpellDatum.make(entity).display(), actionName(errorCtx.action))
}

View file

@ -1,5 +1,6 @@
package at.petrak.hexcasting.common.casting.mishaps
import at.petrak.hexcasting.HexMod
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.Widget
@ -18,32 +19,32 @@ import net.minecraft.world.phys.Vec3
/**
* The value failed some kind of predicate.
*
* [MishapInvalidIota.idx] is the absolute index in the stack.
* [MishapInvalidIota.reverseIdx] is the index from the *back* of the stack.
*/
class MishapInvalidIota(
val perpetrator: SpellDatum<*>,
val idx: Int,
val expectedKey: String
val reverseIdx: Int,
val expected: Component
) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.GRAY)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<SpellDatum<*>>) {
stack[idx] = SpellDatum.make(Widget.GARBAGE)
stack[stack.size - 1 - reverseIdx] = SpellDatum.make(Widget.GARBAGE)
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error(
"invalid_value",
actionName(errorCtx.action!!),
idx,
TranslatableComponent(expectedKey),
actionName(errorCtx.action),
reverseIdx,
expected,
perpetrator.display()
)
companion object {
@JvmStatic
fun ofClass(perpetrator: SpellDatum<*>, idx: Int, cls: Class<*>): MishapInvalidIota {
fun ofClass(perpetrator: SpellDatum<*>, reverseIdx: Int, cls: Class<*>): MishapInvalidIota {
val key = "hexcasting.mishap.invalid_value.class." + when {
Double::class.java.isAssignableFrom(cls) -> "double"
Vec3::class.java.isAssignableFrom(cls) -> "vector"
@ -57,9 +58,12 @@ class MishapInvalidIota(
LivingEntity::class.java.isAssignableFrom(cls) -> "entity.living"
Entity::class.java.isAssignableFrom(cls) -> "entity"
else -> "unknown"
else -> {
HexMod.getLogger().warn("tried to call MishapInvalidData.ofClass with class $cls")
"unknown"
}
}
return MishapInvalidIota(perpetrator, idx, key)
return MishapInvalidIota(perpetrator, reverseIdx, TranslatableComponent(key))
}
}
}

View file

@ -5,7 +5,6 @@ import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import net.minecraft.network.chat.Component
import net.minecraft.world.InteractionHand
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
@ -24,16 +23,10 @@ class MishapLocationTooFarAway(val location: Vec3) : Mishap() {
ctx.caster.setItemInHand(hand, ItemStack.EMPTY.copy())
}
val delta = location.subtract(ctx.position).normalize().scale(2.0)
val delta = location.subtract(ctx.position).normalize().scale(0.5)
for (item in items) {
val entity = ItemEntity(
ctx.world,
ctx.position.x, ctx.position.y, ctx.position.z,
item,
delta.x, delta.y, delta.z
)
ctx.world.addWithUUID(entity)
yeetItem(item, ctx, delta)
}
}

View file

@ -15,5 +15,5 @@ class MishapNoSpellCircle : Mishap() {
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("no_spell_circle", actionName(errorCtx.action!!))
error("no_spell_circle", actionName(errorCtx.action))
}

View file

@ -17,5 +17,5 @@ class MishapNotEnoughArgs(val expected: Int, val got: Int) : Mishap() {
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("not_enough_args", actionName(errorCtx.action!!), expected, got)
error("not_enough_args", actionName(errorCtx.action), expected, got)
}

View file

@ -3,16 +3,15 @@ package at.petrak.hexcasting.common.casting.mishaps
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.colors.FrozenColorizer
import at.petrak.hexcasting.hexmath.HexPattern
import net.minecraft.network.chat.Component
import net.minecraft.world.item.DyeColor
class MishapTooManyCloseParens(val paren: HexPattern) : Mishap() {
class MishapTooManyCloseParens : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.PINK)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<SpellDatum<*>>) {
stack.add(SpellDatum.make(paren))
stack.add(SpellDatum.make(errorCtx.pattern))
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =

View file

@ -4,9 +4,12 @@ import at.petrak.hexcasting.api.spell.OperationResult
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.OperatorSideEffect
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidIota
import at.petrak.hexcasting.common.casting.mishaps.MishapNotEnoughArgs
import net.minecraft.network.chat.TranslatableComponent
import kotlin.math.abs
object OpFisherman : Operator {
val manaCost: Int
@ -14,16 +17,21 @@ object OpFisherman : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
if (stack.isEmpty())
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, 1, stack.size)
val arg = stack.takeLast(1).getChecked<Double>(0)
throw MishapNotEnoughArgs(1, 0)
val arg = stack.getChecked<Double>(stack.lastIndex)
val datum = stack[stack.lastIndex]
val distance = stack.size - (arg + 1) // because getChecked<Int> just gives me a double for some reason
stack.removeLast()
if (distance < stack.size && Math.abs(distance.toInt() - distance) < 0.05f) {
if (distance < stack.size && abs(distance.toInt() - distance) < 0.05f) {
val fish = stack[distance.toInt()]
stack.removeAt(distance.toInt())
stack.add(stack.size, fish)
} else {
throw CastException(CastException.Reason.INVALID_VALUE, "integer less than " + stack.size + " but greater than 0", arg)
throw MishapInvalidIota(
datum,
0,
TranslatableComponent("hexcasting.mishap.invalid_value.fisherman", stack.size)
)
}
val sideEffects = mutableListOf<OperatorSideEffect>(OperatorSideEffect.ConsumeMana(this.manaCost))

View file

@ -3,15 +3,20 @@ package at.petrak.hexcasting.common.casting.operators
import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.Widget
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.items.ItemDataHolder
object OpRead : ConstManaOperator {
override val argc = 0
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val dataer = ctx.getDataHolder()
val datum = (dataer.item as ItemDataHolder).readDatum(dataer, ctx)
return listOf(datum ?: SpellDatum.make(Widget.NULL))
val handStack =
ctx.caster.getItemInHand(ctx.otherHand)
val handItem = handStack.item
if (handItem !is ItemDataHolder) {
throw MishapBadOffhandItem.of(handStack, "iota.read")
}
val datum = handItem.readDatum(handStack, ctx) ?: throw MishapBadOffhandItem.of(handStack, "iota.read")
return listOf(datum)
}
}

View file

@ -3,9 +3,8 @@ package at.petrak.hexcasting.common.casting.operators
import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.Widget
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.items.ItemDataHolder
import net.minecraft.world.entity.item.ItemEntity
@ -17,14 +16,15 @@ object OpTheCoolerRead : ConstManaOperator {
ctx: CastingContext
): List<SpellDatum<*>> {
val target = args.getChecked<ItemEntity>(0)
if (target.item.item !is ItemDataHolder) {
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, ItemDataHolder::class.java, target.item)
val stack = target.item
val item = stack.item
if (item !is ItemDataHolder) {
throw MishapBadOffhandItem.of(stack, "iota.read")
}
ctx.assertEntityInRange(target)
val stack = target.item
val item = stack.item as ItemDataHolder
val datum = item.readDatum(stack, ctx) ?: SpellDatum.make(Widget.NULL)
val datum = item.readDatum(stack, ctx) ?: throw MishapBadOffhandItem.of(stack, "iota.read")
return listOf(datum)
}
}

View file

@ -5,8 +5,9 @@ import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.casting.mishaps.MishapOthersName
import at.petrak.hexcasting.common.items.HexItems
import at.petrak.hexcasting.common.items.ItemDataHolder
import at.petrak.hexcasting.common.items.ItemScroll
@ -26,7 +27,7 @@ object OpWrite : SpellOperator {
val datum = args[0]
val canWrite = if (handItem is ItemDataHolder) {
true
handItem.canWrite(tag, datum)
} else if (datum.payload is HexPattern) {
if (handStack.`is`(HexItems.SCROLL.get()) && !tag.contains(ItemScroll.TAG_PATTERN)) {
true
@ -44,10 +45,10 @@ object OpWrite : SpellOperator {
false
}
if (!canWrite)
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, ItemDataHolder::class.java, handStack)
throw MishapBadOffhandItem.of(handStack, "iota.write")
if (datum.payload is Player && datum.payload != ctx.caster)
throw CastException(CastException.Reason.NO_WRITING_OTHER_NAMES)
throw MishapOthersName(datum.payload)
return Triple(
Spell(datum),

View file

@ -3,8 +3,8 @@ package at.petrak.hexcasting.common.casting.operators.circles
import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.mishaps.MishapNoSpellCircle
import net.minecraft.world.phys.Vec3
class OpCircleBounds(val max: Boolean) : ConstManaOperator {
@ -12,7 +12,7 @@ class OpCircleBounds(val max: Boolean) : ConstManaOperator {
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
if (ctx.spellCircle == null)
throw CastException(CastException.Reason.NO_SPELL_CIRCLE)
throw MishapNoSpellCircle()
val aabb = ctx.spellCircle.aabb

View file

@ -1,11 +1,11 @@
package at.petrak.hexcasting.common.casting.operators.circles
import at.petrak.hexcasting.api.circle.BlockAbstractImpetus
import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.circle.BlockAbstractImpetus
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.mishaps.MishapNoSpellCircle
import net.minecraft.world.phys.Vec3
object OpImpetusDir : ConstManaOperator {
@ -13,7 +13,7 @@ object OpImpetusDir : ConstManaOperator {
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
if (ctx.spellCircle == null)
throw CastException(CastException.Reason.NO_SPELL_CIRCLE)
throw MishapNoSpellCircle()
val pos = ctx.spellCircle.impetusPos
val bs = ctx.world.getBlockState(pos)

View file

@ -3,8 +3,8 @@ package at.petrak.hexcasting.common.casting.operators.circles
import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.mishaps.MishapNoSpellCircle
import net.minecraft.world.phys.Vec3
object OpImpetusPos : ConstManaOperator {
@ -12,7 +12,7 @@ object OpImpetusPos : ConstManaOperator {
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
if (ctx.spellCircle == null)
throw CastException(CastException.Reason.NO_SPELL_CIRCLE)
throw MishapNoSpellCircle()
return Operator.spellListOf(Vec3.atCenterOf(ctx.spellCircle.impetusPos))
}

View file

@ -7,6 +7,9 @@ import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.CastingHarness
import at.petrak.hexcasting.common.casting.OperatorSideEffect
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidIota
import at.petrak.hexcasting.hexmath.HexPattern
import net.minecraft.network.chat.TranslatableComponent
object OpEval : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
@ -20,9 +23,14 @@ object OpEval : Operator {
val sideEffects = mutableListOf<OperatorSideEffect>()
for (pat in instrs) {
val res = harness.getUpdate(pat.tryGet(), ctx.world)
val pattern = if (pat.payload is HexPattern) {
pat.payload
} else {
throw MishapInvalidIota(pat, 0, TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern"))
}
val res = harness.getUpdate(pattern, ctx.world)
sideEffects.addAll(res.sideEffects)
if (res.sideEffects.any { it is OperatorSideEffect.Mishap }) {
if (res.sideEffects.any { it is OperatorSideEffect.DoMishap }) {
break
}
harness.applyFunctionalData(res.newData)

View file

@ -4,15 +4,18 @@ import at.petrak.hexcasting.api.spell.OperationResult
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.CastingHarness
import at.petrak.hexcasting.common.casting.OperatorSideEffect
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidIota
import at.petrak.hexcasting.common.casting.mishaps.MishapNotEnoughArgs
import at.petrak.hexcasting.hexmath.HexPattern
import net.minecraft.network.chat.TranslatableComponent
object OpForEach : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
if (stack.size < 2)
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, 2, stack.size)
throw MishapNotEnoughArgs(2, stack.size)
val instrs: List<SpellDatum<*>> = stack.getChecked(stack.lastIndex - 1)
val datums: List<SpellDatum<*>> = stack.getChecked(stack.lastIndex)
@ -28,9 +31,18 @@ object OpForEach : Operator {
harness.stack.addAll(stack)
harness.stack.add(subdatum)
for (pat in instrs) {
val res = harness.getUpdate(pat.tryGet(), ctx.world)
val pattern = if (pat.payload is HexPattern) {
pat.payload
} else {
throw MishapInvalidIota(
pat,
1,
TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern")
)
}
val res = harness.getUpdate(pattern, ctx.world)
sideEffects.addAll(res.sideEffects)
if (res.sideEffects.any { it is OperatorSideEffect.Mishap }) {
if (res.sideEffects.any { it is OperatorSideEffect.DoMishap }) {
break
}
harness.applyFunctionalData(res.newData)

View file

@ -5,9 +5,11 @@ import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.Operator.Companion.getChecked
import at.petrak.hexcasting.api.spell.Operator.Companion.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.OperatorSideEffect
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidIota
import at.petrak.hexcasting.common.casting.mishaps.MishapNotEnoughArgs
import net.minecraft.network.chat.TranslatableComponent
object OpLastNToList : Operator {
val manaCost: Int
@ -15,13 +17,18 @@ object OpLastNToList : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
if (stack.isEmpty())
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, 1, stack.size)
throw MishapNotEnoughArgs(1, 0)
val arg = stack.takeLast(1).getChecked<Double>(0)
val datum = stack[stack.lastIndex]
stack.removeLast()
if (arg < 0) {
throw CastException(CastException.Reason.INVALID_VALUE, "integer greater than 0", arg)
if (arg < 0 || arg >= stack.size) {
throw MishapInvalidIota(
datum,
0,
TranslatableComponent("hexcasting.mishap.invalid_value.fisherman", stack.size)
)
}
val output = emptyList<SpellDatum<*>>().toMutableList()
val output = mutableListOf<SpellDatum<*>>()
output.addAll(stack.takeLast(arg.toInt()))
val endSize = stack.size - output.toList().size
while (stack.size != endSize) {

View file

@ -1,15 +1,20 @@
package at.petrak.hexcasting.common.casting.operators.math
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidIota
import com.mojang.datafixers.util.Either
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.phys.Vec3
object MathOpUtils {
fun GetNumOrVec(datum: SpellDatum<*>): Either<Double, Vec3> =
fun GetNumOrVec(datum: SpellDatum<*>, reverseIdx: Int): Either<Double, Vec3> =
when (datum.payload) {
is Double -> Either.left(datum.payload)
is Vec3 -> Either.right(datum.payload)
else -> throw CastException(CastException.Reason.OP_WRONG_TYPE, Either::class.java, datum.payload)
else -> throw MishapInvalidIota(
datum,
reverseIdx,
TranslatableComponent("hexcasting.mishap.invalid_value.numvec")
)
}
}

View file

@ -11,7 +11,7 @@ object OpAbsLen : ConstManaOperator {
get() = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val x = MathOpUtils.GetNumOrVec(args[0])
val x = MathOpUtils.GetNumOrVec(args[0], 0)
return spellListOf(
x.map({ num -> num.absoluteValue }, { vec -> vec.length() })

View file

@ -10,8 +10,8 @@ object OpAdd : ConstManaOperator {
get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = MathOpUtils.GetNumOrVec(args[0])
val rhs = MathOpUtils.GetNumOrVec(args[1])
val lhs = MathOpUtils.GetNumOrVec(args[0], 1)
val rhs = MathOpUtils.GetNumOrVec(args[1], 0)
return spellListOf(
lhs.map({ lnum ->

View file

@ -11,8 +11,8 @@ object OpDivCross : ConstManaOperator {
get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = MathOpUtils.GetNumOrVec(args[0])
val rhs = MathOpUtils.GetNumOrVec(args[1])
val lhs = MathOpUtils.GetNumOrVec(args[0], 1)
val rhs = MathOpUtils.GetNumOrVec(args[1], 0)
return spellListOf(
lhs.map({ lnum ->

View file

@ -10,8 +10,8 @@ object OpMulDot : ConstManaOperator {
get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = MathOpUtils.GetNumOrVec(args[0])
val rhs = MathOpUtils.GetNumOrVec(args[1])
val lhs = MathOpUtils.GetNumOrVec(args[0], 1)
val rhs = MathOpUtils.GetNumOrVec(args[1], 0)
return spellListOf(
lhs.map({ lnum ->

View file

@ -12,8 +12,8 @@ object OpPowProj : ConstManaOperator {
get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = MathOpUtils.GetNumOrVec(args[0])
val rhs = MathOpUtils.GetNumOrVec(args[1])
val lhs = MathOpUtils.GetNumOrVec(args[0], 1)
val rhs = MathOpUtils.GetNumOrVec(args[1], 0)
return spellListOf(
lhs.map({ lnum ->

View file

@ -11,8 +11,8 @@ object OpSub : ConstManaOperator {
get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = MathOpUtils.GetNumOrVec(args[0])
val rhs = MathOpUtils.GetNumOrVec(args[1])
val lhs = MathOpUtils.GetNumOrVec(args[0], 1)
val rhs = MathOpUtils.GetNumOrVec(args[1], 0)
return spellListOf(
lhs.map({ lnum ->

View file

@ -4,8 +4,8 @@ import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.items.magic.ItemPackagedSpell
class OpErase : SpellOperator {
@ -17,7 +17,7 @@ class OpErase : SpellOperator {
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val otherHandItem = ctx.caster.getItemInHand(ctx.otherHand)
if (otherHandItem.item !is ItemPackagedSpell) {
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, ItemPackagedSpell::class.java, otherHandItem)
throw MishapBadOffhandItem.of(otherHandItem, "eraseable")
}
return Triple(Spell, 10_000, listOf())

View file

@ -5,9 +5,9 @@ import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.ManaHelper
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.items.HexItems
import at.petrak.hexcasting.common.items.magic.ItemManaHolder
import net.minecraft.world.entity.item.ItemEntity
@ -24,14 +24,27 @@ object OpMakeBattery : SpellOperator {
val otherHandItem = ctx.caster.getItemInHand(ctx.otherHand)
if (otherHandItem.item != Items.GLASS_BOTTLE) {
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM_ITEM, Items.GLASS_BOTTLE, otherHandItem)
throw MishapBadOffhandItem.of(
otherHandItem,
"bottle"
)
}
if (otherHandItem.count != 1) {
throw CastException(CastException.Reason.BAD_OFFHAND_COUNT, 1, otherHandItem.count)
throw MishapBadOffhandItem.of(
otherHandItem,
"only_one"
)
}
ctx.assertEntityInRange(entity)
if (!ManaHelper.isManaItem(entity.item)) {
throw MishapBadOffhandItem.of(
otherHandItem,
"mana"
)
}
return Triple(Spell(entity), 100_000, listOf(ParticleSpray.Burst(entity.position(), 0.5)))
}

View file

@ -5,29 +5,42 @@ import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.ManaHelper
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.casting.mishaps.MishapInvalidIota
import at.petrak.hexcasting.common.items.magic.ItemPackagedSpell
import at.petrak.hexcasting.hexmath.HexPattern
import net.minecraft.nbt.ListTag
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.item.ItemEntity
class OpMakePackagedSpell<T : ItemPackagedSpell>(val type: Class<T>, val cost: Int) : SpellOperator {
class OpMakePackagedSpell<T : ItemPackagedSpell>(val itemType: T, val cost: Int) : SpellOperator {
override val argc = 2
override fun execute(
args: List<SpellDatum<*>>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val entity = args.getChecked<ItemEntity>(0)
val patterns = args.getChecked<List<SpellDatum<*>>>(1).map { it.tryGet<HexPattern>() }
val patterns = args.getChecked<List<SpellDatum<*>>>(1).map {
if (it.payload is HexPattern)
it.payload
else
throw MishapInvalidIota(it, 0, TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern"))
}
val otherHandItem = ctx.caster.getItemInHand(ctx.otherHand)
if (!type.isAssignableFrom(otherHandItem.item.javaClass)) {
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, type, otherHandItem)
if (!otherHandItem.`is`(itemType)) {
throw MishapBadOffhandItem(otherHandItem, itemType.description)
}
ctx.assertEntityInRange(entity)
if (!ManaHelper.isManaItem(entity.item)) {
throw MishapBadOffhandItem.of(
otherHandItem,
"mana"
)
}
return Triple(Spell(entity, patterns), cost, listOf(ParticleSpray.Burst(entity.position(), 0.5)))
}

View file

@ -4,15 +4,15 @@ import at.petrak.hexcasting.api.spell.OperationResult
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.OperatorSideEffect
import at.petrak.hexcasting.common.casting.mishaps.MishapNotEnoughArgs
import net.minecraft.Util
object OpPrint : Operator {
override fun operate(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): OperationResult {
if (stack.isEmpty()) {
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, 1, stack.size)
throw MishapNotEnoughArgs(1, 0)
}
val datum = stack[stack.lastIndex]
return OperationResult(

View file

@ -5,9 +5,9 @@ import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.ManaHelper
import at.petrak.hexcasting.common.casting.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.common.items.magic.ItemManaHolder
import net.minecraft.util.Mth
import net.minecraft.world.entity.item.ItemEntity
@ -20,12 +20,22 @@ object OpRecharge : SpellOperator {
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val otherHandItem = ctx.caster.getItemInHand(ctx.otherHand)
if (otherHandItem.item !is ItemManaHolder) {
throw CastException(CastException.Reason.BAD_OFFHAND_ITEM, ItemManaHolder::class.java, otherHandItem)
throw MishapBadOffhandItem.of(
otherHandItem,
"rechargable"
)
}
val entity = args.getChecked<ItemEntity>(0)
ctx.assertEntityInRange(entity)
if (!ManaHelper.isManaItem(entity.item)) {
throw MishapBadOffhandItem.of(
otherHandItem,
"mana"
)
}
return Triple(Spell(entity), 100_000, listOf(ParticleSpray.Burst(entity.position(), 0.5)))
}

View file

@ -5,8 +5,9 @@ import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.common.casting.CastException
import at.petrak.hexcasting.common.casting.CastingContext
import at.petrak.hexcasting.common.casting.mishaps.MishapAlreadyBrainswept
import at.petrak.hexcasting.common.casting.mishaps.MishapBadBrainsweep
import at.petrak.hexcasting.common.misc.Brainsweeping
import at.petrak.hexcasting.common.recipe.BrainsweepRecipe
import at.petrak.hexcasting.common.recipe.HexRecipeSerializers
@ -29,7 +30,7 @@ object OpBrainsweep : SpellOperator {
ctx.assertEntityInRange(sacrifice)
if (Brainsweeping.isBrainswept(sacrifice))
throw CastException(CastException.Reason.RECIPE_DIDNT_WORK)
throw MishapAlreadyBrainswept(sacrifice)
val bpos = BlockPos(pos)
val state = ctx.world.getBlockState(bpos)
@ -37,7 +38,7 @@ object OpBrainsweep : SpellOperator {
val recman = ctx.world.recipeManager
val recipes = recman.getAllRecipesFor(HexRecipeSerializers.BRAINSWEEP_TYPE)
val recipe = recipes.find { it.matches(state, sacrifice) }
?: throw CastException(CastException.Reason.RECIPE_DIDNT_WORK)
?: throw MishapBadBrainsweep(sacrifice, bpos)
return Triple(
Spell(bpos, sacrifice, recipe),

View file

@ -32,6 +32,11 @@ public class ItemAbacus extends ItemDataHolder {
return datum.serializeToNBT();
}
@Override
public boolean canWrite(CompoundTag tag, SpellDatum<?> datum) {
return false;
}
@Override
public void writeDatum(CompoundTag tag, SpellDatum<?> datum) {
// nope

View file

@ -36,8 +36,12 @@ abstract public class ItemDataHolder extends Item {
}
}
public abstract boolean canWrite(CompoundTag tag, SpellDatum<?> datum);
public abstract void writeDatum(CompoundTag tag, SpellDatum<?> datum);
@Override
public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List<Component> pTooltipComponents,
TooltipFlag pIsAdvanced) {

View file

@ -29,6 +29,11 @@ public class ItemFocus extends ItemDataHolder {
return tag.getCompound(TAG_DATA);
}
@Override
public boolean canWrite(CompoundTag tag, SpellDatum<?> datum) {
return !tag.getBoolean(TAG_SEALED);
}
@Override
public void writeDatum(CompoundTag tag, SpellDatum<?> datum) {
if (!tag.getBoolean(TAG_SEALED)) {

View file

@ -82,6 +82,11 @@ public class ItemSpellbook extends ItemDataHolder {
}
}
@Override
public boolean canWrite(CompoundTag tag, SpellDatum<?> datum) {
return true;
}
public void writeDatum(CompoundTag tag, SpellDatum<?> datum) {
int idx;
if (tag.contains(TAG_SELECTED_PAGE)) {

View file

@ -11,6 +11,7 @@ import at.petrak.paucal.api.datagen.PaucalItemModelProvider;
import com.mojang.datafixers.util.Pair;
import net.minecraft.data.DataGenerator;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.Item;
import net.minecraftforge.client.model.generators.ModelFile;
import net.minecraftforge.common.data.ExistingFileHelper;
@ -104,8 +105,9 @@ public class HexItemModels extends PaucalItemModelProvider {
}
}
for (int i = 0; i < 16; i++) {
singleTexture(HexItems.DYE_COLORIZERS[i].getId().getPath(), new ResourceLocation("item/generated"),
for (int i = 0; i < DyeColor.values().length; i++) {
singleTexture(HexItems.DYE_COLORIZERS.get(DyeColor.values()[i]).getId().getPath(),
new ResourceLocation("item/generated"),
"layer0", new ResourceLocation(HexMod.MOD_ID, "item/colorizer/dye" + i));
}
for (int i = 0; i < 14; i++) {

View file

@ -105,12 +105,12 @@ public class HexRecipes extends PaucalRecipeProvider {
.pattern(" B ")
.unlockedBy("has_item", has(Items.AMETHYST_SHARD)).save(recipes);
for (var dyeColorizer : HexItems.DYE_COLORIZERS) {
var item = dyeColorizer.get();
for (var dye : DyeColor.values()) {
var item = HexItems.DYE_COLORIZERS.get(dye).get();
ShapedRecipeBuilder.shaped(item)
.define('B', Items.BOWL)
.define('D', HexItems.AMETHYST_DUST.get())
.define('C', DyeItem.byColor(DyeColor.values()[item.getDyeIdx()]))
.define('C', DyeItem.byColor(dye))
.pattern(" C ")
.pattern(" D ")
.pattern(" B ")

View file

@ -247,10 +247,11 @@
"hexcasting.spell.hexcasting:const/vec/ny": "Vector Reflection -Y",
"hexcasting.spell.hexcasting:const/vec/nz": "Vector Reflection -Z",
"hexcasting.spell.hexcasting:const/vec/0": "Vector Reflection Zero",
"hexcasting.spell.unknown": "Special Handler",
"hexcasting.mishap.invalid_pattern": "That pattern isn't associated with any action.",
"hexcasting.mishap.invalid_pattern": "That pattern isn't associated with any action",
"hexcasting.mishap.invalid_spell_datum_type": "Tried to use a value of invalid type as a SpellDatum: %s (class %s). This is a bug in the mod.",
"hexcasting.mishap.invalid_value": "%s expected %s at index %s, but got %s",
"hexcasting.mishap.invalid_value": "%s expected %s at index %s of the stack, but got %s",
"hexcasting.mishap.invalid_value.class.double": "a number",
"hexcasting.mishap.invalid_value.class.vector": "a vector",
"hexcasting.mishap.invalid_value.class.list": "a list",
@ -261,18 +262,27 @@
"hexcasting.mishap.invalid_value.class.entity.villager": "a villager",
"hexcasting.mishap.invalid_value.class.entity.living": "a living entity",
"hexcasting.mishap.invalid_value.class.entity": "an entity",
"hexcasting.mishap.not_enough_args": "%s expected %s arguments but the stack was only %s tall",
"hexcasting.mishap.invalid_value.class.unknown": "(unknown, uh-oh, this is a bug)",
"hexcasting.mishap.invalid_value.numvec": "a number or vector",
"hexcasting.mishap.invalid_value.list.pattern": "a list of patterns",
"hexcasting.mishap.invalid_value.fisherman": "an integer between 0 and %d",
"hexcasting.mishap.not_enough_args": "%s expected %s or more arguments but the stack was only %s tall",
"hexcasting.mishap.too_many_close_parens": "Used Retrospection without first using Introspection",
"hexcasting.mishap.location_too_far": "%s is out of range for %s",
"hexcasting.mishap.entity_too_far": "%s is out of range for %s",
"hexcasting.mishap.eval_too_deep": "Recursively evaluated too deep",
"hexcasting.mishap.bad_item": "%s needs %s but got %s",
"hexcasting.mishap.bad_item.offhand": "%s needs %s in the other hand but got %s",
"hexcasting.mishap.bad_item.offhand": "%s needs %s in the other hand but got %dx %s",
"hexcasting.mishap.bad_item.iota": "a place to store iotas",
"hexcasting.mishap.bad_item.iota.read": "a place to read iotas from",
"hexcasting.mishap.bad_item.iota.write": "a place to write iotas to",
"hexcasting.mishap.bad_item.media": "a media-containing item",
"hexcasting.mishap.bad_item.mana": "a media-containing item",
"hexcasting.mishap.bad_item.only_one": "exactly one item",
"hexcasting.mishap.bad_item.eraseable": "an eraseable item",
"hexcasting.mishap.bad_item.bottle": "a glass bottle",
"hexcasting.mishap.bad_item.rechargable": "a rechargable item",
"hexcasting.mishap.bad_brainsweep": "The %s rejected the villager's mind",
"hexcasting.mishap.already_brainswept": "The villager has already been used",
"hexcasting.mishap.no_spell_circle": "%s requires a spell circle",
"hexcasting.mishap.others_name": "Tried to invade %s's privacy",