update destroy water to work on any fluid and add extinguish/ignite fire spells

This commit is contained in:
Noobulus 2022-02-03 15:09:06 -06:00
parent bb60de40f8
commit 7e0723aee1
6 changed files with 177 additions and 4 deletions

View file

@ -98,9 +98,12 @@ public class RegisterPatterns {
OpColorize.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqawqadaq", HexDir.SOUTH_EAST), prefix("create_water"),
OpCreateWater.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dedwedade", HexDir.SOUTH_WEST),
prefix("destroy_water"),
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dedwedade", HexDir.SOUTH_WEST), prefix("destroy_water"),
OpDestroyWater.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddedwdwd", HexDir.EAST), prefix("ignite"),
OpIgnite.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aaqawawa", HexDir.WEST), prefix("extinguish"),
OpExtinguish.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqa", HexDir.NORTH_EAST), prefix("conjure_block"),
new OpConjure(false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqd", HexDir.NORTH_EAST), prefix("conjure_light"),

View file

@ -11,12 +11,12 @@ import net.minecraft.core.Direction
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.tags.FluidTags
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.BucketPickup
import net.minecraft.world.level.block.LiquidBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.material.Fluids
import net.minecraft.world.level.material.Material
import net.minecraft.world.phys.Vec3
@ -42,6 +42,9 @@ object OpDestroyWater : SpellOperator {
val todo = ArrayDeque<BlockPos>()
val seen = HashSet<BlockPos>()
todo.add(BlockPos(target))
for (dir in Direction.values()) { // a little extra range on the initial cast to make it feel more intuitive
todo.add(BlockPos(target).relative(dir))
}
var successes = 0
while (todo.isNotEmpty() && successes <= MAX_DESTROY_COUNT) {
@ -51,7 +54,7 @@ object OpDestroyWater : SpellOperator {
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here)) {
// never seen this pos in my life
val fluid = ctx.world.getFluidState(here)
if (fluid.`is`(FluidTags.WATER)) {
if (fluid != Fluids.EMPTY.defaultFluidState()) {
val blockstate = ctx.world.getBlockState(here)
val material = blockstate.material
val success =

View file

@ -0,0 +1,105 @@
package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.api.Operator
import at.petrak.hexcasting.api.Operator.Companion.getChecked
import at.petrak.hexcasting.api.RenderedSpell
import at.petrak.hexcasting.api.SpellDatum
import at.petrak.hexcasting.api.SpellOperator
import at.petrak.hexcasting.common.casting.CastingContext
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.world.InteractionHand
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.context.UseOnContext
import net.minecraft.world.level.block.*
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.Vec3
object OpExtinguish : SpellOperator {
override val argc = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Triple<RenderedSpell, Int, List<Vec3>> {
val target = args.getChecked<Vec3>(0)
ctx.assertVecInRange(target)
return Triple(
Spell(target),
200_000,
listOf(target)
)
}
const val MAX_DESTROY_COUNT = 1024
private data class Spell(val target: Vec3) : 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))
var successes = 0
while (todo.isNotEmpty() && successes <= MAX_DESTROY_COUNT) {
val here = todo.removeFirst()
val distFromFocus =
ctx.caster.position().distanceToSqr(Vec3(here.x.toDouble(), here.y.toDouble(), here.z.toDouble()))
val distFromTarget =
target.distanceTo(Vec3(here.x.toDouble(), here.y.toDouble(), here.z.toDouble())) // max distance to prevent runaway shenanigans
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here) && distFromTarget < 10) {
// never seen this pos in my life
val blockstate = ctx.world.getBlockState(here)
val success =
when (blockstate.block) {
is BaseFireBlock -> {ctx.world.setBlock(here, Blocks.AIR.defaultBlockState(), 3); true}
is CampfireBlock -> {if (blockstate.getValue(CampfireBlock.LIT)) { // check if campfire is lit before putting it out
val wilson = Items.WOODEN_SHOVEL // summon shovel from the ether to do our bidding
val hereVec = (Vec3(here.x.toDouble(), here.y.toDouble(), here.z.toDouble()))
wilson.useOn(UseOnContext(ctx.world, null, InteractionHand.MAIN_HAND, ItemStack(wilson.asItem()), BlockHitResult(hereVec, Direction.UP, here, false))); true}
else false}
is AbstractCandleBlock -> {
if (blockstate.getValue(AbstractCandleBlock.LIT)) { // same check for candles
AbstractCandleBlock.extinguish(null, blockstate, ctx.world, here); true}
else false}
is NetherPortalBlock -> {ctx.world.setBlock(here, Blocks.AIR.defaultBlockState(), 3); true}
else -> false
}
if (success) {
ctx.world.sendParticles(
ParticleTypes.SMOKE,
here.x + 0.5 + Math.random() * 0.4 - 0.2,
here.y + 0.5 + Math.random() * 0.4 - 0.2,
here.z + 0.5 + Math.random() * 0.4 - 0.2,
2,
0.0,
0.05,
0.0,
0.0
)
successes++
}
for (dir in Direction.values()) {
todo.add(here.relative(dir))
}
}
}
if (successes > 0) {
ctx.world.playSound(
null,
target.x,
target.y,
target.z,
SoundEvents.FIRE_EXTINGUISH,
SoundSource.BLOCKS,
1.0f,
0.95f
)
}
}
}
}

