diff --git a/build.gradle b/build.gradle index 39a6b3d5..a67fcc20 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ apply plugin: 'maven-publish' apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.parchmentmc.librarian.forgegradle' -version = '0.2.1' +version = '0.3.0' group = 'at.petra-k.hexcasting' // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = 'hexcasting' diff --git a/src/main/java/at/petrak/hexcasting/HexConfig.java b/src/main/java/at/petrak/hexcasting/HexConfig.java index 0de7af9c..3b0eea72 100644 --- a/src/main/java/at/petrak/hexcasting/HexConfig.java +++ b/src/main/java/at/petrak/hexcasting/HexConfig.java @@ -20,7 +20,7 @@ public class HexConfig { public HexConfig(ForgeConfigSpec.Builder builder) { manaToHealthRate = builder.comment("How many points of mana a half-heart is worth when casting from HP") - .defineInRange("manaToHealthRate", 100_000.0 / 20.0, 0.0, Double.POSITIVE_INFINITY); + .defineInRange("manaToHealthRate", 200_000.0 / 20.0, 0.0, Double.POSITIVE_INFINITY); patternPointSpeedMultiplier = builder.comment( "How fast the point showing you the stroke order on patterns moves") .defineInRange("manaToHealthRate", 1.0, 0.0, Double.POSITIVE_INFINITY); diff --git a/src/main/java/at/petrak/hexcasting/common/casting/CastingContext.kt b/src/main/java/at/petrak/hexcasting/common/casting/CastingContext.kt index ee332640..c4cbff98 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/CastingContext.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/CastingContext.kt @@ -58,14 +58,16 @@ data class CastingContext( } } - + /** + * Check to make sure a vec is in range + */ fun assertVecInRange(vec: Vec3) { if (vec.distanceToSqr(this.caster.position()) > Operator.MAX_DISTANCE * Operator.MAX_DISTANCE) throw CastException(CastException.Reason.TOO_FAR, vec) } /** - * Return the slot from which to take blocks and itempicking.json. + * Return the slot from which to take blocks and itemsn. */ // https://wiki.vg/Inventory is WRONG // slots 0-8 are the hotbar @@ -97,7 +99,7 @@ data class CastingContext( } /** - * Remove the given gound of the specified item from somewhere in the inventory, favoring slots not in the hotbar. + * Remove the given count of the specified item from somewhere in the inventory, favoring slots not in the hotbar. * Return whether the withdrawal was successful. */ // https://github.com/VazkiiMods/Psi/blob/master/src/main/java/vazkii/psi/common/spell/trick/block/PieceTrickPlaceBlock.java#L143 diff --git a/src/main/java/at/petrak/hexcasting/common/casting/CastingHarness.kt b/src/main/java/at/petrak/hexcasting/common/casting/CastingHarness.kt index 7c9ffac0..8a56d5c7 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/CastingHarness.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/CastingHarness.kt @@ -87,6 +87,13 @@ class CastingHarness private constructor( // we know the operator is ok here val (manaCost, spells) = operator!!.modifyStack(this.stack, this.ctx) + + val leftover = this.withdrawMana(manaCost, ctx.canOvercast) + if (ctx.caster.isDeadOrDying) + return CastResult.Died + else if (leftover > 0) + return CastResult.QuitCasting + // is great IMPLIES caster is enlightened if (!operator.isGreat || ctx.isCasterEnlightened) { spellsToCast = spells @@ -94,9 +101,6 @@ class CastingHarness private constructor( Advancements.FAIL_GREAT_SPELL_TRIGGER.trigger(ctx.caster) } - this.withdrawMana(manaCost, ctx.canOvercast) - if (ctx.caster.isDeadOrDying) - return CastResult.Died } if (spellsToCast.isNotEmpty()) { diff --git a/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java b/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java index 89094fd8..908bb632 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java +++ b/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java @@ -14,8 +14,10 @@ import at.petrak.hexcasting.common.casting.operators.selectors.OpGetCaster; import at.petrak.hexcasting.common.casting.operators.selectors.OpGetEntitiesBy; import at.petrak.hexcasting.common.casting.operators.selectors.OpGetEntityAt; import at.petrak.hexcasting.common.casting.operators.spells.*; +import at.petrak.hexcasting.common.casting.operators.spells.great.OpCreateLava; import at.petrak.hexcasting.common.casting.operators.spells.great.OpFlight; import at.petrak.hexcasting.common.casting.operators.spells.great.OpLightning; +import at.petrak.hexcasting.common.casting.operators.spells.great.OpTeleport; import at.petrak.hexcasting.common.items.magic.ItemArtifact; import at.petrak.hexcasting.common.items.magic.ItemCypher; import at.petrak.hexcasting.common.items.magic.ItemTrinket; @@ -100,12 +102,19 @@ public class RegisterPatterns { new OpMakePackagedSpell<>(ItemTrinket.class, 500_000)); PatternRegistry.addRegularPattern("wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq", new OpMakePackagedSpell<>(ItemArtifact.class, 1_000_000)); + PatternRegistry.addRegularPattern("aqawqadaq", OpCreateWater.INSTANCE); + PatternRegistry.addRegularPattern("dedwedade", OpDestroyWater.INSTANCE); PatternRegistry.addRegularPatternPerWorld(HexPattern.FromAnglesSig("waadwawdaaweewq", HexDir.EAST), prefix("lightning"), OpLightning.INSTANCE); PatternRegistry.addRegularPatternPerWorld(HexPattern.FromAnglesSig("eawwaeawawaa", HexDir.NORTH_EAST), prefix("flight"), OpFlight.INSTANCE); + PatternRegistry.addRegularPatternPerWorld(HexPattern.FromAnglesSig("eaqawqadaqd", HexDir.EAST), + prefix("create_lava"), OpCreateLava.INSTANCE); + PatternRegistry.addRegularPatternPerWorld( + HexPattern.FromAnglesSig("wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq", HexDir.EAST), + prefix("teleport"), OpTeleport.INSTANCE); // == Meta stuff == PatternRegistry.addRegularPattern("qqq", Widget.OPEN_PAREN); diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpBlink.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpBlink.kt index 2a46be53..96a3d619 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpBlink.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpBlink.kt @@ -21,6 +21,7 @@ object OpBlink : SpellOperator { val delta = args.getChecked(1) ctx.assertVecInRange(target.position()) + ctx.assertVecInRange(target.position().add(target.lookAngle.scale(delta))) return Pair( Spell(target, delta), @@ -28,7 +29,7 @@ object OpBlink : SpellOperator { ) } - class Spell(val target: Entity, val delta: Double) : RenderedSpell { + private data class Spell(val target: Entity, val delta: Double) : RenderedSpell { override fun cast(ctx: CastingContext) { val look = target.lookAngle // https://github.com/VazkiiMods/Psi/blob/master/src/main/java/vazkii/psi/common/spell/trick/entity/PieceTrickBlink.java#L74 diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpCreateWater.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpCreateWater.kt new file mode 100644 index 00000000..0c190ff5 --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpCreateWater.kt @@ -0,0 +1,38 @@ +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.world.item.BucketItem +import net.minecraft.world.item.Items +import net.minecraft.world.phys.Vec3 + +object OpCreateWater : SpellOperator { + override val argc = 1 + override fun execute(args: List>, ctx: CastingContext): Pair { + val target = args.getChecked(0) + ctx.assertVecInRange(target) + + return Pair( + Spell(target), + 10_000 + ) + } + + private data class Spell(val target: Vec3) : RenderedSpell { + override fun cast(ctx: CastingContext) { + // Just steal bucket code lmao + val charlie = Items.WATER_BUCKET + if (charlie is BucketItem) { + // make the player null so we don't give them a usage statistic for example + charlie.emptyContents(null, ctx.world, BlockPos(target), null) + } else { + HexMod.getLogger().warn("Items.WATER_BUCKET wasn't a BucketItem?") + } + } + } +} \ No newline at end of file diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpDestroyWater.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpDestroyWater.kt new file mode 100644 index 00000000..bb40e963 --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpDestroyWater.kt @@ -0,0 +1,112 @@ +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.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.Material +import net.minecraft.world.phys.Vec3 + +object OpDestroyWater : SpellOperator { + override val argc = 1 + override fun execute(args: List>, ctx: CastingContext): Pair { + val target = args.getChecked(0) + ctx.assertVecInRange(target) + + return Pair( + Spell(target), + 200_000 + ) + } + + const val MAX_DESTROY_COUNT = 1024 + + private data class Spell(val target: Vec3) : RenderedSpell { + + override fun cast(ctx: CastingContext) { + // SpongeBlock.java + val todo = ArrayDeque() + val seen = HashSet() + 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())) + 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)) { + val blockstate = ctx.world.getBlockState(here) + val material = blockstate.material + val success = + if (blockstate.block is BucketPickup && !(blockstate.block as BucketPickup).pickupBlock( + ctx.world, + here, + blockstate + ).isEmpty + ) { + true + } else if (blockstate.block is LiquidBlock) { + ctx.world.setBlock(here, Blocks.AIR.defaultBlockState(), 3) + true + } else if (material == Material.WATER_PLANT || material == Material.REPLACEABLE_WATER_PLANT) { + val blockentity: BlockEntity? = + if (blockstate.hasBlockEntity()) ctx.world.getBlockEntity(here) else null + Block.dropResources(blockstate, ctx.world, here, blockentity) + 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 + ) + } + } + } +} \ No newline at end of file diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpCreateLava.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpCreateLava.kt new file mode 100644 index 00000000..c352b9bf --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpCreateLava.kt @@ -0,0 +1,39 @@ +package at.petrak.hexcasting.common.casting.operators.spells.great + +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.world.item.BucketItem +import net.minecraft.world.item.Items +import net.minecraft.world.phys.Vec3 + +object OpCreateLava : SpellOperator { + override val argc = 1 + override val isGreat = true + override fun execute(args: List>, ctx: CastingContext): Pair { + val target = args.getChecked(0) + ctx.assertVecInRange(target) + + return Pair( + Spell(target), + 100_000 + ) + } + + private data class Spell(val target: Vec3) : RenderedSpell { + override fun cast(ctx: CastingContext) { + // Just steal bucket code lmao + val charlie = Items.LAVA_BUCKET + if (charlie is BucketItem) { + // make the player null so we don't give them a usage statistic for example + charlie.emptyContents(null, ctx.world, BlockPos(target), null) + } else { + HexMod.getLogger().warn("Items.LAVA_BUCKET wasn't a BucketItem?") + } + } + } +} \ No newline at end of file diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpLightning.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpLightning.kt index ca54444a..1ac16e3c 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpLightning.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpLightning.kt @@ -18,7 +18,7 @@ object OpLightning : SpellOperator { ctx.assertVecInRange(target) return Pair( Spell(target), - 1_500_000 + 150_000 ) } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpTeleport.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpTeleport.kt new file mode 100644 index 00000000..2c564d81 --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/great/OpTeleport.kt @@ -0,0 +1,44 @@ +package at.petrak.hexcasting.common.casting.operators.spells.great + +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 at.petrak.hexcasting.common.network.HexMessages +import at.petrak.hexcasting.common.network.MsgBlinkAck +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.entity.Entity +import net.minecraft.world.phys.Vec3 +import net.minecraftforge.network.PacketDistributor + +object OpTeleport : SpellOperator { + override val argc = 2 + override val isGreat = true + override fun execute(args: List>, ctx: CastingContext): Pair { + val teleportee = args.getChecked(0) + val delta = args.getChecked(1) + + ctx.assertVecInRange(teleportee.position()) + return Pair( + Spell(teleportee, delta), + 1_000_000 + ) + } + + private data class Spell(val teleportee: Entity, val delta: Vec3) : RenderedSpell { + override fun cast(ctx: CastingContext) { + if (delta.lengthSqr() < 32678.0 * 32678.0) { + teleportee.setPos(teleportee.position().add(delta)) + if (teleportee is ServerPlayer) { + HexMessages.getNetwork().send(PacketDistributor.PLAYER.with { teleportee }, MsgBlinkAck(delta)) + } + } + + if (teleportee is ServerPlayer) { + teleportee.inventory.dropAll() + } + } + + } +} \ No newline at end of file diff --git a/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java b/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java index 03c3d7dc..d80f03ac 100644 --- a/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java +++ b/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java @@ -88,8 +88,9 @@ public class ItemScroll extends Item { if (this.pattern != null) { // Do two passes: one with a random size to find a good COM and one with the real calculations + // TODO: i should never have been finding the center of mass, but the center of the smallest bounding square var com1 = this.pattern.getCenter(1); - var lines1 = this.pattern.toLines(1, com1.negated()); + var lines1 = this.pattern.toLines(1, Vec2.ZERO); var maxDist = -1f; @@ -99,7 +100,7 @@ public class ItemScroll extends Item { maxDist = dist; } } - this.scale = Math.min(10, this.getHeight() / 1.5f / maxDist); + this.scale = Math.min(10, this.getHeight() / 2.5f / maxDist); var com2 = this.pattern.getCenter(this.scale); var lines2 = this.pattern.toLines(this.scale, com2.negated()); diff --git a/src/main/resources/assets/hexcasting/lang/en_us.json b/src/main/resources/assets/hexcasting/lang/en_us.json index d1c15d25..9b356330 100644 --- a/src/main/resources/assets/hexcasting/lang/en_us.json +++ b/src/main/resources/assets/hexcasting/lang/en_us.json @@ -30,5 +30,7 @@ "stat.hexcasting.mana_overcasted": "Media overcasted (in dusts)", "itemGroup.hexcasting": "hexcasting", "hexcasting.spell.hexcasting:flight": "Flight", - "hexcasting.spell.hexcasting:lightning": "Summon Lightning" + "hexcasting.spell.hexcasting:lightning": "Summon Lightning", + "hexcasting.spell.hexcasting:create_lava": "Create Lava", + "hexcasting.spell.hexcasting:teleport": "Greater Teleport" } diff --git a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/patterns.json b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/patterns.json deleted file mode 100644 index 4d734983..00000000 --- a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/greatwork/patterns.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "Great Spells", - "category": "hexcasting:greatwork", - "icon": "minecraft:textures/mob_effect/conduit_power.png", - "sortnum": 0, - "advancement": "hexcasting:enlightenment", - "entry_color": "54398a", - "pages": [ - { - "type": "hexcasting:pattern", - "header": "Flight", - "anchor": "OpFlight", - "input": "entity, number, number", - "output": "", - "text": "The power of flight! I have wrestled Nature to its knees. But Nature is vengeful, and itches for me to break its contract so it may break my shins.", - "patterns": { - "startdir": "NORTH_WEST", - "signature": "eawwaeawawaa" - } - }, - { - "type": "patchouli:text", - "text": "The entity (which must be a player) will receive the power of flight. The first number is the number of seconds they may fly for, and the second number is the radius of the zone they may fly in. If the recipient exits that zone, or their timer runs out while midair, the gravity that they spurned will get its revenge. Painfully.$(br2)It costs approximately 1 $(item)Amethyst Dust/$ multiplied by the radius, per second of flight." - }, - { - "type": "hexcasting:pattern", - "header": "Smite", - "anchor": "OpLightning", - "input": "vector", - "output": "", - "text": "I command the heavens! This spell will summon a bolt of lightning to strike the earth where I direct it.$(p)...I should probably not cast it on my own location.", - "hex_size": 6, - "patterns": { - "startdir": "EAST", - "signature": "waadwawdaaweewq" - } - } - ] -} diff --git a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json index 60c402d9..f23c8045 100644 --- a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json +++ b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/basic.json @@ -1,70 +1,66 @@ { - "name": "Basic Spells", - "category": "hexcasting:patterns/spells", - "icon": "minecraft:bookshelf", - "sortnum": 0, - "advancement": "hexcasting:root", - "read_by_default": true, - "pages": [ - { - "type": "hexcasting:pattern", - "header": "Explosion", - "anchor": "OpExplode", - "input": "vector, number", - "output": "", - "text": "Remove a number and vector from the stack, then create an explosion at the given location with the given power.", - "stroke_order": false, - "patterns": { - "startdir": "EAST", - "signature": "aawaawaa" - } - }, - { - "type": "patchouli:text", - "text": "A power of 3 is about as much as a Creeper's blast; 4 is about as much as a TNT blast. Nature refuses to give me a blast of more than 10 power, though.$(br2)Costs about one $(item)Amethyst Shard/$, plus an extra $(item)Amethyst Shard/$ per point of explosion power." - }, - { - "type": "hexcasting:pattern", - "header": "Fireball", - "anchor": "OpExplodeFire", - "input": "vector, number", - "output": "", - "stroke_order": false, - "text": "Remove a number and vector from the stack, then create a fiery explosion at the given location with the given power.", - "patterns": { - "startdir": "EAST", - "signature": "aawqaqwaa" - } - }, - { - "type": "patchouli:text", - "text": "Costs three $(item)Amethyst Shards/$, plus about one extra $(item)Amethyst Shard/$ per point of explosion power. Otherwise, the same as $(l:hexcasting:patterns/spells/basic#OpExplode)$(action)Explosion/$, except with fire." - }, - { - "type": "hexcasting:pattern", - "header": "Impulse", - "anchor": "OpAddMotion", - "input": "entity, vector", - "output": "", - "stroke_order": false, - "text": "Remove an entity and direction from the stack, then give a push to the given entity in the given direction. The strength of the impulse is determined by the length of the vector.$(br)Costs units of $(item)Amethyst Dust/$ proportional to the square of the length of the vector; thus a push vector of length 5 would consume five $(item)Amethyst Shards$(0) or equivalent.", - "patterns": { - "startdir": "EAST", - "signature": "waqwaeawq" - } - }, - { - "type": "hexcasting:pattern", - "header": "Blink", - "anchor": "OpBlink", - "input": "entity, number", - "output": "", - "stroke_order": false, - "text": "Remove an entity and length from the stack, then teleport the given entity along its look vector by the given length.$(br)Costs about 2 $(item)Amethyst Dust/$s times the square of the distance teleported-- thus, teleporting 5 blocks would cost five $(item)Charged Amethyst Crystals$(0) or equivalent.", - "patterns": { - "startdir": "EAST", - "signature": "aqwaeawq" - } - } - ] + "name": "Basic Spells", + "category": "hexcasting:patterns/spells", + "icon": "minecraft:bookshelf", + "sortnum": 0, + "advancement": "hexcasting:root", + "read_by_default": true, + "pages": [ + { + "type": "hexcasting:pattern", + "header": "Explosion", + "anchor": "OpExplode", + "input": "vector, number", + "output": "", + "text": "Remove a number and vector from the stack, then create an explosion at the given location with the given power.", + "patterns": { + "startdir": "EAST", + "signature": "aawaawaa" + } + }, + { + "type": "patchouli:text", + "text": "A power of 3 is about as much as a Creeper's blast; 4 is about as much as a TNT blast. Nature refuses to give me a blast of more than 10 power, though.$(br2)Costs about one $(item)Amethyst Shard/$, plus an extra $(item)Amethyst Shard/$ per point of explosion power." + }, + { + "type": "hexcasting:pattern", + "header": "Fireball", + "anchor": "OpExplodeFire", + "input": "vector, number", + "output": "", + "text": "Remove a number and vector from the stack, then create a fiery explosion at the given location with the given power.", + "patterns": { + "startdir": "EAST", + "signature": "aawqaqwaa" + } + }, + { + "type": "patchouli:text", + "text": "Costs three $(item)Amethyst Shards/$, plus about one extra $(item)Amethyst Shard/$ per point of explosion power. Otherwise, the same as $(l:hexcasting:patterns/spells/basic#OpExplode)$(action)Explosion/$, except with fire." + }, + { + "type": "hexcasting:pattern", + "header": "Impulse", + "anchor": "OpAddMotion", + "input": "entity, vector", + "output": "", + "text": "Remove an entity and direction from the stack, then give a push to the given entity in the given direction. The strength of the impulse is determined by the length of the vector.$(br)Costs units of $(item)Amethyst Dust/$ proportional to the square of the length of the vector; thus a push vector of length 5 would consume five $(item)Amethyst Shards$(0) or equivalent.", + "patterns": { + "startdir": "EAST", + "signature": "waqwaeawq" + } + }, + { + "type": "hexcasting:pattern", + "header": "Blink", + "anchor": "OpBlink", + "input": "entity, number", + "output": "", + "text": "Remove an entity and length from the stack, then teleport the given entity along its look vector by the given length.$(br)Costs about 2 $(item)Amethyst Dust/$s times the square of the distance teleported-- thus, teleporting 5 blocks would cost five $(item)Charged Amethyst Crystals$(0) or equivalent.", + "patterns": { + "startdir": "EAST", + "signature": "aqwaeawq" + } + } + ] } diff --git a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json index f4a2ad65..79b9ab3e 100644 --- a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json +++ b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/blockworks.json @@ -1,36 +1,58 @@ { - "name": "Blockworks", - "category": "hexcasting:patterns/spells", - "icon": "minecraft:cobblestone", - "sortnum": 1, - "advancement": "hexcasting:root", - "read_by_default": true, - "pages": [ - { - "type": "hexcasting:pattern", - "header": "Place Block", - "anchor": "OpPlaceBlock", - "input": "vector", - "output": "", - "text": "Remove a location from the stack, then pick a block item and place it at the given location.$(br)Costs about 1 $(item)Amethyst Dust/$.", - "stroke_order": false, - "patterns": { - "startdir": "EAST", - "signature": "weeeeedqe" - } - }, - { - "type": "hexcasting:pattern", - "header": "Break Block", - "anchor": "OpBreakBlock", - "input": "vector", - "output": "", - "text": "Remove a location from the stack, then break the block at the given location. This spell can break nearly anything a Diamond Pickaxe can break.$(br)Costs about 3 $(item)Amethyst Dust/$s.", - "stroke_order": false, - "patterns": { - "startdir": "SOUTH_EAST", - "signature": "eeeeede" - } - } - ] + "name": "Blockworks", + "category": "hexcasting:patterns/spells", + "icon": "minecraft:cobblestone", + "sortnum": 1, + "advancement": "hexcasting:root", + "read_by_default": true, + "pages": [ + { + "type": "hexcasting:pattern", + "header": "Place Block", + "anchor": "OpPlaceBlock", + "input": "vector", + "output": "", + "text": "Remove a location from the stack, then pick a block item and place it at the given location.$(br)Costs about 1 $(item)Amethyst Dust/$.", + "patterns": { + "startdir": "EAST", + "signature": "eeeeede" + } + }, + { + "type": "hexcasting:pattern", + "header": "Break Block", + "anchor": "OpBreakBlock", + "input": "vector", + "output": "", + "text": "Remove a location from the stack, then break the block at the given location. This spell can break nearly anything a Diamond Pickaxe can break.$(br)Costs about 3 $(item)Amethyst Dust/$s.", + "patterns": { + "startdir": "SOUTH_EAST", + "signature": "qaqqqqq" + } + }, + { + "type": "hexcasting:pattern", + "header": "Create Water", + "anchor": "OpCreateWater", + "input": "vector", + "output": "", + "text": "Summon a block of water or insert a bucket's worth into a block at the given position. Costs about one $(item)Amethyst Dust/$.", + "patterns": { + "startdir": "SOUTH_EAST", + "signature": "aqawqadaq" + } + }, + { + "type": "hexcasting:pattern", + "header": "Destroy Water", + "anchor": "OpDestroyWater", + "input": "vector", + "output": "", + "text": "Destroy a great deal of water around the given position. Costs about two $(item)Amethyst Crystal/$s.", + "patterns": { + "startdir": "SOUTH_WEST", + "signature": "dedwedade" + } + } + ] } diff --git a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/great.json b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/great.json new file mode 100644 index 00000000..ff9f3eee --- /dev/null +++ b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/great.json @@ -0,0 +1,71 @@ +{ + "name": "Great Spells", + "category": "hexcasting:patterns/spells", + "icon": "minecraft:textures/mob_effect/conduit_power.png", + "sortnum": 3, + "advancement": "hexcasting:root", + "pages": [ + { + "type": "hexcasting:pattern", + "header": "Smite", + "anchor": "OpLightning", + "input": "vector", + "output": "", + "stroke_order": false, + "text": "I command the heavens! This spell will summon a bolt of lightning to strike the earth where I direct it. Costs about 3 $(item)Amethyst Shard/$s.", + "hex_size": 6, + "patterns": { + "startdir": "EAST", + "signature": "waadwawdaaweewq" + } + }, + { + "type": "hexcasting:pattern", + "header": "Create Lava", + "anchor": "OpCreateLava", + "input": "vector", + "output": "", + "stroke_order": false, + "text": "Summon a block of lava or insert a bucket's worth into a block at the given position. Costs about one $(item)Charged Amethyst/$.", + "patterns": { + "startdir": "EAST", + "signature": "eaqawqadaqd" + } + }, + { + "type": "hexcasting:pattern", + "header": "Flight", + "anchor": "OpFlight", + "input": "entity, number, number", + "output": "", + "stroke_order": false, + "text": "The power of flight! I have wrestled Nature to its knees. But Nature is vengeful, and itches for me to break its contract so it may break my shins.", + "patterns": { + "startdir": "NORTH_WEST", + "signature": "eawwaeawawaa" + } + }, + { + "type": "patchouli:text", + "text": "The entity (which must be a player) will be endowed with flight. The first number is the number of seconds they may fly for, and the second number is the radius of the zone they may fly in. If the recipient exits that zone, or their timer runs out while midair, the gravity that they spurned will get its revenge. Painfully.$(br2)It costs approximately 1 $(item)Amethyst Dust/$ multiplied by the radius, per second of flight." + }, + { + "type": "hexcasting:pattern", + "header": "Greater Teleport", + "anchor": "OpTeleport", + "input": "entity, vector", + "output": "", + "stroke_order": false, + "hex_size": 8, + "text": "Far more powerful than $(l:patterns/spells/basic#OpBlink)$(action)Blink/$, this spell lets me teleport nearly anywhere in the entire world! There does seem to be a limit, but it is $(italic)much/$ greater than the normal radius of influence I am used to.", + "patterns": { + "startdir": "WEST", + "signature": "wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq" + } + }, + { + "type": "patchouli:text", + "text": "The entity will be teleported by the given vector, which is an offset from its given position. No matter the distance, it always seems to cost about ten $(item)Charged Crystal/$s.$(br2)The transference is not perfect, and it seems when teleporting something as complex as a player, their inventory doesn't $(italic)quite/$ stay attached." + } + ] +} diff --git a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json index b10bab60..892da18d 100644 --- a/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json +++ b/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/spells/hexcasting.json @@ -1,55 +1,52 @@ { - "name": "Crafting Hexcasting Items", - "category": "hexcasting:patterns/spells", - "icon": "hexcasting:artifact{patterns:[]}", - "sortnum": 2, - "advancement": "hexcasting:root", - "read_by_default": true, - "pages": [ - { - "type": "patchouli:text", - "text": "These three spells each create an item that casts a _Hex.$(br)They all require me to hold the empty item in my off-hand, and require two things: the list of patterns to be cast, and an entity representing a dropped stack of $(item)Amethyst/$ to form the item's battery.$(br2)See $(l:items/hexcasting)this entry/$ for more information." - }, - { - "type": "hexcasting:pattern", - "header": "Craft Cypher", - "anchor": "OpMakePackagedSpellCypher", - "input": "entity, list of patterns", - "output": "", - "text": "Costs about one $(item)Charged Amethyst/$.", - "stroke_order": false, - "patterns": { - "startdir": "EAST", - "signature": "waqqqqq" - } - }, - { - "type": "hexcasting:pattern", - "header": "Craft Trinket", - "anchor": "OpMakePackagedSpellTrinket", - "input": "entity, list of patterns", - "output": "", - "text": "Costs about five $(item)Charged Amethyst/$s.", - "stroke_order": false, - "hex_size": 8, - "patterns": { - "startdir": "EAST", - "signature": "wwaqqqqqeaqeaeqqqeaeq" - } - }, - { - "type": "hexcasting:pattern", - "header": "Craft Artifact", - "anchor": "OpMakePackagedSpellArtifact", - "input": "entity, list of patterns", - "output": "", - "text": "Costs about ten $(item)Charged Amethyst/$s.", - "stroke_order": false, - "hex_size": 5, - "patterns": { - "startdir": "EAST", - "signature": "wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq" - } - } - ] + "name": "Crafting Hexcasting Items", + "category": "hexcasting:patterns/spells", + "icon": "hexcasting:artifact{patterns:[]}", + "sortnum": 2, + "advancement": "hexcasting:root", + "read_by_default": true, + "pages": [ + { + "type": "patchouli:text", + "text": "These three spells each create an item that casts a _Hex.$(br)They all require me to hold the empty item in my off-hand, and require two things: the list of patterns to be cast, and an entity representing a dropped stack of $(item)Amethyst/$ to form the item's battery.$(br2)See $(l:items/hexcasting)this entry/$ for more information." + }, + { + "type": "hexcasting:pattern", + "header": "Craft Cypher", + "anchor": "OpMakePackagedSpellCypher", + "input": "entity, list of patterns", + "output": "", + "text": "Costs about one $(item)Charged Amethyst/$.", + "patterns": { + "startdir": "EAST", + "signature": "waqqqqq" + } + }, + { + "type": "hexcasting:pattern", + "header": "Craft Trinket", + "anchor": "OpMakePackagedSpellTrinket", + "input": "entity, list of patterns", + "output": "", + "text": "Costs about five $(item)Charged Amethyst/$s.", + "hex_size": 8, + "patterns": { + "startdir": "EAST", + "signature": "wwaqqqqqeaqeaeqqqeaeq" + } + }, + { + "type": "hexcasting:pattern", + "header": "Craft Artifact", + "anchor": "OpMakePackagedSpellArtifact", + "input": "entity, list of patterns", + "output": "", + "text": "Costs about ten $(item)Charged Amethyst/$s.", + "hex_size": 5, + "patterns": { + "startdir": "EAST", + "signature": "wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq" + } + } + ] }