new spells get your new spells
This commit is contained in:
parent
524384f1d5
commit
fb2ebc568a
18 changed files with 506 additions and 207 deletions
|
@ -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'
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -21,6 +21,7 @@ object OpBlink : SpellOperator {
|
|||
val delta = args.getChecked<Double>(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
|
||||
|
|
|
@ -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<SpellDatum<*>>, ctx: CastingContext): Pair<RenderedSpell, Int> {
|
||||
val target = args.getChecked<Vec3>(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?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<SpellDatum<*>>, ctx: CastingContext): Pair<RenderedSpell, Int> {
|
||||
val target = args.getChecked<Vec3>(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<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()))
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<SpellDatum<*>>, ctx: CastingContext): Pair<RenderedSpell, Int> {
|
||||
val target = args.getChecked<Vec3>(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?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ object OpLightning : SpellOperator {
|
|||
ctx.assertVecInRange(target)
|
||||
return Pair(
|
||||
Spell(target),
|
||||
1_500_000
|
||||
150_000
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<SpellDatum<*>>, ctx: CastingContext): Pair<RenderedSpell, Int> {
|
||||
val teleportee = args.getChecked<Entity>(0)
|
||||
val delta = args.getChecked<Vec3>(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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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."
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue