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.SpellContinuation
import at.petrak.hexcasting.api.spell.iota.Iota
/**
* 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.world.entity.Entity
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.npc.Villager
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")
}
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) }
if (x is EntityIota) {
val e = x.entity
if (e is LivingEntity)
if (e is LivingEntity && e !is ArmorStand)
return e
}
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")
}
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 {
val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) }
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.OperatorSideEffect
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
interface SpellAction : Action {
@ -17,7 +18,12 @@ interface SpellAction : Action {
ctx: CastingContext
): 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)
throw MishapNotEnoughArgs(this.argc, stack.size)
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
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)
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.ParticleSpray
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.ListIota
import at.petrak.hexcasting.api.spell.iota.NullIota
@ -116,7 +115,7 @@ class CastingHarness private constructor(
listOf(
OperatorSideEffect.DoMishap(
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(
OperatorSideEffect.DoMishap(
MishapError(exception),
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null)
Mishap.Context((iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST), null)
)
)
)
@ -273,82 +272,95 @@ class CastingHarness private constructor(
* either escaping it onto the stack or changing the parenthese-handling state.
*/
private fun handleParentheses(iota: Iota): Pair<FunctionalData, ResolvedPatternType>? {
val operator = (iota.payload as? HexPattern)?.let {
try {
PatternRegistry.matchPattern(it, this.ctx.world)
} catch (mishap: Mishap) {
null
}
if (iota !is PatternIota) {
throw IllegalStateException()
}
val sig = iota.pattern.anglesSignature()
return if (this.parenCount > 0) {
if (this.parenCount > 0) {
if (this.escapeNext) {
val newParens = this.parenthesized.toMutableList()
newParens.add(iota)
this.getFunctionalData().copy(
return this.getFunctionalData().copy(
escapeNext = false,
parenthesized = newParens
) to ResolvedPatternType.ESCAPED
} else if (operator == Widget.ESCAPE) {
this.getFunctionalData().copy(
escapeNext = true,
) to ResolvedPatternType.EVALUATED
} else if (operator == Widget.OPEN_PAREN) {
// we have escaped the parens onto the stack; we just also record our count.
val newParens = this.parenthesized.toMutableList()
newParens.add(iota)
this.getFunctionalData().copy(
parenthesized = newParens,
parenCount = this.parenCount + 1
) to if (this.parenCount == 0) ResolvedPatternType.EVALUATED else ResolvedPatternType.ESCAPED
} else if (operator == Widget.CLOSE_PAREN) {
val newParenCount = this.parenCount - 1
if (newParenCount == 0) {
val newStack = this.stack.toMutableList()
newStack.add(ListIota(this.parenthesized.toList()))
}
return when (sig) {
SpecialPatterns.CONSIDERATION.anglesSignature() -> {
this.getFunctionalData().copy(
stack = newStack,
parenCount = newParenCount,
parenthesized = listOf()
escapeNext = true,
) to ResolvedPatternType.EVALUATED
} else if (newParenCount < 0) {
throw MishapTooManyCloseParens()
} else {
// we have this situation: "(()"
// we need to add the close paren
}
SpecialPatterns.INTROSPECTION.anglesSignature() -> {
// we have escaped the parens onto the stack; we just also record our count.
val newParens = this.parenthesized.toMutableList()
newParens.add(iota)
this.getFunctionalData().copy(
parenthesized = newParens,
parenCount = this.parenCount + 1
) to if (this.parenCount == 0) ResolvedPatternType.EVALUATED else ResolvedPatternType.ESCAPED
}
SpecialPatterns.RETROSPECTION.anglesSignature() -> {
val newParenCount = this.parenCount - 1
if (newParenCount == 0) {
val newStack = this.stack.toMutableList()
newStack.add(ListIota(this.parenthesized.toList()))
this.getFunctionalData().copy(
stack = newStack,
parenCount = newParenCount,
parenthesized = listOf()
) to ResolvedPatternType.EVALUATED
} else if (newParenCount < 0) {
throw MishapTooManyCloseParens()
} else {
// we have this situation: "(()"
// we need to add the close paren
val newParens = this.parenthesized.toMutableList()
newParens.add(iota)
this.getFunctionalData().copy(
parenCount = newParenCount,
parenthesized = newParens
) to ResolvedPatternType.ESCAPED
}
}
else -> {
val newParens = this.parenthesized.toMutableList()
newParens.add(iota)
this.getFunctionalData().copy(
parenCount = newParenCount,
parenthesized = newParens
) to ResolvedPatternType.ESCAPED
}
} else {
val newParens = this.parenthesized.toMutableList()
newParens.add(iota)
this.getFunctionalData().copy(
parenthesized = newParens
) to ResolvedPatternType.ESCAPED
}
} else if (this.escapeNext) {
}
if (this.escapeNext) {
val newStack = this.stack.toMutableList()
newStack.add(iota)
this.getFunctionalData().copy(
return this.getFunctionalData().copy(
stack = newStack,
escapeNext = false,
) to ResolvedPatternType.ESCAPED
} else if (operator == Widget.ESCAPE) {
this.getFunctionalData().copy(
escapeNext = true
) to ResolvedPatternType.EVALUATED
} else if (operator == Widget.OPEN_PAREN) {
this.getFunctionalData().copy(
parenCount = this.parenCount + 1
) to ResolvedPatternType.EVALUATED
} else if (operator == Widget.CLOSE_PAREN) {
throw MishapTooManyCloseParens()
} else {
null
}
return when (sig) {
SpecialPatterns.CONSIDERATION.anglesSignature() -> {
this.getFunctionalData().copy(
escapeNext = true
) to ResolvedPatternType.EVALUATED
}
SpecialPatterns.INTROSPECTION.anglesSignature() -> {
this.getFunctionalData().copy(
parenCount = this.parenCount + 1
) to ResolvedPatternType.EVALUATED
}
SpecialPatterns.RETROSPECTION.anglesSignature() -> {
throw MishapTooManyCloseParens()
}
else -> {
null
}
}
}

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
public int color() {
return 0;
return 0xff_55ffff;
}
};
}

View file

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

View file

@ -14,6 +14,10 @@ import org.jetbrains.annotations.Nullable;
public class NullIota extends Iota {
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 NullIota() {

View file

@ -5,6 +5,8 @@ import at.petrak.hexcasting.common.lib.HexIotaTypes;
import net.minecraft.nbt.LongArrayTag;
import net.minecraft.nbt.Tag;
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.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
@ -52,7 +54,16 @@ public class Vec3Iota extends Iota {
@Override
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.mod.HexItemTags
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.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.api.utils.lightPurple

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell.mishaps
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.iota.Iota
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.Entity
import net.minecraft.world.item.DyeColor
@ -17,5 +17,5 @@ class MishapEntityTooFarAway(val entity: Entity) : Mishap() {
}
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
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.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.GarbageIota
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.world.item.DyeColor
class MishapInvalidPattern : Mishap() {
@ -14,7 +14,7 @@ class MishapInvalidPattern : Mishap() {
override fun resolutionType(ctx: CastingContext) = ResolvedPatternType.INVALID
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) =

View file

@ -1,9 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps
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.iota.GarbageIota
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.DyeColor
@ -13,9 +13,9 @@ class MishapLocationInWrongDimension(val properDimension: ResourceLocation) : Mi
dyeColor(DyeColor.MAGENTA)
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 =
error(
"wrong_dimension", actionName(errorCtx.action!!), properDimension.toString(),

View file

@ -1,8 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps
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.iota.Iota
import at.petrak.hexcasting.api.spell.iota.Vec3Iota
import net.minecraft.network.chat.Component
import net.minecraft.world.item.DyeColor
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 =
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
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 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
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)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
for (i in got until expected)
stack.add(LegacySpellDatum.make(Widget.GARBAGE))
repeat(expected - got) { stack.add(NullIota.INSTANCE) }
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context) =

View file

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

View file

@ -1,9 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
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
class MishapTooManyCloseParens : Mishap() {
@ -11,7 +11,8 @@ class MishapTooManyCloseParens : Mishap() {
dyeColor(DyeColor.ORANGE)
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) =

View file

@ -3,7 +3,9 @@ package at.petrak.hexcasting.common.casting;
import at.petrak.hexcasting.api.PatternRegistry;
import at.petrak.hexcasting.api.misc.ManaConstants;
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.HexDir;
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"),
OpExtinguish.INSTANCE);
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"),
new OpConjure(true));
new OpConjureBlock(true));
PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqwawqaqw", HexDir.NORTH_EAST), modLoc("bonemeal"),
OpTheOnlyReasonAnyoneDownloadedPsi.INSTANCE);
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwaeaeaeaeaea", HexDir.NORTH_WEST),
@ -315,11 +317,9 @@ public class RegisterPatterns {
// == Meta stuff ==
PatternRegistry.mapPattern(HexPattern.fromAngles("qqq", HexDir.WEST), modLoc("open_paren"),
Widget.OPEN_PAREN);
PatternRegistry.mapPattern(HexPattern.fromAngles("eee", HexDir.EAST), modLoc("close_paren"),
Widget.CLOSE_PAREN);
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqaw", HexDir.WEST), modLoc("escape"), Widget.ESCAPE);
// Intro/Retro/Consideration are now special-form-likes and aren't even ops.
// TODO should there be a registry for these too
// http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf
// eval being a space filling curve feels apt doesn't it
PatternRegistry.mapPattern(HexPattern.fromAngles("deaqq", HexDir.SOUTH_EAST), modLoc("eval"),
@ -348,32 +348,33 @@ public class RegisterPatterns {
// == 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"),
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"),
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"),
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"),
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"),
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"),
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.
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"),
Action.makeConstantOp(LegacySpellDatum.make(Math.PI)));
Action.makeConstantOp(new DoubleIota(Math.PI)));
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
PatternRegistry.mapPattern(HexPattern.fromAngles("aaq", HexDir.EAST), modLoc("const/double/e"),
Action.makeConstantOp(LegacySpellDatum.make(Math.E)));
Action.makeConstantOp(new DoubleIota(Math.E)));
// == Entities ==
@ -489,7 +490,7 @@ public class RegisterPatterns {
if (negate) {
accumulator = -accumulator;
}
return Action.makeConstantOp(LegacySpellDatum.make(accumulator));
return Action.makeConstantOp(new DoubleIota(accumulator));
} else {
return null;
}

View file

@ -1,8 +1,9 @@
package at.petrak.hexcasting.common.casting.operators.circles
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.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle
import net.minecraft.world.phys.Vec3
@ -16,8 +17,8 @@ class OpCircleBounds(val max: Boolean) : ConstManaAction {
val aabb = ctx.spellCircle.aabb
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
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.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.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle
object OpImpetusDir : ConstManaAction {
@ -16,6 +17,6 @@ object OpImpetusDir : ConstManaAction {
val pos = ctx.spellCircle.impetusPos
val bs = ctx.world.getBlockState(pos)
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
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.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle
@ -12,6 +13,6 @@ object OpImpetusPos : ConstManaAction {
if (ctx.spellCircle == null)
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.asActionResult
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.iota.Iota
@ -11,7 +10,7 @@ object OpAppend : ConstManaAction {
override val argc = 2
override fun execute(args: List<Iota>, ctx: CastingContext): List<Iota> {
val list = args.getList(0, argc).toMutableList()
val datum = args.getIota(1)
val datum = args[1]
list.add(datum)
return list.asActionResult
}

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.lists
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.getList
import at.petrak.hexcasting.api.spell.iota.Iota
@ -9,6 +10,6 @@ import at.petrak.hexcasting.api.spell.iota.Iota
object OpListSize : ConstManaAction {
override val argc = 1
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> {
val list = args.getList(0, 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
}
}

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.asActionResult
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.getIota
import at.petrak.hexcasting.api.spell.iota.Iota
object OpSingleton : ConstManaAction {
override val argc = 1
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
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.getLong
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> {
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
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.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.*
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.phys.Vec3
@ -18,8 +15,8 @@ object OpAddMotion : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Entity>(0, argc)
val motion = args.getChecked<Vec3>(1, argc)
val target = args.getEntity(0, argc)
val motion = args.getVec3(1, argc)
ctx.assertEntityInRange(target)
var motionForCost = motion.lengthSqr()
if (ctx.hasBeenGivenMotion(target))

View file

@ -1,12 +1,9 @@
package at.petrak.hexcasting.common.casting.operators.spells
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.RenderedSpell
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.SpellAction
import at.petrak.hexcasting.api.spell.*
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.xplat.IXplatAbstractions
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
@ -19,9 +16,9 @@ object OpBeep : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
val instrument = args.getChecked<Double>(1, argc).toInt().coerceIn(0, NoteBlockInstrument.values().size - 1)
val note = args.getChecked<Double>(2, argc).toInt().coerceIn(0, 24)
val target = args.getVec3(0, argc)
val instrument = args.getPositiveIntUnder(1, NoteBlockInstrument.values().size, argc)
val note = args.getPositiveIntUnder(2, 24, argc) // mojang don't have magic numbers challenge
ctx.assertVecInRange(target)
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.spell.*
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.MishapLocationTooFarAway
import at.petrak.hexcasting.common.network.MsgBlinkAck
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import kotlin.math.max
import kotlin.math.roundToInt
object OpBlink : SpellAction {
@ -18,8 +18,8 @@ object OpBlink : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Entity>(0, argc)
val delta = max(0.0, args.getChecked(1, argc))
val target = args.getEntity(0, argc)
val delta = args.getDouble(1, argc)
ctx.assertEntityInRange(target)
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.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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos
import net.minecraft.world.phys.Vec3
@ -16,21 +20,18 @@ object OpBreakBlock : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val pos = args.getChecked<Vec3>(0, argc)
val pos = args.getBlockPos(0, argc)
ctx.assertVecInRange(pos)
val centered = Vec3.atCenterOf(BlockPos(pos))
return Triple(
Spell(pos),
(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) {
val pos = BlockPos(v)
if (!ctx.world.mayInteract(ctx.caster, pos))
return

View file

@ -1,8 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells
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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock
import at.petrak.hexcasting.common.blocks.BlockConjured
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.phys.Vec3
class OpConjure(val light: Boolean) : SpellAction {
class OpConjureBlock(val light: Boolean) : SpellAction {
override val argc = 1
override fun execute(
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
val target = args.getChecked<Vec3>(0, argc)
ctx.assertVecInRange(target)
val pos = BlockPos(target)
val pos = args.getBlockPos(0, argc)
ctx.assertVecInRange(pos)
if (!ctx.world.mayInteract(ctx.caster, pos))
return null
@ -34,16 +36,14 @@ class OpConjure(val light: Boolean) : SpellAction {
throw MishapBadBlock.of(pos, "replaceable")
return Triple(
Spell(target, light),
Spell(pos, light),
ManaConstants.DUST_UNIT,
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) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
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.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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos
import net.minecraft.world.item.BucketItem
@ -21,20 +25,17 @@ object OpCreateWater : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
ctx.assertVecInRange(target)
val target = args.getBlockPos(0, argc)
return Triple(
Spell(target),
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) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
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.spell.*
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.Direction
import net.minecraft.core.particles.ParticleTypes
@ -23,25 +24,23 @@ object OpDestroyWater : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target)
return Triple(
Spell(target),
2 * ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.burst(target, 3.0))
listOf(ParticleSpray.burst(Vec3.atCenterOf(target), 3.0))
)
}
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) {
// SpongeBlock.java
val todo = ArrayDeque<BlockPos>()
val seen = HashSet<BlockPos>()
val basePos = BlockPos(target)
// 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) {
@ -53,7 +52,10 @@ object OpDestroyWater : SpellAction {
val here = todo.removeFirst()
val distFromFocus =
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
val fluid = ctx.world.getFluidState(here)
if (fluid != Fluids.EMPTY.defaultFluidState()) {
@ -104,9 +106,9 @@ object OpDestroyWater : SpellAction {
if (successes > 0) {
ctx.world.playSound(
null,
target.x,
target.y,
target.z,
basePos.x.toDouble(),
basePos.y.toDouble(),
basePos.z.toDouble(),
SoundEvents.FIRE_EXTINGUISH,
SoundSource.BLOCKS,
1.0f,

View file

@ -1,12 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells
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.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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock
import at.petrak.hexcasting.common.misc.AkashicTreeGrower
import net.minecraft.core.BlockPos
@ -20,18 +20,15 @@ object OpEdifySapling : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val pos = args.getChecked<Vec3>(0, argc)
ctx.assertVecInRange(pos)
val bpos = BlockPos(pos)
val bs = ctx.world.getBlockState(bpos)
val pos = args.getBlockPos(0, argc)
val bs = ctx.world.getBlockState(pos)
if (!bs.`is`(BlockTags.SAPLINGS))
throw MishapBadBlock.of(bpos, "sapling")
throw MishapBadBlock.of(pos, "sapling")
return Triple(
Spell(bpos),
Spell(pos),
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.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos
import net.minecraft.util.Mth
import net.minecraft.world.level.Explosion
import net.minecraft.world.phys.Vec3
@ -16,15 +16,14 @@ class OpExplode(val fire: Boolean) : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val pos = args.getChecked<Vec3>(0, argc)
val strength = args.getChecked<Double>(1, argc)
val pos = args.getVec3(0, argc)
val strength = args.getPositiveDoubleUnder(1, 10.0, argc)
ctx.assertVecInRange(pos)
val clampedStrength = Mth.clamp(strength, 0.0, 10.0)
val cost = ManaConstants.DUST_UNIT * (3 * clampedStrength + if (fire) 0.125 else 1.0)
val cost = ManaConstants.DUST_UNIT * (3 * strength + if (fire) 0.125 else 1.0)
return Triple(
Spell(pos, clampedStrength, this.fire),
Spell(pos, strength, this.fire),
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.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.ktxt.UseOnContext
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
@ -22,37 +23,35 @@ object OpExtinguish : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target)
return Triple(
Spell(target),
ManaConstants.DUST_UNIT * 6,
listOf(ParticleSpray.burst(target, 1.0))
listOf(ParticleSpray.burst(Vec3.atCenterOf(target), 1.0))
)
}
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) {
// how many levels of "borrowed" code are we on now
val todo = ArrayDeque<BlockPos>()
val seen = HashSet<BlockPos>()
todo.add(BlockPos(target))
todo.add(target)
var successes = 0
while (todo.isNotEmpty() && successes <= MAX_DESTROY_COUNT) {
val here = todo.removeFirst()
val distFromFocus =
ctx.caster.position().distanceToSqr(Vec3.atCenterOf(here))
val distFromTarget =
target.distanceTo(Vec3.atCenterOf(here)) // max distance to prevent runaway shenanigans
if (distFromFocus < Action.MAX_DISTANCE * Action.MAX_DISTANCE && seen.add(here) && distFromTarget < 10 && ctx.world.mayInteract(
ctx.caster,
here
)
val distFromTarget = target.distSqr(here) // max distance to prevent runaway shenanigans
if (distFromFocus < Action.MAX_DISTANCE * Action.MAX_DISTANCE
&& seen.add(here)
&& distFromTarget < 10 * 10
&& ctx.world.mayInteract(ctx.caster, here)
) {
// never seen this pos in my life
val blockstate = ctx.world.getBlockState(here)
@ -110,9 +109,9 @@ object OpExtinguish : SpellAction {
if (successes > 0) {
ctx.world.playSound(
null,
target.x,
target.y,
target.z,
target.x.toDouble(),
target.y.toDouble(),
target.z.toDouble(),
SoundEvents.FIRE_EXTINGUISH,
SoundSource.BLOCKS,
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.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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.ktxt.UseOnContext
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
@ -20,7 +24,7 @@ object OpIgnite : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target)
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) {
val pos = BlockPos(target)
// TODO should we do these checks in the action part of the spell
if (!ctx.world.mayInteract(ctx.caster, pos))
return
@ -46,7 +50,7 @@ object OpIgnite : SpellAction {
null,
InteractionHand.MAIN_HAND,
ItemStack(maxwell.asItem()),
BlockHitResult(target, Direction.UP, pos, false)
BlockHitResult(Vec3.atCenterOf(pos), Direction.UP, pos, false)
)
)
} 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.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.getItemEntity
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.api.utils.extractMana
@ -22,7 +26,7 @@ object OpMakeBattery : SpellAction {
args: List<Iota>,
ctx: CastingContext
): 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) }

View file

@ -1,12 +1,8 @@
package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.spell.getChecked
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.*
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.MishapBadOffhandItem
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>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val entity = args.getChecked<ItemEntity>(0, argc)
val patterns = args.getChecked<SpellList>(1, argc).toList()
val entity = args.getItemEntity(0, argc)
val patterns = args.getList(1, argc).toList()
val (handStack, hand) = ctx.getHeldItemToOperateOn {
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(it)

View file

@ -1,8 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells
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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBlock
import net.minecraft.core.BlockPos
import net.minecraft.core.particles.BlockParticleOption
@ -23,10 +27,8 @@ object OpPlaceBlock : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
val target = args.getChecked<Vec3>(0, argc)
ctx.assertVecInRange(target)
val pos = BlockPos(target)
val pos = args.getBlockPos(0, argc)
ctx.assertVecInRange(pos)
if (!ctx.world.mayInteract(ctx.caster, pos))
return null
@ -43,16 +45,14 @@ object OpPlaceBlock : SpellAction {
throw MishapBadBlock.of(pos, "replaceable")
return Triple(
Spell(target),
Spell(pos),
ManaConstants.DUST_UNIT / 8,
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) {
val pos = BlockPos(vec)
if (!ctx.world.mayInteract(ctx.caster, pos))
return
@ -86,11 +86,15 @@ object OpPlaceBlock : SpellAction {
ctx.world.playSound(
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()
)
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.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.MobEffectInstance
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.decoration.ArmorStand
import kotlin.math.max
class OpPotionEffect(
val effect: MobEffect,
@ -23,14 +21,13 @@ class OpPotionEffect(
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<LivingEntity>(0, argc)
if (target is ArmorStand)
throw MishapInvalidIota.ofType(LegacySpellDatum.make(target), 0, LivingEntity::class.java)
val duration = max(args.getChecked(1, argc), 0.0)
ctx.assertEntityInRange(target)
val target = args.getLivingEntityButNotArmorStand(0, argc)
val duration = args.getPositiveDouble(1, argc)
val potency = if (this.allowPotency)
args.getChecked<Double>(2, argc).coerceIn(1.0, 128.0)
args.getPositiveDoubleUnder(2, 127.0, argc)
else 1.0
ctx.assertEntityInRange(target)
val cost = this.baseCost * duration * if (potencyCubic) {
potency * potency * potency

View file

@ -1,17 +1,23 @@
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.OperationResult
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.OperatorSideEffect
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 net.minecraft.Util
// TODO should this dump the whole stack
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()) {
throw MishapNotEnoughArgs(1, 0)
}

View file

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

View file

@ -1,8 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells
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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.InteractionHand
@ -19,21 +23,18 @@ object OpTheOnlyReasonAnyoneDownloadedPsi : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
ctx.assertVecInRange(target)
val target = args.getBlockPos(0, argc)
return Triple(
Spell(target),
(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) {
// 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))
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.spell.*
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.MishapBadBrainsweep
import at.petrak.hexcasting.common.misc.Brainsweeping
@ -22,30 +23,32 @@ object OpBrainsweep : SpellAction {
override val isGreat = true
// this way you can hear the villager dying more : )
override fun hasCastingSound(ctx: CastingContext) = false
override fun execute(
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val sacrifice = args.getChecked<Villager>(0, argc)
val pos = args.getChecked<Vec3>(1, argc)
val sacrifice = args.getVillager(0, argc)
val pos = args.getBlockPos(1, argc)
ctx.assertVecInRange(pos)
ctx.assertEntityInRange(sacrifice)
if (Brainsweeping.isBrainswept(sacrifice))
throw MishapAlreadyBrainswept(sacrifice)
val bpos = BlockPos(pos)
val state = ctx.world.getBlockState(bpos)
val state = ctx.world.getBlockState(pos)
val recman = ctx.world.recipeManager
val recipes = recman.getAllRecipesFor(HexRecipeSerializers.BRAINSWEEP_TYPE)
val recipe = recipes.find { it.matches(state, sacrifice) }
?: throw MishapBadBrainsweep(sacrifice, bpos)
?: throw MishapBadBrainsweep(sacrifice, pos)
return Triple(
Spell(bpos, state, sacrifice, recipe),
Spell(pos, state, sacrifice, recipe),
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.misc.ManaConstants
import at.petrak.hexcasting.api.spell.getChecked
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.getBlockPos
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos
import net.minecraft.world.item.BucketItem
@ -25,7 +25,7 @@ object OpCreateLava : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
val target = args.getBlockPos(0, argc)
ctx.assertVecInRange(target)
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) {
val pos = BlockPos(target)
if (!ctx.world.mayInteract(ctx.caster, pos))
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.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.phys.Vec3
import kotlin.math.max
import kotlin.math.roundToInt
object OpFlight : SpellAction {
@ -18,9 +18,9 @@ object OpFlight : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<ServerPlayer>(0, argc)
val timeRaw = max(args.getChecked(1, argc), 0.0)
val radiusRaw = max(args.getChecked(2, argc), 0.0)
val target = args.getPlayer(0, argc)
val timeRaw = args.getPositiveDouble(1, argc)
val radiusRaw = args.getPositiveDouble(2, argc)
ctx.assertEntityInRange(target)
// Convert to ticks

View file

@ -1,12 +1,12 @@
package at.petrak.hexcasting.common.casting.operators.spells.great
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.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.getVec3
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LightningBolt
@ -20,7 +20,7 @@ object OpLightning : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
val target = args.getVec3(0, argc)
ctx.assertVecInRange(target)
return Triple(
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.spell.*
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.MishapLocationTooFarAway
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.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 {
override val argc = 2
override val isGreat = true
@ -18,8 +21,8 @@ object OpTeleport : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val teleportee = args.getChecked<Entity>(0, argc)
val delta = args.getChecked<Vec3>(1, argc)
val teleportee = args.getEntity(0, argc)
val delta = args.getVec3(1, argc)
ctx.assertEntityInRange(teleportee)
if (!teleportee.canChangeDimensions())
@ -44,6 +47,7 @@ object OpTeleport : SpellAction {
override fun cast(ctx: CastingContext) {
val distance = delta.length()
// TODO make this not a magic number (config?)
if (distance < 32768.0) {
teleportee.setPos(teleportee.position().add(delta))
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.player.Sentinel
import at.petrak.hexcasting.api.spell.getChecked
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.getVec3
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.world.phys.Vec3
@ -20,7 +19,7 @@ class OpCreateSentinel(val extendsRange: Boolean) : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
val target = args.getChecked<Vec3>(0, argc)
val target = args.getVec3(0, argc)
ctx.assertVecInRange(target)
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.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.iota.Iota
import at.petrak.hexcasting.api.spell.iota.NullIota
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationInWrongDimension
import at.petrak.hexcasting.xplat.IXplatAbstractions
@ -15,8 +17,8 @@ object OpGetSentinelPos : ConstManaAction {
if (sentinel.dimension != ctx.world.dimension())
throw MishapLocationInWrongDimension(sentinel.dimension.location())
return if (sentinel.hasSentinel)
sentinel.position.asSpellResult
sentinel.position.asActionResult
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.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.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.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 {
override val argc = 1
override val manaCost = ManaConstants.DUST_UNIT / 10
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)
@ -21,8 +24,8 @@ object OpGetSentinelWayfind : ConstManaAction {
throw MishapLocationInWrongDimension(sentinel.dimension.location())
return if (!sentinel.hasSentinel)
null.asSpellResult
listOf(NullIota.INSTANCE)
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 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 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<>();
// 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 RecipeType<BrainsweepRecipe> BRAINSWEEP_TYPE;
public static final RecipeSerializer<SealFocusRecipe> SEAL_FOCUS = register("seal_focus",

View file

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

View file

@ -387,6 +387,7 @@
"hexcasting.mishap.invalid_value.numlist": "an integer or list",
"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 less than %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.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.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import me.andrew.gravitychanger.api.GravityChangerAPI
import net.minecraft.core.Direction
import net.minecraft.world.entity.Entity
@ -10,10 +11,11 @@ import net.minecraft.world.phys.Vec3
object OpChangeGravity : SpellAction {
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>> {
val target = args.getChecked<Entity>(0)
val vec = args.getChecked<Vec3>(1)
val target = args.getEntity(0, argc)
// 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)
return Triple(

View file

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