View file

@ -0,0 +1,44 @@
package at.petrak.hexcasting.common.casting.operators.spells
import at.petrak.hexcasting.HexMod
import at.petrak.hexcasting.api.Operator.Companion.getChecked
import at.petrak.hexcasting.api.RenderedSpell
import at.petrak.hexcasting.api.SpellDatum
import at.petrak.hexcasting.api.SpellOperator
import at.petrak.hexcasting.common.casting.CastingContext
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.InteractionHand
import net.minecraft.world.item.FireChargeItem
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.context.UseOnContext
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.Vec3
object OpIgnite : SpellOperator {
override val argc = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Triple<RenderedSpell, Int, List<Vec3>> {
val target = args.getChecked<Vec3>(0)
ctx.assertVecInRange(target)
return Triple(
Spell(target),
10_000,
listOf(target)
)
}
private data class Spell(val target: Vec3) : RenderedSpell {
override fun cast(ctx: CastingContext) {
// steal petra code that steals bucket code
val maxwell = Items.FIRE_CHARGE
if (maxwell is FireChargeItem) {
// help
maxwell.useOn(UseOnContext(ctx.world, null, InteractionHand.MAIN_HAND, ItemStack(maxwell.asItem()), BlockHitResult(target, Direction.UP, BlockPos(target), false)))
} else {
HexMod.getLogger().warn("Items.FIRE_CHARGE wasn't a FireChargeItem?")
}
}
}
}

View file

@ -132,6 +132,8 @@
"hexcasting.spell.hexcasting:erase": "Erase Item",
"hexcasting.spell.hexcasting:create_water": "Create Water",
"hexcasting.spell.hexcasting:destroy_water": "Destroy Water",
"hexcasting.spell.hexcasting:ignite": "Ignite Block",
"hexcasting.spell.hexcasting:extinguish": "Extinguish Area",
"hexcasting.spell.hexcasting:conjure_block": "Conjure Block",
"hexcasting.spell.hexcasting:conjure_light": "Conjure Light",
"hexcasting.spell.hexcasting:bonemeal": "Overgrow",

View file

@ -61,6 +61,22 @@
"input": "vector",
"output": "",
"text": "hexcasting.page.blockworks7"
},
{
"type": "hexcasting:pattern",
"op_id": "hexcasting:ignite",
"anchor": "hexcasting:ignite",
"input": "vector",
"output": "",
"text": "Start a fire on top of the given location, as if a $(item)Fire Charge/$ was applied. Costs about one $(item)Amethyst Dust/$."
},
{
"type": "hexcasting:pattern",
"op_id": "hexcasting:extinguish",
"anchor": "hexcasting:extinguish",
"input": "vector",
"output": "",
"text": "Extinguish blocks in a large area. Costs about two $(item)Amethyst Crystal/$s."
}
]
}