do spells and finish up the harness ... now onto blocks!

This commit is contained in:
gamma-delta 2022-06-14 02:11:38 -05:00
parent 2917a3b358
commit 8b7369fe8b
59 changed files with 408 additions and 320 deletions

View file

@ -2,8 +2,14 @@ package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect
import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.iota.Iota
/** /**
* What happens when an operator is through? * What happens when an operator is through?
*/ */
data class OperationResult(val newContinuation: SpellContinuation, val newStack: List<Iota>, val newLocalIota: Iota, val sideEffects: List<OperatorSideEffect>) data class OperationResult(
val newContinuation: SpellContinuation,
val newStack: List<Iota>,
val newLocalIota: Iota,
val sideEffects: List<OperatorSideEffect>
)

View file

@ -12,6 +12,7 @@ import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.decoration.ArmorStand
import net.minecraft.world.entity.item.ItemEntity import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -98,11 +99,11 @@ fun List<Iota>.getVillager(idx: Int, argc: Int = 0): Villager {
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.villager") throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.villager")
} }
fun List<Iota>.getLivingEntity(idx: Int, argc: Int = 0): LivingEntity { fun List<Iota>.getLivingEntityButNotArmorStand(idx: Int, argc: Int = 0): LivingEntity {
val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) }
if (x is EntityIota) { if (x is EntityIota) {
val e = x.entity val e = x.entity
if (e is LivingEntity) if (e is LivingEntity && e !is ArmorStand)
return e return e
} }
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.living") throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.living")
@ -119,6 +120,17 @@ fun List<Iota>.getPositiveDouble(idx: Int, argc: Int = 0): Double {
throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "double.positive") throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "double.positive")
} }
fun List<Iota>.getPositiveDoubleUnder(idx: Int, max: Double, argc: Int = 0): Double {
val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) }
if (x is DoubleIota) {
val double = x.double
if (double in 0.0..max) {
return double
}
}
throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "double.positive.lessthan", max)
}
fun List<Iota>.getDoubleBetween(idx: Int, min: Double, max: Double, argc: Int = 0): Double { fun List<Iota>.getDoubleBetween(idx: Int, min: Double, max: Double, argc: Int = 0): Double {
val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) }
if (x is DoubleIota) { if (x is DoubleIota) {

View file

@ -3,6 +3,7 @@ package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect
import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
interface SpellAction : Action { interface SpellAction : Action {
@ -17,7 +18,12 @@ interface SpellAction : Action {
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>? ): Triple<RenderedSpell, Int, List<ParticleSpray>>?
override fun operate(continuation: SpellContinuation, stack: MutableList<Iota>, local: Iota, ctx: CastingContext): OperationResult { override fun operate(
continuation: SpellContinuation,
stack: MutableList<Iota>,
local: Iota,
ctx: CastingContext
): OperationResult {
if (this.argc > stack.size) if (this.argc > stack.size)
throw MishapNotEnoughArgs(this.argc, stack.size) throw MishapNotEnoughArgs(this.argc, stack.size)
val args = stack.takeLast(this.argc) val args = stack.takeLast(this.argc)
@ -32,7 +38,13 @@ interface SpellAction : Action {
// Don't have an effect if the caster isn't enlightened, even if processing other side effects // Don't have an effect if the caster isn't enlightened, even if processing other side effects
if (!isGreat || ctx.isCasterEnlightened) if (!isGreat || ctx.isCasterEnlightened)
sideEffects.add(OperatorSideEffect.AttemptSpell(spell, this.hasCastingSound(ctx), this.awardsCastingStat(ctx))) sideEffects.add(
OperatorSideEffect.AttemptSpell(
spell,
this.hasCastingSound(ctx),
this.awardsCastingStat(ctx)
)
)
for (spray in particles) for (spray in particles)
sideEffects.add(OperatorSideEffect.Particles(spray)) sideEffects.add(OperatorSideEffect.Particles(spray))

View file

@ -11,7 +11,6 @@ import at.petrak.hexcasting.api.mod.HexStatistics
import at.petrak.hexcasting.api.spell.Action import at.petrak.hexcasting.api.spell.Action
import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.SpellList import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.Widget
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.ListIota import at.petrak.hexcasting.api.spell.iota.ListIota
import at.petrak.hexcasting.api.spell.iota.NullIota import at.petrak.hexcasting.api.spell.iota.NullIota
@ -116,7 +115,7 @@ class CastingHarness private constructor(
listOf( listOf(
OperatorSideEffect.DoMishap( OperatorSideEffect.DoMishap(
mishap, mishap,
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null) Mishap.Context((iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST), null)
) )
), ),
) )
@ -129,7 +128,7 @@ class CastingHarness private constructor(
listOf( listOf(
OperatorSideEffect.DoMishap( OperatorSideEffect.DoMishap(
MishapError(exception), MishapError(exception),
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null) Mishap.Context((iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST), null)
) )
) )
) )
@ -273,27 +272,28 @@ class CastingHarness private constructor(
* either escaping it onto the stack or changing the parenthese-handling state. * either escaping it onto the stack or changing the parenthese-handling state.
*/ */
private fun handleParentheses(iota: Iota): Pair<FunctionalData, ResolvedPatternType>? { private fun handleParentheses(iota: Iota): Pair<FunctionalData, ResolvedPatternType>? {
val operator = (iota.payload as? HexPattern)?.let { if (iota !is PatternIota) {
try { throw IllegalStateException()
PatternRegistry.matchPattern(it, this.ctx.world)
} catch (mishap: Mishap) {
null
}
} }
val sig = iota.pattern.anglesSignature()
return if (this.parenCount > 0) { if (this.parenCount > 0) {
if (this.escapeNext) { if (this.escapeNext) {
val newParens = this.parenthesized.toMutableList() val newParens = this.parenthesized.toMutableList()
newParens.add(iota) newParens.add(iota)
this.getFunctionalData().copy( return this.getFunctionalData().copy(
escapeNext = false, escapeNext = false,
parenthesized = newParens parenthesized = newParens
) to ResolvedPatternType.ESCAPED ) to ResolvedPatternType.ESCAPED
} else if (operator == Widget.ESCAPE) { }
return when (sig) {
SpecialPatterns.CONSIDERATION.anglesSignature() -> {
this.getFunctionalData().copy( this.getFunctionalData().copy(
escapeNext = true, escapeNext = true,
) to ResolvedPatternType.EVALUATED ) to ResolvedPatternType.EVALUATED
} else if (operator == Widget.OPEN_PAREN) { }
SpecialPatterns.INTROSPECTION.anglesSignature() -> {
// we have escaped the parens onto the stack; we just also record our count. // we have escaped the parens onto the stack; we just also record our count.
val newParens = this.parenthesized.toMutableList() val newParens = this.parenthesized.toMutableList()
newParens.add(iota) newParens.add(iota)
@ -301,7 +301,8 @@ class CastingHarness private constructor(
parenthesized = newParens, parenthesized = newParens,
parenCount = this.parenCount + 1 parenCount = this.parenCount + 1
) to if (this.parenCount == 0) ResolvedPatternType.EVALUATED else ResolvedPatternType.ESCAPED ) to if (this.parenCount == 0) ResolvedPatternType.EVALUATED else ResolvedPatternType.ESCAPED
} else if (operator == Widget.CLOSE_PAREN) { }
SpecialPatterns.RETROSPECTION.anglesSignature() -> {
val newParenCount = this.parenCount - 1 val newParenCount = this.parenCount - 1
if (newParenCount == 0) { if (newParenCount == 0) {
val newStack = this.stack.toMutableList() val newStack = this.stack.toMutableList()
@ -323,34 +324,45 @@ class CastingHarness private constructor(
parenthesized = newParens parenthesized = newParens
) to ResolvedPatternType.ESCAPED ) to ResolvedPatternType.ESCAPED
} }
} else { }
else -> {
val newParens = this.parenthesized.toMutableList() val newParens = this.parenthesized.toMutableList()
newParens.add(iota) newParens.add(iota)
this.getFunctionalData().copy( this.getFunctionalData().copy(
parenthesized = newParens parenthesized = newParens
) to ResolvedPatternType.ESCAPED ) to ResolvedPatternType.ESCAPED
} }
} else if (this.escapeNext) { }
}
if (this.escapeNext) {
val newStack = this.stack.toMutableList() val newStack = this.stack.toMutableList()
newStack.add(iota) newStack.add(iota)
this.getFunctionalData().copy( return this.getFunctionalData().copy(
stack = newStack, stack = newStack,
escapeNext = false, escapeNext = false,
) to ResolvedPatternType.ESCAPED ) to ResolvedPatternType.ESCAPED
} else if (operator == Widget.ESCAPE) { }
return when (sig) {
SpecialPatterns.CONSIDERATION.anglesSignature() -> {
this.getFunctionalData().copy( this.getFunctionalData().copy(
escapeNext = true escapeNext = true
) to ResolvedPatternType.EVALUATED ) to ResolvedPatternType.EVALUATED
} else if (operator == Widget.OPEN_PAREN) { }
SpecialPatterns.INTROSPECTION.anglesSignature() -> {
this.getFunctionalData().copy( this.getFunctionalData().copy(
parenCount = this.parenCount + 1 parenCount = this.parenCount + 1
) to ResolvedPatternType.EVALUATED ) to ResolvedPatternType.EVALUATED
} else if (operator == Widget.CLOSE_PAREN) { }
SpecialPatterns.RETROSPECTION.anglesSignature() -> {
throw MishapTooManyCloseParens() throw MishapTooManyCloseParens()
} else { }
else -> {
null null
} }
} }
}
/** /**
* Might cast from hitpoints. * Might cast from hitpoints.

View file

@ -0,0 +1,10 @@
package at.petrak.hexcasting.api.spell.casting
import at.petrak.hexcasting.api.spell.math.HexDir
import at.petrak.hexcasting.api.spell.math.HexPattern
object SpecialPatterns {
val INTROSPECTION = HexPattern.fromAngles("qqq", HexDir.WEST)
val RETROSPECTION = HexPattern.fromAngles("eee", HexDir.EAST)
val CONSIDERATION = HexPattern.fromAngles("qqqaw", HexDir.EAST)
}

View file

@ -72,7 +72,7 @@ public class EntityIota extends Iota {
@Override @Override
public int color() { public int color() {
return 0; return 0xff_55ffff;
} }
}; };
} }

View file

@ -16,11 +16,6 @@ public abstract class Iota {
this.payload = payload; this.payload = payload;
} }
public @NotNull
Object getPayload() {
return payload;
}
public @NotNull public @NotNull
IotaType<?> getType() { IotaType<?> getType() {
return this.type; return this.type;

View file

@ -14,6 +14,10 @@ import org.jetbrains.annotations.Nullable;
public class NullIota extends Iota { public class NullIota extends Iota {
private static final Object NULL_SUBSTITUTE = new Object(); private static final Object NULL_SUBSTITUTE = new Object();
/**
* There's no <i>reason</i> you can't make your own new {@link NullIota}; it should work just fine.
* But having a canonical one saves allocations.
*/
public static final NullIota INSTANCE = new NullIota(); public static final NullIota INSTANCE = new NullIota();
public NullIota() { public NullIota() {

View file

@ -5,6 +5,8 @@ import at.petrak.hexcasting.common.lib.HexIotaTypes;
import net.minecraft.nbt.LongArrayTag; import net.minecraft.nbt.LongArrayTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -52,7 +54,16 @@ public class Vec3Iota extends Iota {
@Override @Override
public int color() { public int color() {
return 0; return 0xff_ff55ff;
} }
}; };
public static Component display(double x, double y, double z) {
return new TextComponent(String.format("(%.2f, %.2f, %.2f)", x, y, z))
.withStyle(Style.EMPTY.withColor(HexIotaTypes.VEC3.color()));
}
public static Component display(Vec3 v) {
return display(v.x, v.y, v.z);
}
} }

View file

@ -3,9 +3,9 @@ package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.mod.HexItemTags import at.petrak.hexcasting.api.mod.HexItemTags
import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.utils.asTranslatedComponent import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.api.utils.lightPurple import at.petrak.hexcasting.api.utils.lightPurple

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell.mishaps package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
@ -17,5 +17,5 @@ class MishapEntityTooFarAway(val entity: Entity) : Mishap() {
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component = override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("entity_too_far", LegacySpellDatum.make(entity).display(), actionName(errorCtx.action)) error("entity_too_far", entity.displayName, actionName(errorCtx.action))
} }

