greater patterns now aren't just spells

Akashic Read is deliberately not a greater pattern, so you can distribute trinkets based on it on a server or something
This commit is contained in:
yrsegal@gmail.com 2022-05-24 17:44:28 -04:00
parent 37df5d3c56
commit 4f0e390c14
9 changed files with 86 additions and 42 deletions

View file

@ -7,8 +7,7 @@ import net.minecraft.world.phys.Vec3
/**
* Manipulates the stack in some way, usually by popping some number of values off the stack
* and pushing one new value.
* For a more "traditional" pop arguments, push return experience, see
* [SimpleOperator][at.petrak.hexcasting.api.spell.ConstManaOperator]
* For a more "traditional" pop arguments, push return experience, see [ConstManaOperator].
*
* Implementors MUST NOT mutate the context.
*/
@ -25,10 +24,22 @@ interface Operator {
fun operate(continuation: SpellContinuation, stack: MutableList<SpellDatum<*>>, local: SpellDatum<*>, ctx: CastingContext): OperationResult
/**
* Do you need to be enlightened to use this operator?
* Do you need to be enlightened to use this operator? (i.e. is this operator a Great Pattern)
*/
val isGreat: Boolean get() = false
/**
* Should this Great Pattern process and have side effects, even if its user isn't enlightened?
*
* The pattern itself may modify its effects based on whether the user is enlightened or not, regardless of what this value is.
*/
val alwaysProcessGreatSpell: Boolean get() = this is SpellOperator
/**
* Can this Great Pattern give you Blind Diversion?
*/
val causesBlindDiversion: Boolean get() = this is SpellOperator
companion object {
// I see why vzakii did this: you can't raycast out to infinity!
const val MAX_DISTANCE: Double = 32.0

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
interface SpellOperator : Operator {
@ -25,13 +25,17 @@ interface SpellOperator : Operator {
val executeResult = this.execute(args, ctx) ?: return OperationResult(continuation, stack, local, listOf())
val (spell, mana, particles) = executeResult
val sideEffects = mutableListOf(
OperatorSideEffect.ConsumeMana(mana),
OperatorSideEffect.AttemptSpell(spell, this.isGreat, this.hasCastingSound(ctx), this.awardsCastingStat(ctx))
)
for (spray in particles) {
val sideEffects = mutableListOf<OperatorSideEffect>()
if (mana > 0)
sideEffects.add(OperatorSideEffect.ConsumeMana(mana))
// 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)))
for (spray in particles)
sideEffects.add(OperatorSideEffect.Particles(spray))
}
return OperationResult(continuation, stack, local, sideEffects)
}

View file

@ -147,15 +147,32 @@ class CastingHarness private constructor(
if (!HexConfig.server().isActionAllowed(operatorIdPair.second)) {
throw MishapDisallowedSpell()
}
val (cont2, stack2, local2, sideEffectsUnmut) = operatorIdPair.first.operate(
continuation,
this.stack.toMutableList(),
this.localIota,
this.ctx
)
this.localIota = local2
val pattern = operatorIdPair.first
val unenlightened = pattern.isGreat && !ctx.isCasterEnlightened
val sideEffects = mutableListOf<OperatorSideEffect>()
var stack2: List<SpellDatum<*>>? = null
var cont2 = continuation
if (!unenlightened || pattern.alwaysProcessGreatSpell) {
val result = pattern.operate(
continuation,
this.stack.toMutableList(),
this.localIota,
this.ctx
)
cont2 = result.newContinuation
stack2 = result.newStack
this.localIota = result.newLocalIota
sideEffects.addAll(result.sideEffects)
}
if (unenlightened) {
sideEffects.add(OperatorSideEffect.RequiredEnlightenment(pattern.causesBlindDiversion))
}
// Stick a poofy particle effect at the caster position
val sideEffects = sideEffectsUnmut.toMutableList()
if (this.ctx.spellCircle == null)
sideEffects.add(
OperatorSideEffect.Particles(
@ -167,9 +184,11 @@ class CastingHarness private constructor(
)
)
val fd = this.getFunctionalData().copy(
stack = stack2,
)
val fd = stack2?.let {
this.getFunctionalData().copy(
stack = it,
)
}
return CastResult(
cont2,
@ -177,6 +196,7 @@ class CastingHarness private constructor(
ResolvedPatternType.EVALUATED,
sideEffects,
)
} catch (mishap: Mishap) {
return CastResult(
continuation,

View file

@ -22,23 +22,28 @@ sealed class OperatorSideEffect {
/** Return whether to cancel all further [OperatorSideEffect] */
abstract fun performEffect(harness: CastingHarness): Boolean
data class RequiredEnlightenment(val awardStat: Boolean) : OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
harness.ctx.caster.sendMessage(
TranslatableComponent("hexcasting.message.cant_great_spell"),
Util.NIL_UUID
)
if (awardStat)
HexAdvancementTriggers.FAIL_GREAT_SPELL_TRIGGER.trigger(harness.ctx.caster)
return true
}
}
/** Try to cast a spell */
data class AttemptSpell(val spell: RenderedSpell, val isGreat: Boolean, val hasCastingSound: Boolean = true, val awardStat: Boolean = true) :
data class AttemptSpell(val spell: RenderedSpell, val hasCastingSound: Boolean = true, val awardStat: Boolean = true) :
OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
return if (this.isGreat && !harness.ctx.isCasterEnlightened) {
harness.ctx.caster.sendMessage(
TranslatableComponent("hexcasting.message.cant_great_spell"),
Util.NIL_UUID
)
HexAdvancementTriggers.FAIL_GREAT_SPELL_TRIGGER.trigger(harness.ctx.caster)
true
} else {
this.spell.cast(harness.ctx)
if (awardStat)
harness.ctx.caster.awardStat(HexStatistics.SPELLS_CAST)
false
}
this.spell.cast(harness.ctx)
if (awardStat)
harness.ctx.caster.awardStat(HexStatistics.SPELLS_CAST)
return false
}
}

View file

@ -1,11 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.akashic
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.SpellDatum
import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.MishapNoAkashicRecord
@ -19,6 +15,8 @@ import net.minecraft.world.phys.Vec3
object OpAkashicWrite : SpellOperator {
override val argc = 3
override val isGreat = true
override fun execute(
args: List<SpellDatum<*>>,
ctx: CastingContext

View file

@ -10,6 +10,8 @@ import net.minecraft.world.phys.Vec3
class OpCircleBounds(val max: Boolean) : ConstManaOperator {
override val argc = 0
override val isGreat = true
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
if (ctx.spellCircle == null)
throw MishapNoSpellCircle()

View file

@ -10,6 +10,8 @@ import at.petrak.hexcasting.api.spell.mishaps.MishapNoSpellCircle
object OpImpetusDir : ConstManaOperator {
override val argc = 0
override val isGreat = true
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
if (ctx.spellCircle == null)
throw MishapNoSpellCircle()

View file

@ -10,6 +10,8 @@ import net.minecraft.world.phys.Vec3
object OpImpetusPos : ConstManaOperator {
override val argc = 0
override val isGreat = true
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
if (ctx.spellCircle == null)
throw MishapNoSpellCircle()

View file

@ -5,8 +5,8 @@ import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
import net.minecraft.Util
@ -18,7 +18,7 @@ object OpPrint : Operator {
val datum = stack[stack.lastIndex]
return OperationResult(
continuation, stack, local, listOf(
OperatorSideEffect.AttemptSpell(Spell(datum), false)
OperatorSideEffect.AttemptSpell(Spell(datum), hasCastingSound = false, awardStat = false)
)
)
}