HexCasting/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/Mishap.kt

113 lines
4.1 KiB
Kotlin

package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.pigment.FrozenPigment
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.api.utils.lightPurple
import at.petrak.hexcasting.common.lib.HexItems
import at.petrak.hexcasting.ktxt.*
import net.minecraft.Util
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
abstract class Mishap : Throwable() {
/** Mishaps spray half-red, half-this-color. */
abstract fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment
open fun particleSpray(ctx: CastingEnvironment): ParticleSpray {
return ParticleSpray(
ctx.mishapSprayPos().add(0.0, 0.2, 0.0),
Vec3(0.0, 2.0, 0.0),
0.2, Math.PI / 4, 40)
}
open fun resolutionType(ctx: CastingEnvironment): ResolvedPatternType = ResolvedPatternType.ERRORED
/**
* Execute the actual effect, not any sfx.
*
* You can also mess up the stack with this.
*/
abstract fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>)
protected abstract fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component
/**
* Every error message should be prefixed with the name of the action...
*/
public fun errorMessageWithName(ctx: CastingEnvironment, errorCtx: Context): Component {
return if (errorCtx.name != null) {
"hexcasting.mishap".asTranslatedComponent(errorCtx.name, this.errorMessage(ctx, errorCtx))
} else {
this.errorMessage(ctx, errorCtx)
}
}
// Useful helper functions
protected fun dyeColor(color: DyeColor): FrozenPigment =
FrozenPigment(
ItemStack(HexItems.DYE_COLORIZERS[color]!!),
Util.NIL_UUID
)
protected fun error(stub: String, vararg args: Any): Component =
"hexcasting.mishap.$stub".asTranslatedComponent(*args)
protected fun actionName(name: Component?): Component =
name ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple
protected fun blockAtPos(ctx: CastingEnvironment, pos: BlockPos): Component {
return ctx.world.getBlockState(pos).block.name
}
data class Context(val pattern: HexPattern, val name: Component?)
companion object {
@JvmStatic
fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {
entity.setHurtWithStamp(source, entity.level.gameTime)
val targetHealth = entity.health - amount
if (entity.invulnerableTime > 10) {
val lastHurt = entity.lastHurt
if (lastHurt < amount)
entity.invulnerableTime = 0
else
entity.lastHurt -= amount
}
if (!entity.hurt(source, amount) &&
!entity.isInvulnerableTo(source) &&
!entity.level.isClientSide &&
!entity.isDeadOrDying
) {
// Ok, if you REALLY don't want to play nice...
entity.health = targetHealth
entity.markHurt()
if (entity.isDeadOrDying) {
if (!entity.checkTotemDeathProtection(source)) {
val sound = entity.deathSoundAccessor
if (sound != null) {
entity.playSound(sound, entity.soundVolumeAccessor, entity.voicePitch)
}
entity.die(source)
}
} else {
entity.playHurtSound(source)
}
}
}
}
}