View file

@ -1,10 +1,10 @@
package at.petrak.hexcasting.api.spell.mishaps package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.Widget
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.GarbageIota
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
class MishapInvalidPattern : Mishap() { class MishapInvalidPattern : Mishap() {
@ -14,7 +14,7 @@ class MishapInvalidPattern : Mishap() {
override fun resolutionType(ctx: CastingContext) = ResolvedPatternType.INVALID override fun resolutionType(ctx: CastingContext) = ResolvedPatternType.INVALID
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
stack.add(LegacySpellDatum.make(Widget.GARBAGE)) stack.add(GarbageIota.INSTANCE)
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context) = override fun errorMessage(ctx: CastingContext, errorCtx: Context) =

View file

@ -1,9 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.Widget
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.GarbageIota
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
@ -13,7 +13,7 @@ class MishapLocationInWrongDimension(val properDimension: ResourceLocation) : Mi
dyeColor(DyeColor.MAGENTA) dyeColor(DyeColor.MAGENTA)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
stack.add(LegacySpellDatum.make(Widget.GARBAGE)) stack.add(GarbageIota.INSTANCE)
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component = override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =

View file

@ -1,8 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.Vec3Iota
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -16,5 +17,5 @@ class MishapLocationTooFarAway(val location: Vec3, val type: String = "too_far")
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component = override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =
error("location_$type", LegacySpellDatum.make(location).display(), actionName(errorCtx.action!!)) error("location_$type", Vec3Iota.display(location), actionName(errorCtx.action))
} }

View file

