diff --git a/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpSurfaceRaycast.kt b/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpFluidSurfaceRaycast.kt similarity index 96% rename from src/main/java/miyucomics/hexical/casting/patterns/raycast/OpSurfaceRaycast.kt rename to src/main/java/miyucomics/hexical/casting/patterns/raycast/OpFluidSurfaceRaycast.kt index 19d714ba9..2abc7f19a 100644 --- a/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpSurfaceRaycast.kt +++ b/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpFluidSurfaceRaycast.kt @@ -4,7 +4,6 @@ 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.iota.NullIota -import net.minecraft.block.Blocks import net.minecraft.block.FluidBlock import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Vec3d @@ -12,7 +11,7 @@ import java.lang.IllegalStateException import kotlin.math.abs import kotlin.math.floor -class OpSurfaceRaycast : ConstMediaAction { +class OpFluidSurfaceRaycast : ConstMediaAction { override val argc = 2 override fun execute(args: List, ctx: CastingContext): List { val start = args.getVec3(0, argc) diff --git a/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpPiercingRaycast.kt b/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpPiercingRaycast.kt new file mode 100644 index 000000000..c089bfe7a --- /dev/null +++ b/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpPiercingRaycast.kt @@ -0,0 +1,93 @@ +package miyucomics.hexical.casting.patterns.raycast + +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.iota.NullIota +import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota +import miyucomics.hexical.casting.iota.getIdentifier +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import net.minecraft.util.registry.Registry +import java.lang.IllegalStateException +import kotlin.math.abs +import kotlin.math.floor + +class OpPiercingRaycast : ConstMediaAction { + override val argc = 3 + override fun execute(args: List, ctx: CastingContext): List { + val start = args.getVec3(0, argc) + ctx.assertVecInRange(start) + val direction = args.getVec3(1, argc).normalize() + if (direction == Vec3d.ZERO) + return listOf(NullIota()) + val id = args.getIdentifier(2, argc) + if (!Registry.BLOCK.containsId(id)) + throw MishapInvalidIota.of(args[2], 2, "block_id") + val targetBlockType = Registry.BLOCK.get(args.getIdentifier(0, argc)) + val delta = Vec3d(abs(1 / direction.x), abs(1 / direction.y), abs(1 / direction.z)) + + var voxelX = floor(start.x) + var voxelY = floor(start.y) + var voxelZ = floor(start.z) + val stepX: Int + val stepY: Int + val stepZ: Int + var sideDistanceX: Double + var sideDistanceY: Double + var sideDistanceZ: Double + + if (direction.x > 0) { + stepX = 1 + sideDistanceX = (voxelX + 1 - start.x) * delta.x + } else { + stepX = -1 + sideDistanceX = (start.x - voxelX) * delta.x + } + + if (direction.y > 0) { + stepY = 1 + sideDistanceY = (voxelY + 1 - start.y) * delta.y + } else { + stepY = -1 + sideDistanceY = (start.y - voxelY) * delta.y + } + + if (direction.z > 0) { + stepZ = 1 + sideDistanceZ = (voxelZ + 1 - start.z) * delta.z + } else { + stepZ = -1 + sideDistanceZ = (start.z - voxelZ) * delta.z + } + + while (true) { + val (axis, step, offset) = when { + sideDistanceX < sideDistanceY && sideDistanceX < sideDistanceZ -> Triple('X', stepX, delta.x) + sideDistanceY < sideDistanceZ -> Triple('Y', stepY, delta.y) + else -> Triple('Z', stepZ, delta.z) + } + + when (axis) { + 'X' -> { + voxelX += step + sideDistanceX += offset + } + 'Y' -> { + voxelY += step + sideDistanceY += offset + } + 'Z' -> { + voxelZ += step + sideDistanceZ += offset + } + else -> throw IllegalStateException() + } + + if (ctx.world.getBlockState(BlockPos(voxelX, voxelY, voxelZ)).block == targetBlockType) + return Vec3d(voxelX, voxelY, voxelZ).asActionResult + if (!ctx.isVecInRange(Vec3d(voxelX, voxelY, voxelZ))) + return listOf(NullIota()) + } + } +} \ No newline at end of file diff --git a/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpPiercingSurfaceRaycast.kt b/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpPiercingSurfaceRaycast.kt new file mode 100644 index 000000000..5383835bf --- /dev/null +++ b/src/main/java/miyucomics/hexical/casting/patterns/raycast/OpPiercingSurfaceRaycast.kt @@ -0,0 +1,98 @@ +package miyucomics.hexical.casting.patterns.raycast + +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.iota.NullIota +import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota +import miyucomics.hexical.casting.iota.getIdentifier +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import net.minecraft.util.registry.Registry +import java.lang.IllegalStateException +import kotlin.math.abs +import kotlin.math.floor + +class OpPiercingSurfaceRaycast : ConstMediaAction { + override val argc = 3 + override fun execute(args: List, ctx: CastingContext): List { + val start = args.getVec3(0, argc) + ctx.assertVecInRange(start) + val direction = args.getVec3(1, argc).normalize() + if (direction == Vec3d.ZERO) + return listOf(NullIota()) + val id = args.getIdentifier(2, argc) + if (!Registry.BLOCK.containsId(id)) + throw MishapInvalidIota.of(args[2], 2, "block_id") + val targetBlockType = Registry.BLOCK.get(args.getIdentifier(0, argc)) + val delta = Vec3d(abs(1 / direction.x), abs(1 / direction.y), abs(1 / direction.z)) + + var voxelX = floor(start.x) + var voxelY = floor(start.y) + var voxelZ = floor(start.z) + val stepX: Int + val stepY: Int + val stepZ: Int + var sideDistanceX: Double + var sideDistanceY: Double + var sideDistanceZ: Double + + if (direction.x > 0) { + stepX = 1 + sideDistanceX = (voxelX + 1 - start.x) * delta.x + } else { + stepX = -1 + sideDistanceX = (start.x - voxelX) * delta.x + } + + if (direction.y > 0) { + stepY = 1 + sideDistanceY = (voxelY + 1 - start.y) * delta.y + } else { + stepY = -1 + sideDistanceY = (start.y - voxelY) * delta.y + } + + if (direction.z > 0) { + stepZ = 1 + sideDistanceZ = (voxelZ + 1 - start.z) * delta.z + } else { + stepZ = -1 + sideDistanceZ = (start.z - voxelZ) * delta.z + } + + var normal: Vec3d + + while (true) { + val (axis, step, offset) = when { + sideDistanceX < sideDistanceY && sideDistanceX < sideDistanceZ -> Triple('X', stepX, delta.x) + sideDistanceY < sideDistanceZ -> Triple('Y', stepY, delta.y) + else -> Triple('Z', stepZ, delta.z) + } + + when (axis) { + 'X' -> { + voxelX += step + sideDistanceX += offset + normal = Vec3d(-step.toDouble(), 0.0, 0.0) + } + 'Y' -> { + voxelY += step + sideDistanceY += offset + normal = Vec3d(0.0, -step.toDouble(), 0.0) + } + 'Z' -> { + voxelZ += step + sideDistanceZ += offset + normal = Vec3d(0.0, 0.0, -step.toDouble()) + } + else -> throw IllegalStateException() + } + + if (ctx.world.getBlockState(BlockPos(voxelX, voxelY, voxelZ)).block == targetBlockType) + return normal.asActionResult + if (!ctx.isVecInRange(Vec3d(voxelX, voxelY, voxelZ))) + return listOf(NullIota()) + } + } +} \ No newline at end of file diff --git a/src/main/java/miyucomics/hexical/registry/HexicalPatterns.kt b/src/main/java/miyucomics/hexical/registry/HexicalPatterns.kt index 4791576c3..adc25fd00 100644 --- a/src/main/java/miyucomics/hexical/registry/HexicalPatterns.kt +++ b/src/main/java/miyucomics/hexical/registry/HexicalPatterns.kt @@ -37,7 +37,8 @@ import miyucomics.hexical.casting.patterns.mage_blocks.OpModifyMageBlock import miyucomics.hexical.casting.patterns.prestidigitation.OpCanPrestidigitation import miyucomics.hexical.casting.patterns.prestidigitation.OpPrestidigitation import miyucomics.hexical.casting.patterns.raycast.OpFluidRaycast -import miyucomics.hexical.casting.patterns.raycast.OpSurfaceRaycast +import miyucomics.hexical.casting.patterns.raycast.OpFluidSurfaceRaycast +import miyucomics.hexical.casting.patterns.raycast.OpPiercingRaycast import miyucomics.hexical.casting.patterns.soroban.OpSorobanDecrement import miyucomics.hexical.casting.patterns.soroban.OpSorobanIncrement import miyucomics.hexical.casting.patterns.soroban.OpSorobanReset @@ -68,6 +69,11 @@ object HexicalPatterns { registerPerWorld("conjure_mesh", "qaqqqqqwqqqdeeweweeaeewewee", HexDir.EAST, OpConjureMesh()) register("weave_mesh", "qaqqqqqwqqqdeewewee", HexDir.EAST, OpWeaveMesh()) + register("fluid_raycast", "wqqaqwede", HexDir.EAST, OpFluidRaycast()) + register("fluid_surface_raycast", "weedewqaq", HexDir.EAST, OpFluidSurfaceRaycast()) + register("piercing_raycast", "wqqddqeqddq", HexDir.EAST, OpPiercingRaycast()) + register("piercing_surface_raycast", "weeaaeqeaae", HexDir.EAST, OpPiercingRaycast()) + register("mimic_dye", "awddwqaeqqqeaeqqq", HexDir.EAST, OpMimicDye()) register("perlin", "qawedqdq", HexDir.WEST, OpPerlin()) @@ -219,9 +225,6 @@ object HexicalPatterns { register("is_baby", "awaqdwaaw", HexDir.SOUTH_WEST, OpGetLivingEntityData(6)) register("breedable", "awaaqdqaawa", HexDir.EAST, OpGetBreed()) - register("fluid_raycast", "wqqaqwede", HexDir.EAST, OpFluidRaycast()) - register("surface_raycast", "weedewqaq", HexDir.EAST, OpSurfaceRaycast()) - register("get_enchantments", "waqeaeqawqwawaw", HexDir.WEST, OpGetItemStackData(2)) register("get_enchantment_strength", "waqwwqaweede", HexDir.WEST, OpGetEnchantmentStrength()) diff --git a/src/main/resources/assets/hexical/lang/en_us.json b/src/main/resources/assets/hexical/lang/en_us.json index 94b8b01e4..2d1a069c6 100644 --- a/src/main/resources/assets/hexical/lang/en_us.json +++ b/src/main/resources/assets/hexical/lang/en_us.json @@ -138,10 +138,6 @@ "hexical.page.lightning_rod_staff.1": "$(o)I learned there are troubles$(br2)Of more than one kind.$(br2)Some come from ahead$(br2)And some come from behind.$(br2)But I've bought a big bat.$(br)I'm all ready, you see.$(br)Now my troubles are going$(br)To have troubles with $(l)me!$()", "hexical.page.simple.title": "Hexical Patterns", - "hexcasting.spell.hexical:fluid_raycast": "Naval Distillation", - "hexical.page.fluid_raycast.summary": "Works similar to $(l:patterns/basics#hexcasting:raycast)Archer's Distillation$() but targets liquids, piercing through all other blocks.", - "hexcasting.spell.hexical:surface_raycast": "Lilypad Distillation", - "hexical.page.surface_raycast.summary": "Works similar to $(l:patterns/basics#hexcasting:raycast/axis)Architect's Distillation$() but targets liquids, piercing through all other blocks.", "hexcasting.spell.hexical:theodolite": "Theodolite's Purification", "hexical.page.theodolite.summary": "Like Alidade's Purification but rather than the entity's facing vector, it pushes the vector that points upwards from their head.", "hexcasting.spell.hexical:dup_many": "Dioscuri Gambit II", @@ -263,6 +259,16 @@ "hexcasting.spell.hexical:set_arch_lamp_storage": "Archgenie Gambit", "hexical.page.get_arch_lamp_storage.summary": "Gets the lamp's iota storage.", + "hexical.page.special_raycasts.title": "Special Raycasts", + "hexcasting.spell.hexical:fluid_raycast": "Naval Distillation", + "hexical.page.fluid_raycast.summary": "Works similar to $(l:patterns/basics#hexcasting:raycast)Archer's Distillation$() but targets only liquids, piercing through all other blocks.", + "hexcasting.spell.hexical:fluid_surface_raycast": "Lilypad Distillation", + "hexical.page.fluid_surface_raycast.summary": "Works similar to $(l:patterns/basics#hexcasting:raycast/axis)Architect's Distillation$() but targets only liquids, piercing through all other blocks.", + "hexcasting.spell.hexical:piercing_raycast": "Railgun Exaltation", + "hexical.page.piercing_raycast.summary": "Works similar to $(l:patterns/basics#hexcasting:raycast)Archer's Distillation$() but accepts an additional identifier. It will pierce all blocks until it hits the block specified by the identifier.", + "hexcasting.spell.hexical:piercing_surface_raycast": "Laser Exaltation", + "hexical.page.piercing_surface_raycast.summary": "Works similar to $(l:patterns/basics#hexcasting:raycast/axis)Architect's Distillation$() but accepts an additional identifier. It will pierce all blocks until it hits the block specified by the identifier.", + "hexical.page.conjure_compass.title": "Conjured Compasses", "hexcasting.spell.hexical:conjure_compass": "Conjure Compass", "hexical.page.conjure_compass.summary": "Conjures a compass at the location pointing towards the second vector. Costs one shard.", @@ -581,4 +587,4 @@ "hexical.page.meshes.1": "The mesh must be woven to have any appearance. The constraints for the list of vectors provided to a mesh are quite minimal. The list must be no more than 32 vectors long, and those vectors must have magnitudes less than 10. The mesh will then connect each of those points, defined by the relative offset, to each other.", "hexcasting.spell.hexical:weave_mesh": "Weave Mesh", "hexical.page.weave_mesh.summary": "Takes a list of vectors, with constraints defined on the prior page, and weaves the mesh into that shape for free." -} +} \ No newline at end of file diff --git a/src/main/resources/data/hexical/patchouli_books/hexicalbook/en_us/entries/patterns/simple.json b/src/main/resources/data/hexical/patchouli_books/hexicalbook/en_us/entries/patterns/simple.json index 4f3247fa3..2e637c2dd 100644 --- a/src/main/resources/data/hexical/patchouli_books/hexicalbook/en_us/entries/patterns/simple.json +++ b/src/main/resources/data/hexical/patchouli_books/hexicalbook/en_us/entries/patterns/simple.json @@ -5,20 +5,6 @@ "advancement": "hexcasting:root", "pages": [ { - "type": "hexcasting:pattern", - "op_id": "hexical:fluid_raycast", - "anchor": "hexical:fluid_raycast", - "input": "vector, vector", - "output": "vector", - "text": "hexical.page.fluid_raycast.summary" - }, { - "type": "hexcasting:pattern", - "op_id": "hexical:surface_raycast", - "anchor": "hexical:surface_raycast", - "input": "vector, vector", - "output": "vector", - "text": "hexical.page.surface_raycast.summary" - }, { "type": "hexcasting:pattern", "op_id": "hexical:theodolite", "anchor": "hexical:theodolite", @@ -111,4 +97,4 @@ "text": "hexical.page.themis.1" } ] -} +} \ No newline at end of file diff --git a/src/main/resources/data/hexical/patchouli_books/hexicalbook/en_us/entries/patterns/special_raycasts.json b/src/main/resources/data/hexical/patchouli_books/hexicalbook/en_us/entries/patterns/special_raycasts.json new file mode 100644 index 000000000..4e949fc17 --- /dev/null +++ b/src/main/resources/data/hexical/patchouli_books/hexicalbook/en_us/entries/patterns/special_raycasts.json @@ -0,0 +1,37 @@ +{ + "name": "hexical.page.special_raycasts.title", + "icon": "minecraft:spectral_arrow", + "category": "hexcasting:patterns", + "advancement": "hexcasting:root", + "pages": [ + { + "type": "hexcasting:pattern", + "op_id": "hexical:fluid_raycast", + "anchor": "hexical:fluid_raycast", + "input": "vector, vector", + "output": "vector/null", + "text": "hexical.page.fluid_raycast.summary" + }, { + "type": "hexcasting:pattern", + "op_id": "hexical:fluid_surface_raycast", + "anchor": "hexical:fluid_surface_raycast", + "input": "vector, vector", + "output": "vector/null", + "text": "hexical.page.fluid_surface_raycast.summary" + }, { + "type": "hexcasting:pattern", + "op_id": "hexical:piercing_raycast", + "anchor": "hexical:piercing_raycast", + "input": "vector, vector, identifier", + "output": "vector/null", + "text": "hexical.page.piercing_raycast.summary" + }, { + "type": "hexcasting:pattern", + "op_id": "hexical:piercing_surface_raycast", + "anchor": "hexical:piercing_surface_raycast", + "input": "vector, vector, identifier", + "output": "vector/null", + "text": "hexical.page.piercing_surface_raycast.summary" + } + ] +} \ No newline at end of file