@ -1,10 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.Widget
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import net.minecraft.network.chat.Component import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.NullIota
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
class MishapNotEnoughArgs(val expected: Int, val got: Int) : Mishap() { class MishapNotEnoughArgs(val expected: Int, val got: Int) : Mishap() {
@ -12,8 +11,7 @@ class MishapNotEnoughArgs(val expected: Int, val got: Int) : Mishap() {
dyeColor(DyeColor.LIGHT_GRAY) dyeColor(DyeColor.LIGHT_GRAY)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
for (i in got until expected) repeat(expected - got) { stack.add(NullIota.INSTANCE) }
stack.add(LegacySpellDatum.make(Widget.GARBAGE))
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context) = override fun errorMessage(ctx: CastingContext, errorCtx: Context) =

View file

@ -1,9 +1,10 @@
package at.petrak.hexcasting.api.spell.mishaps package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.EntityIota
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.ListIota
import net.minecraft.world.effect.MobEffectInstance import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
@ -23,22 +24,20 @@ class MishapOthersName(val other: Player) : Mishap() {
companion object { companion object {
@JvmStatic @JvmStatic
fun getTrueNameFromDatum(datum: Iota, caster: Player): Player? { fun getTrueNameFromDatum(datum: Iota, caster: Player): Player? {
if (datum.payload is Player && datum.payload != caster) if (datum is EntityIota && datum.entity is Player && datum != caster)
return datum.payload return datum.entity as Player
else if (datum.payload !is SpellList) if (datum !is ListIota)
return null return null
val poolToSearch: MutableList<Iota> = val poolToSearch = ArrayDeque<Iota>()
datum.payload.filterIsInstance<Iota>().toMutableList() poolToSearch.addLast(datum)
while (poolToSearch.isNotEmpty()) { while (poolToSearch.isNotEmpty()) {
val datumToCheck = poolToSearch[0] val datumToCheck = poolToSearch.removeFirst()
poolToSearch.removeAt(0) if (datumToCheck is EntityIota && datumToCheck.entity is Player && datumToCheck.entity != caster)
return datumToCheck.entity as Player
if (datumToCheck.payload is Player && datumToCheck.payload != caster) if (datumToCheck is ListIota)
return datumToCheck.payload poolToSearch.addAll(datumToCheck.list)
else if (datumToCheck.payload is SpellList)
poolToSearch.addAll(datumToCheck.payload.filterIsInstance<Iota>())
} }
return null return null

View file

@ -1,9 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import net.minecraft.network.chat.Component import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.PatternIota
import net.minecraft.world.item.DyeColor import net.minecraft.world.item.DyeColor
class MishapTooManyCloseParens : Mishap() { class MishapTooManyCloseParens : Mishap() {
@ -11,7 +11,8 @@ class MishapTooManyCloseParens : Mishap() {
dyeColor(DyeColor.ORANGE) dyeColor(DyeColor.ORANGE)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
stack.add(LegacySpellDatum.make(errorCtx.pattern)) // TODO this is a kinda shitty mishap
stack.add(PatternIota(errorCtx.pattern))
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context) = override fun errorMessage(ctx: CastingContext, errorCtx: Context) =

View file

@ -3,7 +3,9 @@ package at.petrak.hexcasting.common.casting;
import at.petrak.hexcasting.api.PatternRegistry; import at.petrak.hexcasting.api.PatternRegistry;
import at.petrak.hexcasting.api.misc.ManaConstants; import at.petrak.hexcasting.api.misc.ManaConstants;
import at.petrak.hexcasting.api.spell.Action; import at.petrak.hexcasting.api.spell.Action;
import at.petrak.hexcasting.api.spell.Widget; import at.petrak.hexcasting.api.spell.iota.DoubleIota;
import at.petrak.hexcasting.api.spell.iota.NullIota;
import at.petrak.hexcasting.api.spell.iota.Vec3Iota;
import at.petrak.hexcasting.api.spell.math.HexAngle; import at.petrak.hexcasting.api.spell.math.HexAngle;
import at.petrak.hexcasting.api.spell.math.HexDir; import at.petrak.hexcasting.api.spell.math.HexDir;
import at.petrak.hexcasting.api.spell.math.HexPattern; import at.petrak.hexcasting.api.spell.math.HexPattern;
@ -209,9 +211,9 @@ public class RegisterPatterns {
PatternRegistry.mapPattern(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"), PatternRegistry.mapPattern(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"),
OpExtinguish.INSTANCE); OpExtinguish.INSTANCE);
PatternRegistry.mapPattern(HexPattern.fromAngles("qqa", HexDir.NORTH_EAST), modLoc("conjure_block"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqa", HexDir.NORTH_EAST), modLoc("conjure_block"),
new OpConjure(false)); new OpConjureBlock(false));
PatternRegistry.mapPattern(HexPattern.fromAngles("qqd", HexDir.NORTH_EAST), modLoc("conjure_light"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqd", HexDir.NORTH_EAST), modLoc("conjure_light"),
new OpConjure(true)); new OpConjureBlock(true));
PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqwawqaqw", HexDir.NORTH_EAST), modLoc("bonemeal"), PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqwawqaqw", HexDir.NORTH_EAST), modLoc("bonemeal"),
OpTheOnlyReasonAnyoneDownloadedPsi.INSTANCE); OpTheOnlyReasonAnyoneDownloadedPsi.INSTANCE);
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwaeaeaeaeaea", HexDir.NORTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwaeaeaeaeaea", HexDir.NORTH_WEST),
@ -315,11 +317,9 @@ public class RegisterPatterns {
// == Meta stuff == // == Meta stuff ==
PatternRegistry.mapPattern(HexPattern.fromAngles("qqq", HexDir.WEST), modLoc("open_paren"), // Intro/Retro/Consideration are now special-form-likes and aren't even ops.
Widget.OPEN_PAREN); // TODO should there be a registry for these too
PatternRegistry.mapPattern(HexPattern.fromAngles("eee", HexDir.EAST), modLoc("close_paren"),
Widget.CLOSE_PAREN);
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqaw", HexDir.WEST), modLoc("escape"), Widget.ESCAPE);
// http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf // http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf
// eval being a space filling curve feels apt doesn't it // eval being a space filling curve feels apt doesn't it
PatternRegistry.mapPattern(HexPattern.fromAngles("deaqq", HexDir.SOUTH_EAST), modLoc("eval"), PatternRegistry.mapPattern(HexPattern.fromAngles("deaqq", HexDir.SOUTH_EAST), modLoc("eval"),
@ -348,32 +348,33 @@ public class RegisterPatterns {
// == Consts == // == Consts ==
PatternRegistry.mapPattern(HexPattern.fromAngles("d", HexDir.EAST), modLoc("const/null"), Widget.NULL); PatternRegistry.mapPattern(HexPattern.fromAngles("d", HexDir.EAST), modLoc("const/null"),
Action.makeConstantOp(NullIota.INSTANCE));
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqea", HexDir.NORTH_WEST), modLoc("const/vec/px"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqea", HexDir.NORTH_WEST), modLoc("const/vec/px"),
Action.makeConstantOp(LegacySpellDatum.make(new Vec3(1.0, 0.0, 0.0)))); Action.makeConstantOp(new Vec3Iota(new Vec3(1.0, 0.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqew", HexDir.NORTH_WEST), modLoc("const/vec/py"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqew", HexDir.NORTH_WEST), modLoc("const/vec/py"),
Action.makeConstantOp(LegacySpellDatum.make(new Vec3(0.0, 1.0, 0.0)))); Action.makeConstantOp(new Vec3Iota(new Vec3(0.0, 1.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqed", HexDir.NORTH_WEST), modLoc("const/vec/pz"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqed", HexDir.NORTH_WEST), modLoc("const/vec/pz"),
Action.makeConstantOp(LegacySpellDatum.make(new Vec3(0.0, 0.0, 1.0)))); Action.makeConstantOp(new Vec3Iota(new Vec3(0.0, 0.0, 1.0))));
PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqa", HexDir.SOUTH_WEST), modLoc("const/vec/nx"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqa", HexDir.SOUTH_WEST), modLoc("const/vec/nx"),
Action.makeConstantOp(LegacySpellDatum.make(new Vec3(-1.0, 0.0, 0.0)))); Action.makeConstantOp(new Vec3Iota(new Vec3(-1.0, 0.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqw", HexDir.SOUTH_WEST), modLoc("const/vec/ny"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqw", HexDir.SOUTH_WEST), modLoc("const/vec/ny"),
Action.makeConstantOp(LegacySpellDatum.make(new Vec3(0.0, -1.0, 0.0)))); Action.makeConstantOp(new Vec3Iota(new Vec3(0.0, -1.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqd", HexDir.SOUTH_WEST), modLoc("const/vec/nz"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqd", HexDir.SOUTH_WEST), modLoc("const/vec/nz"),
Action.makeConstantOp(LegacySpellDatum.make(new Vec3(0.0, 0.0, -1.0)))); Action.makeConstantOp(new Vec3Iota(new Vec3(0.0, 0.0, -1.0))));
// Yep, this is what I spend the "plain hexagon" pattern on. // Yep, this is what I spend the "plain hexagon" pattern on.
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqq", HexDir.NORTH_WEST), modLoc("const/vec/0"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqq", HexDir.NORTH_WEST), modLoc("const/vec/0"),
Action.makeConstantOp(LegacySpellDatum.make(new Vec3(0.0, 0.0, 0.0)))); Action.makeConstantOp(new Vec3Iota(new Vec3(0.0, 0.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.fromAngles("qdwdq", HexDir.NORTH_EAST), modLoc("const/double/pi"), PatternRegistry.mapPattern(HexPattern.fromAngles("qdwdq", HexDir.NORTH_EAST), modLoc("const/double/pi"),
Action.makeConstantOp(LegacySpellDatum.make(Math.PI))); Action.makeConstantOp(new DoubleIota(Math.PI)));
PatternRegistry.mapPattern(HexPattern.fromAngles("eawae", HexDir.NORTH_WEST), modLoc("const/double/tau"), PatternRegistry.mapPattern(HexPattern.fromAngles("eawae", HexDir.NORTH_WEST), modLoc("const/double/tau"),
Action.makeConstantOp(LegacySpellDatum.make(HexUtils.TAU))); Action.makeConstantOp(new DoubleIota(HexUtils.TAU)));
// e // e
PatternRegistry.mapPattern(HexPattern.fromAngles("aaq", HexDir.EAST), modLoc("const/double/e"), PatternRegistry.mapPattern(HexPattern.fromAngles("aaq", HexDir.EAST), modLoc("const/double/e"),
Action.makeConstantOp(LegacySpellDatum.make(Math.E))); Action.makeConstantOp(new DoubleIota(Math.E)));
// == Entities == // == Entities ==
@ -489,7 +490,7 @@ public class RegisterPatterns {
if (negate) { if (negate) {
accumulator = -accumulator; accumulator = -accumulator;
} }
return Action.makeConstantOp(LegacySpellDatum.make(accumulator)); return Action.makeConstantOp(new DoubleIota(accumulator));
} else { } else {
return null; return null;
} }

View file

@ -1,8 +1,9 @@
package at.petrak.hexcasting.common.casting.operators.circles package at.petrak.hexcasting.common.casting.operators.circles
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -16,8 +17,8 @@ class OpCircleBounds(val max: Boolean) : ConstManaAction {
val aabb = ctx.spellCircle.aabb val aabb = ctx.spellCircle.aabb
return if (max) return if (max)
Vec3(aabb.maxX - 0.5, aabb.maxY - 0.5, aabb.maxZ - 0.5).asSpellResult Vec3(aabb.maxX - 0.5, aabb.maxY - 0.5, aabb.maxZ - 0.5).asActionResult
else else
Vec3(aabb.minX + 0.5, aabb.minY + 0.5, aabb.minZ + 0.5).asSpellResult Vec3(aabb.minX + 0.5, aabb.minY + 0.5, aabb.minZ + 0.5).asActionResult
} }
} }

View file

@ -2,8 +2,9 @@ package at.petrak.hexcasting.common.casting.operators.circles
import at.petrak.hexcasting.api.block.circle.BlockAbstractImpetus import at.petrak.hexcasting.api.block.circle.BlockAbstractImpetus
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle
object OpImpetusDir : ConstManaAction { object OpImpetusDir : ConstManaAction {
@ -16,6 +17,6 @@ object OpImpetusDir : ConstManaAction {
val pos = ctx.spellCircle.impetusPos val pos = ctx.spellCircle.impetusPos
val bs = ctx.world.getBlockState(pos) val bs = ctx.world.getBlockState(pos)
val dir = bs.getValue(BlockAbstractImpetus.FACING) val dir = bs.getValue(BlockAbstractImpetus.FACING)
return dir.step().asSpellResult return dir.step().asActionResult
} }
} }

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.circles package at.petrak.hexcasting.common.casting.operators.circles
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle
@ -12,6 +13,6 @@ object OpImpetusPos : ConstManaAction {
if (ctx.spellCircle == null) if (ctx.spellCircle == null)
throw MishapNoSpellCircle() throw MishapNoSpellCircle()
return ctx.spellCircle.impetusPos.asSpellResult return ctx.spellCircle.impetusPos.asActionResult
} }
} }

View file

@ -3,7 +3,6 @@ package at.petrak.hexcasting.common.casting.operators.lists
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.asActionResult import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getIota
import at.petrak.hexcasting.api.spell.getList import at.petrak.hexcasting.api.spell.getList
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.iota.Iota
@ -11,7 +10,7 @@ object OpAppend : ConstManaAction {
override val argc = 2 override val argc = 2
override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
val list = args.getList(0, argc).toMutableList() val list = args.getList(0, argc).toMutableList()
val datum = args.getIota(1) val datum = args[1]
list.add(datum) list.add(datum)
return list.asActionResult return list.asActionResult
} }

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.lists package at.petrak.hexcasting.common.casting.operators.lists
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getList import at.petrak.hexcasting.api.spell.getList
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.iota.Iota
@ -9,6 +10,6 @@ import at.petrak.hexcasting.api.spell.iota.Iota
object OpListSize : ConstManaAction { object OpListSize : ConstManaAction {
override val argc = 1 override val argc = 1
override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
return args.getList(0, argc).toList().size.asSpellResult // mmm one-liner return args.getList(0, argc).toList().size.asActionResult // mmm one-liner
} }
} }

View file

@ -9,7 +9,7 @@ object OpModifyInPlace : ConstManaAction {
override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
val list = args.getList(0, argc) val list = args.getList(0, argc)
val index = args.getPositiveIntUnder(1, list.size(), argc) val index = args.getPositiveIntUnder(1, list.size(), argc)
val iota = args.getIota(2) val iota = args[2]
return list.modifyAt(index) { SpellList.LPair(iota, it.cdr) }.asActionResult return list.modifyAt(index) { SpellList.LPair(iota, it.cdr) }.asActionResult
} }
} }

View file

@ -3,12 +3,11 @@ package at.petrak.hexcasting.common.casting.operators.lists
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.asActionResult import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getIota
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.iota.Iota
object OpSingleton : ConstManaAction { object OpSingleton : ConstManaAction {
override val argc = 1 override val argc = 1
override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
return listOf(args.getIota(0)).asActionResult // god i love one-liners return listOf(args[0]).asActionResult // god i love one-liners
} }
} }

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.math.bit package at.petrak.hexcasting.common.casting.operators.math.bit
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getLong import at.petrak.hexcasting.api.spell.getLong
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.iota.Iota
@ -10,6 +11,6 @@ object OpNot : ConstManaAction {
override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
val num = args.getLong(0, argc) val num = args.getLong(0, argc)
return num.inv().asSpellResult return num.inv().asActionResult
} }
} }

View file

@ -1,12 +1,9 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -18,8 +15,8 @@ object OpAddMotion : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Entity>(0, argc) val target = args.getEntity(0, argc)
val motion = args.getChecked<Vec3>(1, argc) val motion = args.getVec3(1, argc)
ctx.assertEntityInRange(target) ctx.assertEntityInRange(target)
var motionForCost = motion.lengthSqr() var motionForCost = motion.lengthSqr()
if (ctx.hasBeenGivenMotion(target)) if (ctx.hasBeenGivenMotion(target))

View file

@ -1,12 +1,9 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.common.network.MsgBeepAck import at.petrak.hexcasting.common.network.MsgBeepAck
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
@ -19,9 +16,9 @@ object OpBeep : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getVec3(0, argc)
val instrument = args.getChecked<Double>(1, argc).toInt().coerceIn(0, NoteBlockInstrument.values().size - 1) val instrument = args.getPositiveIntUnder(1, NoteBlockInstrument.values().size, argc)
val note = args.getChecked<Double>(2, argc).toInt().coerceIn(0, 24) val note = args.getPositiveIntUnder(2, 24, argc) // mojang don't have magic numbers challenge
ctx.assertVecInRange(target) ctx.assertVecInRange(target)
return Triple( return Triple(

View file

@ -3,13 +3,13 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapImmuneEntity import at.petrak.hexcasting.api.spell.mishaps.MishapImmuneEntity
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway
import at.petrak.hexcasting.common.network.MsgBlinkAck import at.petrak.hexcasting.common.network.MsgBlinkAck
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import kotlin.math.max
import kotlin.math.roundToInt import kotlin.math.roundToInt
object OpBlink : SpellAction { object OpBlink : SpellAction {
@ -18,8 +18,8 @@ object OpBlink : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Entity>(0, argc) val target = args.getEntity(0, argc)
val delta = max(0.0, args.getChecked(1, argc)) val delta = args.getDouble(1, argc)
ctx.assertEntityInRange(target) ctx.assertEntityInRange(target)
if (!target.canChangeDimensions()) if (!target.canChangeDimensions())

View file

@ -2,8 +2,12 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -16,21 +20,18 @@ object OpBreakBlock : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val pos = args.getChecked<Vec3>(0, argc) val pos = args.getBlockPos(0, argc)
ctx.assertVecInRange(pos) ctx.assertVecInRange(pos)
val centered = Vec3.atCenterOf(BlockPos(pos))
return Triple( return Triple(
Spell(pos), Spell(pos),
(ManaConstants.DUST_UNIT * 1.125).toInt(), (ManaConstants.DUST_UNIT * 1.125).toInt(),
listOf(ParticleSpray.burst(centered, 1.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0))
) )
} }
private data class Spell(val v: Vec3) : RenderedSpell { private data class Spell(val pos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
val pos = BlockPos(v)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return return

View file

@ -1,8 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock
import at.petrak.hexcasting.common.blocks.BlockConjured import at.petrak.hexcasting.common.blocks.BlockConjured
import at.petrak.hexcasting.common.lib.HexBlocks import at.petrak.hexcasting.common.lib.HexBlocks
@ -13,16 +17,14 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.DirectionalPlaceContext import net.minecraft.world.item.context.DirectionalPlaceContext
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
class OpConjure(val light: Boolean) : SpellAction { class OpConjureBlock(val light: Boolean) : SpellAction {
override val argc = 1 override val argc = 1
override fun execute( override fun execute(
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>? { ): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
val target = args.getChecked<Vec3>(0, argc) val pos = args.getBlockPos(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(pos)
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return null return null
@ -34,16 +36,14 @@ class OpConjure(val light: Boolean) : SpellAction {
throw MishapBadBlock.of(pos, "replaceable") throw MishapBadBlock.of(pos, "replaceable")
return Triple( return Triple(
Spell(target, light), Spell(pos, light),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0)) listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0))
) )
} }
private data class Spell(val target: Vec3, val light: Boolean) : RenderedSpell { private data class Spell(val pos: BlockPos, val light: Boolean) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return return

View file

@ -2,8 +2,12 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.HexAPI import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.item.BucketItem import net.minecraft.world.item.BucketItem
@ -21,20 +25,17 @@ object OpCreateWater : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target)
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(target), 1.0))
) )
} }
private data class Spell(val target: Vec3) : RenderedSpell { private data class Spell(val pos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return return
val state = ctx.world.getBlockState(pos) val state = ctx.world.getBlockState(pos)

View file

@ -3,6 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.particles.ParticleTypes import net.minecraft.core.particles.ParticleTypes
@ -23,25 +24,23 @@ object OpDestroyWater : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(target)
return Triple( return Triple(
Spell(target), Spell(target),
2 * ManaConstants.CRYSTAL_UNIT, 2 * ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.burst(target, 3.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(target), 3.0))
) )
} }
const val MAX_DESTROY_COUNT = 1024 const val MAX_DESTROY_COUNT = 1024
private data class Spell(val target: Vec3) : RenderedSpell { private data class Spell(val basePos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
// SpongeBlock.java // SpongeBlock.java
val todo = ArrayDeque<BlockPos>() val todo = ArrayDeque<BlockPos>()
val seen = HashSet<BlockPos>() val seen = HashSet<BlockPos>()
val basePos = BlockPos(target)
// a little extra range on the initial cast to make it feel more intuitive // a little extra range on the initial cast to make it feel more intuitive
for (xShift in -2..2) for (yShift in -2..2) for (zShift in -2..2) { for (xShift in -2..2) for (yShift in -2..2) for (zShift in -2..2) {
@ -53,7 +52,10 @@ object OpDestroyWater : SpellAction {
val here = todo.removeFirst() val here = todo.removeFirst()
val distFromFocus = val distFromFocus =
ctx.caster.position().distanceToSqr(Vec3.atCenterOf(here)) ctx.caster.position().distanceToSqr(Vec3.atCenterOf(here))
if (distFromFocus < Action.MAX_DISTANCE * Action.MAX_DISTANCE && seen.add(here) && ctx.world.mayInteract(ctx.caster, here)) { if (distFromFocus < Action.MAX_DISTANCE * Action.MAX_DISTANCE
&& seen.add(here)
&& ctx.world.mayInteract(ctx.caster, here)
) {
// never seen this pos in my life // never seen this pos in my life
val fluid = ctx.world.getFluidState(here) val fluid = ctx.world.getFluidState(here)
if (fluid != Fluids.EMPTY.defaultFluidState()) { if (fluid != Fluids.EMPTY.defaultFluidState()) {
@ -104,9 +106,9 @@ object OpDestroyWater : SpellAction {
if (successes > 0) { if (successes > 0) {
ctx.world.playSound( ctx.world.playSound(
null, null,
target.x, basePos.x.toDouble(),
target.y, basePos.y.toDouble(),
target.z, basePos.z.toDouble(),
SoundEvents.FIRE_EXTINGUISH, SoundEvents.FIRE_EXTINGUISH,
SoundSource.BLOCKS, SoundSource.BLOCKS,
1.0f, 1.0f,

View file

@ -1,12 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.getChecked
import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock
import at.petrak.hexcasting.common.misc.AkashicTreeGrower import at.petrak.hexcasting.common.misc.AkashicTreeGrower
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
@ -20,18 +20,15 @@ object OpEdifySapling : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val pos = args.getChecked<Vec3>(0, argc) val pos = args.getBlockPos(0, argc)
ctx.assertVecInRange(pos) val bs = ctx.world.getBlockState(pos)
val bpos = BlockPos(pos)
val bs = ctx.world.getBlockState(bpos)
if (!bs.`is`(BlockTags.SAPLINGS)) if (!bs.`is`(BlockTags.SAPLINGS))
throw MishapBadBlock.of(bpos, "sapling") throw MishapBadBlock.of(pos, "sapling")
return Triple( return Triple(
Spell(bpos), Spell(pos),
ManaConstants.CRYSTAL_UNIT, ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray(Vec3.atCenterOf(bpos), Vec3(0.0, 2.0, 0.0), 0.1, Math.PI / 4, 100)) listOf(ParticleSpray(Vec3.atCenterOf(pos), Vec3(0.0, 2.0, 0.0), 0.1, Math.PI / 4, 100))
) )
} }

View file

@ -3,8 +3,8 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.util.Mth
import net.minecraft.world.level.Explosion import net.minecraft.world.level.Explosion
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -16,15 +16,14 @@ class OpExplode(val fire: Boolean) : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val pos = args.getChecked<Vec3>(0, argc) val pos = args.getVec3(0, argc)
val strength = args.getChecked<Double>(1, argc) val strength = args.getPositiveDoubleUnder(1, 10.0, argc)
ctx.assertVecInRange(pos) ctx.assertVecInRange(pos)
val clampedStrength = Mth.clamp(strength, 0.0, 10.0) val cost = ManaConstants.DUST_UNIT * (3 * strength + if (fire) 0.125 else 1.0)
val cost = ManaConstants.DUST_UNIT * (3 * clampedStrength + if (fire) 0.125 else 1.0)
return Triple( return Triple(
Spell(pos, clampedStrength, this.fire), Spell(pos, strength, this.fire),
cost.toInt(), cost.toInt(),
listOf(ParticleSpray.burst(pos, clampedStrength, 50)) listOf(ParticleSpray.burst(pos, strength, 50))
) )
} }

View file

@ -3,6 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.ktxt.UseOnContext import at.petrak.hexcasting.ktxt.UseOnContext
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
@ -22,37 +23,35 @@ object OpExtinguish : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(target)
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.DUST_UNIT * 6, ManaConstants.DUST_UNIT * 6,
listOf(ParticleSpray.burst(target, 1.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(target), 1.0))
) )
} }
const val MAX_DESTROY_COUNT = 1024 const val MAX_DESTROY_COUNT = 1024
private data class Spell(val target: Vec3) : RenderedSpell { private data class Spell(val target: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
// how many levels of "borrowed" code are we on now // how many levels of "borrowed" code are we on now
val todo = ArrayDeque<BlockPos>() val todo = ArrayDeque<BlockPos>()
val seen = HashSet<BlockPos>() val seen = HashSet<BlockPos>()
todo.add(BlockPos(target)) todo.add(target)
var successes = 0 var successes = 0
while (todo.isNotEmpty() && successes <= MAX_DESTROY_COUNT) { while (todo.isNotEmpty() && successes <= MAX_DESTROY_COUNT) {
val here = todo.removeFirst() val here = todo.removeFirst()
val distFromFocus = val distFromFocus =
ctx.caster.position().distanceToSqr(Vec3.atCenterOf(here)) ctx.caster.position().distanceToSqr(Vec3.atCenterOf(here))
val distFromTarget = val distFromTarget = target.distSqr(here) // max distance to prevent runaway shenanigans
target.distanceTo(Vec3.atCenterOf(here)) // max distance to prevent runaway shenanigans if (distFromFocus < Action.MAX_DISTANCE * Action.MAX_DISTANCE
if (distFromFocus < Action.MAX_DISTANCE * Action.MAX_DISTANCE && seen.add(here) && distFromTarget < 10 && ctx.world.mayInteract( && seen.add(here)
ctx.caster, && distFromTarget < 10 * 10
here && ctx.world.mayInteract(ctx.caster, here)
)
) { ) {
// never seen this pos in my life // never seen this pos in my life
val blockstate = ctx.world.getBlockState(here) val blockstate = ctx.world.getBlockState(here)
@ -110,9 +109,9 @@ object OpExtinguish : SpellAction {
if (successes > 0) { if (successes > 0) {
ctx.world.playSound( ctx.world.playSound(
null, null,
target.x, target.x.toDouble(),
target.y, target.y.toDouble(),
target.z, target.z.toDouble(),
SoundEvents.FIRE_EXTINGUISH, SoundEvents.FIRE_EXTINGUISH,
SoundSource.BLOCKS, SoundSource.BLOCKS,
1.0f, 1.0f,

View file

@ -2,8 +2,12 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.HexAPI import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.ktxt.UseOnContext import at.petrak.hexcasting.ktxt.UseOnContext
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
@ -20,7 +24,7 @@ object OpIgnite : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(target)
return Triple( return Triple(
@ -30,9 +34,9 @@ object OpIgnite : SpellAction {
) )
} }
private data class Spell(val target: Vec3) : RenderedSpell { private data class Spell(val pos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
val pos = BlockPos(target) // TODO should we do these checks in the action part of the spell
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return return
@ -46,7 +50,7 @@ object OpIgnite : SpellAction {
null, null,
InteractionHand.MAIN_HAND, InteractionHand.MAIN_HAND,
ItemStack(maxwell.asItem()), ItemStack(maxwell.asItem()),
BlockHitResult(target, Direction.UP, pos, false) BlockHitResult(Vec3.atCenterOf(pos), Direction.UP, pos, false)
) )
) )
} else { } else {

View file

@ -2,8 +2,12 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.mod.HexItemTags import at.petrak.hexcasting.api.mod.HexItemTags
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getItemEntity
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.api.utils.extractMana import at.petrak.hexcasting.api.utils.extractMana
@ -22,7 +26,7 @@ object OpMakeBattery : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val entity = args.getChecked<ItemEntity>(0, argc) val entity = args.getItemEntity(0, argc)
val (handStack, hand) = ctx.getHeldItemToOperateOn { it.`is`(HexItemTags.PHIAL_BASE) } val (handStack, hand) = ctx.getHeldItemToOperateOn { it.`is`(HexItemTags.PHIAL_BASE) }

View file

@ -1,12 +1,8 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.api.spell.mishaps.MishapOthersName import at.petrak.hexcasting.api.spell.mishaps.MishapOthersName
@ -22,8 +18,8 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val entity = args.getChecked<ItemEntity>(0, argc) val entity = args.getItemEntity(0, argc)
val patterns = args.getChecked<SpellList>(1, argc).toList() val patterns = args.getList(1, argc).toList()
val (handStack, hand) = ctx.getHeldItemToOperateOn { val (handStack, hand) = ctx.getHeldItemToOperateOn {
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(it) val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(it)

View file

@ -1,8 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.particles.BlockParticleOption import net.minecraft.core.particles.BlockParticleOption
@ -23,10 +27,8 @@ object OpPlaceBlock : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>? { ): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
val target = args.getChecked<Vec3>(0, argc) val pos = args.getBlockPos(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(pos)
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return null return null
@ -43,16 +45,14 @@ object OpPlaceBlock : SpellAction {
throw MishapBadBlock.of(pos, "replaceable") throw MishapBadBlock.of(pos, "replaceable")
return Triple( return Triple(
Spell(target), Spell(pos),
ManaConstants.DUST_UNIT / 8, ManaConstants.DUST_UNIT / 8,
listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0)) listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0))
) )
} }
private data class Spell(val vec: Vec3) : RenderedSpell { private data class Spell(val pos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
val pos = BlockPos(vec)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return return
@ -86,11 +86,15 @@ object OpPlaceBlock : SpellAction {
ctx.world.playSound( ctx.world.playSound(
ctx.caster, ctx.caster,
vec.x, vec.y, vec.z, bstate.soundType.placeSound, SoundSource.BLOCKS, 1.0f, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(),
bstate.soundType.placeSound, SoundSource.BLOCKS, 1.0f,
1.0f + (Math.random() * 0.5 - 0.25).toFloat() 1.0f + (Math.random() * 0.5 - 0.25).toFloat()
) )
val particle = BlockParticleOption(ParticleTypes.BLOCK, bstate) val particle = BlockParticleOption(ParticleTypes.BLOCK, bstate)
ctx.world.sendParticles(particle, vec.x, vec.y, vec.z, 4, 0.1, 0.2, 0.1, 0.1) ctx.world.sendParticles(
particle, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(),
4, 0.1, 0.2, 0.1, 0.1
)
} }
} }
} }

View file

@ -2,12 +2,10 @@ package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.world.effect.MobEffect import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectInstance import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.decoration.ArmorStand
import kotlin.math.max
class OpPotionEffect( class OpPotionEffect(
val effect: MobEffect, val effect: MobEffect,
@ -23,14 +21,13 @@ class OpPotionEffect(
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<LivingEntity>(0, argc) val target = args.getLivingEntityButNotArmorStand(0, argc)
if (target is ArmorStand) val duration = args.getPositiveDouble(1, argc)
throw MishapInvalidIota.ofType(LegacySpellDatum.make(target), 0, LivingEntity::class.java)
val duration = max(args.getChecked(1, argc), 0.0)
ctx.assertEntityInRange(target)
val potency = if (this.allowPotency) val potency = if (this.allowPotency)
args.getChecked<Double>(2, argc).coerceIn(1.0, 128.0) args.getPositiveDoubleUnder(2, 127.0, argc)
else 1.0 else 1.0
ctx.assertEntityInRange(target)
val cost = this.baseCost * duration * if (potencyCubic) { val cost = this.baseCost * duration * if (potencyCubic) {
potency * potency * potency potency * potency * potency

View file

@ -1,17 +1,23 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.spell.OperationResult
import at.petrak.hexcasting.api.spell.Action import at.petrak.hexcasting.api.spell.Action
import at.petrak.hexcasting.api.spell.OperationResult
import at.petrak.hexcasting.api.spell.RenderedSpell import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect
import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
import net.minecraft.Util import net.minecraft.Util
// TODO should this dump the whole stack
object OpPrint : Action { object OpPrint : Action {
override fun operate(continuation: SpellContinuation, stack: MutableList<Iota>, local: Iota, ctx: CastingContext): OperationResult { override fun operate(
continuation: SpellContinuation,
stack: MutableList<Iota>,
local: Iota,
ctx: CastingContext
): OperationResult {
if (stack.isEmpty()) { if (stack.isEmpty()) {
throw MishapNotEnoughArgs(1, 0) throw MishapNotEnoughArgs(1, 0)
} }

View file

@ -1,8 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getItemEntity
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.api.utils.extractMana import at.petrak.hexcasting.api.utils.extractMana
@ -16,6 +20,8 @@ object OpRecharge : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>? { ): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
val entity = args.getItemEntity(0, argc)
val (handStack, hand) = ctx.getHeldItemToOperateOn { val (handStack, hand) = ctx.getHeldItemToOperateOn {
val mana = IXplatAbstractions.INSTANCE.findManaHolder(it) val mana = IXplatAbstractions.INSTANCE.findManaHolder(it)
mana != null && mana.canRecharge() && mana.media /* doo doo da do doo */ < mana.maxMedia mana != null && mana.canRecharge() && mana.media /* doo doo da do doo */ < mana.maxMedia
@ -30,7 +36,6 @@ object OpRecharge : SpellAction {
"rechargable" "rechargable"
) )
val entity = args.getChecked<ItemEntity>(0, argc)
ctx.assertEntityInRange(entity) ctx.assertEntityInRange(entity)
if (!isManaItem(entity.item)) { if (!isManaItem(entity.item)) {

View file

@ -1,8 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionHand
@ -19,21 +23,18 @@ object OpTheOnlyReasonAnyoneDownloadedPsi : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target)
return Triple( return Triple(
Spell(target), Spell(target),
(ManaConstants.DUST_UNIT + 1.125).toInt(), (ManaConstants.DUST_UNIT + 1.125).toInt(),
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(target), 1.0))
) )
} }
private data class Spell(val target: Vec3) : RenderedSpell { private data class Spell(val pos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
// https://github.com/VazkiiMods/Psi/blob/master/src/main/java/vazkii/psi/common/spell/trick/PieceTrickOvergrow.java // https://github.com/VazkiiMods/Psi/blob/master/src/main/java/vazkii/psi/common/spell/trick/PieceTrickOvergrow.java
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return return

View file

@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapAlreadyBrainswept import at.petrak.hexcasting.api.spell.mishaps.MishapAlreadyBrainswept
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBrainsweep import at.petrak.hexcasting.api.spell.mishaps.MishapBadBrainsweep
import at.petrak.hexcasting.common.misc.Brainsweeping import at.petrak.hexcasting.common.misc.Brainsweeping
@ -22,30 +23,32 @@ object OpBrainsweep : SpellAction {
override val isGreat = true override val isGreat = true
// this way you can hear the villager dying more : )
override fun hasCastingSound(ctx: CastingContext) = false
override fun execute( override fun execute(
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val sacrifice = args.getChecked<Villager>(0, argc) val sacrifice = args.getVillager(0, argc)
val pos = args.getChecked<Vec3>(1, argc) val pos = args.getBlockPos(1, argc)
ctx.assertVecInRange(pos) ctx.assertVecInRange(pos)
ctx.assertEntityInRange(sacrifice) ctx.assertEntityInRange(sacrifice)
if (Brainsweeping.isBrainswept(sacrifice)) if (Brainsweeping.isBrainswept(sacrifice))
throw MishapAlreadyBrainswept(sacrifice) throw MishapAlreadyBrainswept(sacrifice)
val bpos = BlockPos(pos) val state = ctx.world.getBlockState(pos)
val state = ctx.world.getBlockState(bpos)
val recman = ctx.world.recipeManager val recman = ctx.world.recipeManager
val recipes = recman.getAllRecipesFor(HexRecipeSerializers.BRAINSWEEP_TYPE) val recipes = recman.getAllRecipesFor(HexRecipeSerializers.BRAINSWEEP_TYPE)
val recipe = recipes.find { it.matches(state, sacrifice) } val recipe = recipes.find { it.matches(state, sacrifice) }
?: throw MishapBadBrainsweep(sacrifice, bpos) ?: throw MishapBadBrainsweep(sacrifice, pos)
return Triple( return Triple(
Spell(bpos, state, sacrifice, recipe), Spell(pos, state, sacrifice, recipe),
10 * ManaConstants.CRYSTAL_UNIT, 10 * ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.cloud(sacrifice.position(), 1.0), ParticleSpray.burst(Vec3.atCenterOf(bpos), 0.3, 100)) listOf(ParticleSpray.cloud(sacrifice.position(), 1.0), ParticleSpray.burst(Vec3.atCenterOf(pos), 0.3, 100))
) )
} }

View file

@ -2,12 +2,12 @@ package at.petrak.hexcasting.common.casting.operators.spells.great
import at.petrak.hexcasting.api.HexAPI import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.getChecked
import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.item.BucketItem import net.minecraft.world.item.BucketItem
@ -25,7 +25,7 @@ object OpCreateLava : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(target)
return Triple( return Triple(
@ -35,10 +35,8 @@ object OpCreateLava : SpellAction {
) )
} }
private data class Spell(val target: Vec3) : RenderedSpell { private data class Spell(val pos: BlockPos) : RenderedSpell {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos)) if (!ctx.world.mayInteract(ctx.caster, pos))
return return

View file

@ -4,11 +4,11 @@ import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.player.FlightAbility import at.petrak.hexcasting.api.player.FlightAbility
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
import kotlin.math.max
import kotlin.math.roundToInt import kotlin.math.roundToInt
object OpFlight : SpellAction { object OpFlight : SpellAction {
@ -18,9 +18,9 @@ object OpFlight : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<ServerPlayer>(0, argc) val target = args.getPlayer(0, argc)
val timeRaw = max(args.getChecked(1, argc), 0.0) val timeRaw = args.getPositiveDouble(1, argc)
val radiusRaw = max(args.getChecked(2, argc), 0.0) val radiusRaw = args.getPositiveDouble(2, argc)
ctx.assertEntityInRange(target) ctx.assertEntityInRange(target)
// Convert to ticks // Convert to ticks

View file

@ -1,12 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells.great package at.petrak.hexcasting.common.casting.operators.spells.great
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.getChecked
import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getVec3
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LightningBolt import net.minecraft.world.entity.LightningBolt
@ -20,7 +20,7 @@ object OpLightning : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getVec3(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(target)
return Triple( return Triple(
Spell(target), Spell(target),

View file

@ -3,6 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.spells.great
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapImmuneEntity import at.petrak.hexcasting.api.spell.mishaps.MishapImmuneEntity
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway
import at.petrak.hexcasting.common.network.MsgBlinkAck import at.petrak.hexcasting.common.network.MsgBlinkAck
@ -11,6 +12,8 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
// TODO while we're making breaking changes I *really* want to have the vector in the entity's local space
// WRT its look vector
object OpTeleport : SpellAction { object OpTeleport : SpellAction {
override val argc = 2 override val argc = 2
override val isGreat = true override val isGreat = true
@ -18,8 +21,8 @@ object OpTeleport : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val teleportee = args.getChecked<Entity>(0, argc) val teleportee = args.getEntity(0, argc)
val delta = args.getChecked<Vec3>(1, argc) val delta = args.getVec3(1, argc)
ctx.assertEntityInRange(teleportee) ctx.assertEntityInRange(teleportee)
if (!teleportee.canChangeDimensions()) if (!teleportee.canChangeDimensions())
@ -44,6 +47,7 @@ object OpTeleport : SpellAction {
override fun cast(ctx: CastingContext) { override fun cast(ctx: CastingContext) {
val distance = delta.length() val distance = delta.length()
// TODO make this not a magic number (config?)
if (distance < 32768.0) { if (distance < 32768.0) {
teleportee.setPos(teleportee.position().add(delta)) teleportee.setPos(teleportee.position().add(delta))
if (teleportee is ServerPlayer) { if (teleportee is ServerPlayer) {

View file

@ -2,13 +2,12 @@ package at.petrak.hexcasting.common.casting.operators.spells.sentinel
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.player.Sentinel import at.petrak.hexcasting.api.player.Sentinel
import at.petrak.hexcasting.api.spell.getChecked
import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getVec3
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -20,7 +19,7 @@ class OpCreateSentinel(val extendsRange: Boolean) : SpellAction {
args: List<Iota>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc) val target = args.getVec3(0, argc)
ctx.assertVecInRange(target) ctx.assertVecInRange(target)
return Triple( return Triple(

View file

@ -2,8 +2,10 @@ package at.petrak.hexcasting.common.casting.operators.spells.sentinel
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.NullIota
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationInWrongDimension import at.petrak.hexcasting.api.spell.mishaps.MishapLocationInWrongDimension
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
@ -15,8 +17,8 @@ object OpGetSentinelPos : ConstManaAction {
if (sentinel.dimension != ctx.world.dimension()) if (sentinel.dimension != ctx.world.dimension())
throw MishapLocationInWrongDimension(sentinel.dimension.location()) throw MishapLocationInWrongDimension(sentinel.dimension.location())
return if (sentinel.hasSentinel) return if (sentinel.hasSentinel)
sentinel.position.asSpellResult sentinel.position.asActionResult
else else
null.asSpellResult listOf(NullIota.INSTANCE)
} }
} }

View file

@ -2,18 +2,21 @@ package at.petrak.hexcasting.common.casting.operators.spells.sentinel
import at.petrak.hexcasting.api.misc.ManaConstants import at.petrak.hexcasting.api.misc.ManaConstants
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.getVec3
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.NullIota
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationInWrongDimension import at.petrak.hexcasting.api.spell.mishaps.MishapLocationInWrongDimension
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.world.phys.Vec3
// TODO I don't think anyone has ever used this operation in the history of the world.
// TODO standardize "a negligible amount" of media to be 1/8 a dust
object OpGetSentinelWayfind : ConstManaAction { object OpGetSentinelWayfind : ConstManaAction {
override val argc = 1 override val argc = 1
override val manaCost = ManaConstants.DUST_UNIT / 10 override val manaCost = ManaConstants.DUST_UNIT / 10
override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
val from = args.getChecked<Vec3>(0, argc) val from = args.getVec3(0, argc)
val sentinel = IXplatAbstractions.INSTANCE.getSentinel(ctx.caster) val sentinel = IXplatAbstractions.INSTANCE.getSentinel(ctx.caster)
@ -21,8 +24,8 @@ object OpGetSentinelWayfind : ConstManaAction {
throw MishapLocationInWrongDimension(sentinel.dimension.location()) throw MishapLocationInWrongDimension(sentinel.dimension.location())
return if (!sentinel.hasSentinel) return if (!sentinel.hasSentinel)
null.asSpellResult listOf(NullIota.INSTANCE)
else else
sentinel.position.subtract(from).normalize().asSpellResult sentinel.position.subtract(from).normalize().asActionResult
} }
} }

View file

@ -76,7 +76,7 @@ public record MsgCastParticleAck(ParticleSpray spray, FrozenColorizer colorizer)
var color = msg.colorizer().getColor(RANDOM.nextFloat() * 256f, Vec3.ZERO); var color = msg.colorizer().getColor(RANDOM.nextFloat() * 256f, Vec3.ZERO);
var offset = randomInCircle(Mth.TWO_PI).normalize() var offset = randomInCircle(Mth.TWO_PI).normalize()
.scale(RANDOM.nextFloat() * msg.spray().getSpread() / 2); .scale(RANDOM.nextFloat() * msg.spray().getFuzziness() / 2);
var pos = msg.spray().getPos().add(offset); var pos = msg.spray().getPos().add(offset);
var phi = Math.acos(1.0 - RANDOM.nextDouble() * (1.0 - Math.cos(msg.spray().getSpread()))); var phi = Math.acos(1.0 - RANDOM.nextDouble() * (1.0 - Math.cos(msg.spray().getSpread())));

View file

@ -21,6 +21,7 @@ public class HexRecipeSerializers {
private static final Map<ResourceLocation, RecipeSerializer<?>> SERIALIZERS = new LinkedHashMap<>(); private static final Map<ResourceLocation, RecipeSerializer<?>> SERIALIZERS = new LinkedHashMap<>();
// TODO: custom costs in brainsweeping. also custom entities but we'll getting there
public static final RecipeSerializer<?> BRAINSWEEP = register("brainsweep", new BrainsweepRecipe.Serializer()); public static final RecipeSerializer<?> BRAINSWEEP = register("brainsweep", new BrainsweepRecipe.Serializer());
public static RecipeType<BrainsweepRecipe> BRAINSWEEP_TYPE; public static RecipeType<BrainsweepRecipe> BRAINSWEEP_TYPE;
public static final RecipeSerializer<SealFocusRecipe> SEAL_FOCUS = register("seal_focus", public static final RecipeSerializer<SealFocusRecipe> SEAL_FOCUS = register("seal_focus",

View file

@ -1,17 +1,17 @@
package at.petrak.hexcasting.interop.pehkui package at.petrak.hexcasting.interop.pehkui
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.getEntity
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.world.entity.Entity
object OpGetScale : ConstManaAction { object OpGetScale : ConstManaAction {
override val argc = 1 override val argc = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
val target = args.getChecked<Entity>(0) val target = args.getEntity(0, argc)
return IXplatAbstractions.INSTANCE.pehkuiApi.getScale(target).toDouble().asSpellResult return IXplatAbstractions.INSTANCE.pehkuiApi.getScale(target).toDouble().asActionResult
} }
} }

View file

@ -2,19 +2,19 @@ package at.petrak.hexcasting.interop.pehkui
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.util.Mth
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
object OpSetScale : SpellAction { object OpSetScale : SpellAction {
override val argc = 2 override val argc = 2
override fun execute( override fun execute(
args: List<SpellDatum<*>>, args: List<Iota>,
ctx: CastingContext ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> { ): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Entity>(0) val target = args.getEntity(0, argc)
val scale = Mth.clamp(args.getChecked<Double>(1), 1.0 / 32.0, 8.0) val scale = args.getDoubleBetween(1, 1.0 / 32.0, 8.0, argc)
return Triple( return Triple(
Spell(target, scale), Spell(target, scale),

View file

@ -387,6 +387,7 @@
"hexcasting.mishap.invalid_value.numlist": "an integer or list", "hexcasting.mishap.invalid_value.numlist": "an integer or list",
"hexcasting.mishap.invalid_value.list.pattern": "a list of patterns", "hexcasting.mishap.invalid_value.list.pattern": "a list of patterns",
"hexcasting.mishap.invalid_value.double.positive": "a positive number", "hexcasting.mishap.invalid_value.double.positive": "a positive number",
"hexcasting.mishap.invalid_value.double.positive": "a positive number less than %d",
"hexcasting.mishap.invalid_value.double.between": "a number between %d and %d", "hexcasting.mishap.invalid_value.double.between": "a number between %d and %d",
"hexcasting.mishap.invalid_value.int": "an integer", "hexcasting.mishap.invalid_value.int": "an integer",
"hexcasting.mishap.invalid_value.int.positive": "a positive integer", "hexcasting.mishap.invalid_value.int.positive": "a positive integer",

View file

@ -2,6 +2,7 @@ package at.petrak.hexcasting.fabric.interop.gravity
import at.petrak.hexcasting.api.spell.* import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import me.andrew.gravitychanger.api.GravityChangerAPI import me.andrew.gravitychanger.api.GravityChangerAPI
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
@ -10,10 +11,11 @@ import net.minecraft.world.phys.Vec3
object OpChangeGravity : SpellAction { object OpChangeGravity : SpellAction {
override val argc = 2 override val argc = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): override fun execute(args: List<Iota>, ctx: CastingContext):
Triple<RenderedSpell, Int, List<ParticleSpray>> { Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Entity>(0) val target = args.getEntity(0, argc)
val vec = args.getChecked<Vec3>(1) // TODO is it worth making a special "axial vector" getter
val vec = args.getVec3(1, argc)
val snapped = Direction.getNearest(vec.x, vec.y, vec.z) val snapped = Direction.getNearest(vec.x, vec.y, vec.z)
return Triple( return Triple(

View file

@ -1,19 +1,19 @@
package at.petrak.hexcasting.fabric.interop.gravity package at.petrak.hexcasting.fabric.interop.gravity
import at.petrak.hexcasting.api.spell.ConstManaAction import at.petrak.hexcasting.api.spell.ConstManaAction
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getChecked import at.petrak.hexcasting.api.spell.getEntity
import at.petrak.hexcasting.api.spell.iota.Iota
import me.andrew.gravitychanger.api.GravityChangerAPI import me.andrew.gravitychanger.api.GravityChangerAPI
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
object OpGetGravity : ConstManaAction { object OpGetGravity : ConstManaAction {
override val argc = 1 override val argc = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
val target = args.getChecked<Entity>(1) val target = args.getEntity(1)
val grav = GravityChangerAPI.getGravityDirection(target) val grav = GravityChangerAPI.getGravityDirection(target)
return Vec3.atLowerCornerOf(grav.normal).asSpellResult return Vec3.atLowerCornerOf(grav.normal).asActionResult
} }
} }