3 new spells and fix a bunch of bugs, closes #1
This commit is contained in:
parent
1a3faecae9
commit
11042f3008
46 changed files with 698 additions and 156 deletions
21
original_ideas_doc.txt
Normal file
21
original_ideas_doc.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
PieceTrickBlaze.java
|
||||||
|
PieceTrickBreakLoop.java
|
||||||
|
PieceTrickChangeSlot.java
|
||||||
|
PieceTrickDebug.java
|
||||||
|
PieceTrickDebugSpamless.java
|
||||||
|
PieceTrickDelay.java
|
||||||
|
PieceTrickDetonate.java
|
||||||
|
PieceTrickDie.java
|
||||||
|
PieceTrickEidosAnchor.java
|
||||||
|
PieceTrickEidosReversal.java
|
||||||
|
PieceTrickEvaluate.java
|
||||||
|
PieceTrickExplode.java
|
||||||
|
PieceTrickOvergrow.java
|
||||||
|
PieceTrickParticleTrail.java
|
||||||
|
PieceTrickPlaySound.java
|
||||||
|
PieceTrickRussianRoulette.java
|
||||||
|
PieceTrickSaveVector.java
|
||||||
|
PieceTrickSmite.java
|
||||||
|
PieceTrickSpinChamber.java
|
||||||
|
PieceTrickSwitchTargetSlot.java
|
||||||
|
PieceTrickTorrent.java
|
|
@ -1,2 +1,42 @@
|
||||||
package at.petrak.hex;public class HexConfig {
|
package at.petrak.hex;
|
||||||
|
|
||||||
|
import net.minecraft.world.item.Tier;
|
||||||
|
import net.minecraft.world.item.Tiers;
|
||||||
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
|
|
||||||
|
public class HexConfig {
|
||||||
|
public final ForgeConfigSpec.IntValue maxRecurseDepth;
|
||||||
|
public final ForgeConfigSpec.IntValue wandRechargeRate;
|
||||||
|
public final ForgeConfigSpec.DoubleValue healthToManaRate;
|
||||||
|
public final ForgeConfigSpec.IntValue opBreakHarvestLevel;
|
||||||
|
|
||||||
|
public HexConfig(ForgeConfigSpec.Builder builder) {
|
||||||
|
maxRecurseDepth = builder.comment("How many times an Eval can recursively cast itself")
|
||||||
|
.defineInRange("maxRecurseDepth", 15, 0, Integer.MAX_VALUE);
|
||||||
|
wandRechargeRate = builder.comment("How many mana points a wand recharges per tick")
|
||||||
|
.defineInRange("wandRechargeRate", 2, 0, Integer.MAX_VALUE);
|
||||||
|
healthToManaRate = builder.comment("How many points of mana a half-heart is worth when casting from HP")
|
||||||
|
.defineInRange("healthToManaRate", 10.0, 0.0, 1_000_000.0);
|
||||||
|
|
||||||
|
builder.push("spells");
|
||||||
|
opBreakHarvestLevel = builder.comment(
|
||||||
|
"The harvest level of the Break Block spell.",
|
||||||
|
"0 = wood, 1 = stone, 2 = iron, 3 = diamond, 4 = netherite."
|
||||||
|
).defineInRange("opBreakHarvestLevel", 3, 0, 4);
|
||||||
|
builder.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i'm not kidding look upon net.minecraftforge.common.TierSortingRegistry and weep
|
||||||
|
*/
|
||||||
|
public Tier getOpBreakHarvestLevelBecauseForgeThoughtItWasAGoodIdeaToImplementHarvestTiersUsingAnHonestToGodTopoSort() {
|
||||||
|
return switch (this.opBreakHarvestLevel.get()) {
|
||||||
|
case 0 -> Tiers.WOOD;
|
||||||
|
case 1 -> Tiers.STONE;
|
||||||
|
case 2 -> Tiers.IRON;
|
||||||
|
case 3 -> Tiers.DIAMOND;
|
||||||
|
case 4 -> Tiers.NETHERITE;
|
||||||
|
default -> throw new RuntimeException("unreachable");
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@ import at.petrak.hex.common.casting.SpellDatum;
|
||||||
import at.petrak.hex.common.casting.SpellWidget;
|
import at.petrak.hex.common.casting.SpellWidget;
|
||||||
import at.petrak.hex.common.casting.operators.*;
|
import at.petrak.hex.common.casting.operators.*;
|
||||||
import at.petrak.hex.common.casting.operators.math.*;
|
import at.petrak.hex.common.casting.operators.math.*;
|
||||||
import at.petrak.hex.common.casting.operators.spells.OpAddMotion;
|
import at.petrak.hex.common.casting.operators.spells.*;
|
||||||
import at.petrak.hex.common.casting.operators.spells.OpExplode;
|
|
||||||
import at.petrak.hex.common.casting.operators.spells.OpPrint;
|
|
||||||
import at.petrak.hex.common.items.HexItems;
|
import at.petrak.hex.common.items.HexItems;
|
||||||
import at.petrak.hex.common.network.HexMessages;
|
import at.petrak.hex.common.network.HexMessages;
|
||||||
|
import at.petrak.hex.server.TickScheduler;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
@ -24,6 +24,14 @@ import org.apache.logging.log4j.Logger;
|
||||||
public class HexMod {
|
public class HexMod {
|
||||||
// hmm today I will use a popular logging framework :clueless:
|
// hmm today I will use a popular logging framework :clueless:
|
||||||
public static final Logger LOGGER = LogManager.getLogger();
|
public static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
public static final HexConfig CONFIG;
|
||||||
|
public static final ForgeConfigSpec CONFIG_SPEC;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final var specPair = new ForgeConfigSpec.Builder().configure(HexConfig::new);
|
||||||
|
CONFIG = specPair.getLeft();
|
||||||
|
CONFIG_SPEC = specPair.getRight();
|
||||||
|
}
|
||||||
|
|
||||||
public static final String MOD_ID = "hex";
|
public static final String MOD_ID = "hex";
|
||||||
|
|
||||||
|
@ -32,8 +40,10 @@ public class HexMod {
|
||||||
var evbus = FMLJavaModLoadingContext.get().getModEventBus();
|
var evbus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
evbus.register(HexMod.class);
|
evbus.register(HexMod.class);
|
||||||
|
|
||||||
HexItems.ITEMS.register(evbus);
|
HexItems.ITEMS.register(evbus);
|
||||||
HexMessages.register();
|
HexMessages.register();
|
||||||
|
MinecraftForge.EVENT_BUS.register(TickScheduler.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// I guess this means the client will have a big empty map for patterns
|
// I guess this means the client will have a big empty map for patterns
|
||||||
|
@ -44,32 +54,22 @@ public class HexMod {
|
||||||
for (Pair<String, SpellOperator> p : new Pair[]{
|
for (Pair<String, SpellOperator> p : new Pair[]{
|
||||||
// == Getters ==
|
// == Getters ==
|
||||||
|
|
||||||
// diamond shape to get the caster
|
|
||||||
new Pair<>("qaq", OpGetCaster.INSTANCE),
|
new Pair<>("qaq", OpGetCaster.INSTANCE),
|
||||||
new Pair<>("ede", OpGetCaster.INSTANCE),
|
new Pair<>("ede", OpGetCaster.INSTANCE),
|
||||||
// small triangle to get the entity pos
|
|
||||||
new Pair<>("aa", OpEntityPos.INSTANCE),
|
new Pair<>("aa", OpEntityPos.INSTANCE),
|
||||||
new Pair<>("dd", OpEntityPos.INSTANCE),
|
new Pair<>("dd", OpEntityPos.INSTANCE),
|
||||||
// Arrow to get the look vector
|
|
||||||
new Pair<>("wa", OpEntityLook.INSTANCE),
|
new Pair<>("wa", OpEntityLook.INSTANCE),
|
||||||
new Pair<>("wd", OpEntityLook.INSTANCE),
|
new Pair<>("wd", OpEntityLook.INSTANCE),
|
||||||
|
|
||||||
// CCW battleaxe for block raycast
|
|
||||||
new Pair<>("wqaawdd", OpBlockRaycast.INSTANCE),
|
new Pair<>("wqaawdd", OpBlockRaycast.INSTANCE),
|
||||||
// and CW for axis raycast
|
|
||||||
new Pair<>("weddwaa", OpBlockAxisRaycast.INSTANCE),
|
new Pair<>("weddwaa", OpBlockAxisRaycast.INSTANCE),
|
||||||
// CCW diamond mace thing for entity raycast
|
|
||||||
new Pair<>("weaqa", OpEntityRaycast.INSTANCE),
|
new Pair<>("weaqa", OpEntityRaycast.INSTANCE),
|
||||||
|
|
||||||
// == Modify Stack ==
|
// == Modify Stack ==
|
||||||
|
|
||||||
// CCW hook for undo
|
|
||||||
new Pair<>("a", OpUndo.INSTANCE),
|
new Pair<>("a", OpUndo.INSTANCE),
|
||||||
// and CW for null
|
|
||||||
new Pair<>("d", SpellWidget.NULL),
|
new Pair<>("d", SpellWidget.NULL),
|
||||||
// Two triangles holding hands to duplicate
|
|
||||||
new Pair<>("aadaa", OpDuplicate.INSTANCE),
|
new Pair<>("aadaa", OpDuplicate.INSTANCE),
|
||||||
// Two opposing triangles to swap
|
|
||||||
new Pair<>("aawdd", OpSwap.INSTANCE),
|
new Pair<>("aawdd", OpSwap.INSTANCE),
|
||||||
|
|
||||||
// == Math ==
|
// == Math ==
|
||||||
|
@ -82,12 +82,13 @@ public class HexMod {
|
||||||
|
|
||||||
// == Spells ==
|
// == Spells ==
|
||||||
|
|
||||||
// hook for debug
|
|
||||||
new Pair<>("de", OpPrint.INSTANCE),
|
new Pair<>("de", OpPrint.INSTANCE),
|
||||||
new Pair<>("aq", OpPrint.INSTANCE),
|
new Pair<>("aq", OpPrint.INSTANCE),
|
||||||
// nuclear sign for explosion
|
|
||||||
new Pair<>("aawaawaa", OpExplode.INSTANCE),
|
new Pair<>("aawaawaa", OpExplode.INSTANCE),
|
||||||
new Pair<>("weeewdq", OpAddMotion.INSTANCE),
|
new Pair<>("weeewdq", OpAddMotion.INSTANCE),
|
||||||
|
new Pair<>("qaqqqqq", OpPlaceBlock.INSTANCE),
|
||||||
|
new Pair<>("eeeeede", OpBreakBlock.INSTANCE),
|
||||||
|
new Pair<>("waadwawdaaweewq", OpLightning.INSTANCE),
|
||||||
|
|
||||||
// == Meta stuff ==
|
// == Meta stuff ==
|
||||||
new Pair<>("qqq", SpellWidget.OPEN_PAREN),
|
new Pair<>("qqq", SpellWidget.OPEN_PAREN),
|
||||||
|
@ -96,8 +97,8 @@ public class HexMod {
|
||||||
// http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf
|
// http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf
|
||||||
// eval being a space filling curve feels apt doesn't it
|
// eval being a space filling curve feels apt doesn't it
|
||||||
new Pair<>("deaqq", OpEval.INSTANCE),
|
new Pair<>("deaqq", OpEval.INSTANCE),
|
||||||
new Pair<>("aqqqqq", OpReadFromSpellbook.INSTANCE),
|
new Pair<>("aqqqqq", OpRead.INSTANCE),
|
||||||
new Pair<>("deeeee", OpWriteToSpellbook.INSTANCE),
|
new Pair<>("deeeee", OpWrite.INSTANCE),
|
||||||
}) {
|
}) {
|
||||||
PatternRegistry.addRegularPattern(p.getFirst(), p.getSecond());
|
PatternRegistry.addRegularPattern(p.getFirst(), p.getSecond());
|
||||||
count++;
|
count++;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import at.petrak.hex.common.casting.SpellDatum
|
||||||
/**
|
/**
|
||||||
* A SimpleOperator that always costs the same amount of mana.
|
* A SimpleOperator that always costs the same amount of mana.
|
||||||
*/
|
*/
|
||||||
interface SimpleFreeOperator : SpellOperator {
|
interface ConstManaOperator : SpellOperator {
|
||||||
val argc: Int
|
val argc: Int
|
||||||
val manaCost: Int
|
val manaCost: Int
|
||||||
get() = 0
|
get() = 0
|
||||||
|
|
|
@ -10,16 +10,17 @@ import at.petrak.hex.common.casting.SpellDatum
|
||||||
*/
|
*/
|
||||||
interface SimpleOperator : SpellOperator {
|
interface SimpleOperator : SpellOperator {
|
||||||
val argc: Int
|
val argc: Int
|
||||||
fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>>
|
fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Pair<List<SpellDatum<*>>, Int>
|
||||||
|
|
||||||
override fun modifyStack(stack: MutableList<SpellDatum<*>>, ctx: CastingContext) {
|
override fun modifyStack(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): Int {
|
||||||
if (this.argc > stack.size)
|
if (this.argc > stack.size)
|
||||||
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, this.argc, stack.size)
|
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, this.argc, stack.size)
|
||||||
val args = stack.takeLast(this.argc)
|
val args = stack.takeLast(this.argc)
|
||||||
// there's gotta be a better way to do this
|
// there's gotta be a better way to do this
|
||||||
for (_idx in 0 until this.argc)
|
for (_idx in 0 until this.argc)
|
||||||
stack.removeLast()
|
stack.removeLast()
|
||||||
val newData = this.execute(args, ctx)
|
val (newData, mana) = this.execute(args, ctx)
|
||||||
stack.addAll(newData)
|
stack.addAll(newData)
|
||||||
|
return mana
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
package at.petrak.hex.api
|
package at.petrak.hex.api
|
||||||
|
|
||||||
import at.petrak.hex.common.casting.CastException
|
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
@ -14,10 +13,10 @@ import net.minecraft.world.phys.Vec3
|
||||||
* Implementors MUST NOT mutate the context.
|
* Implementors MUST NOT mutate the context.
|
||||||
*/
|
*/
|
||||||
interface SpellOperator {
|
interface SpellOperator {
|
||||||
val manaCost: Int
|
/**
|
||||||
get() = 0
|
* Operate on the stack and return the mana cost.
|
||||||
|
*/
|
||||||
fun modifyStack(stack: MutableList<SpellDatum<*>>, ctx: CastingContext)
|
fun modifyStack(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): Int
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// I see why vzakii did this: you can't raycast out to infinity!
|
// I see why vzakii did this: you can't raycast out to infinity!
|
||||||
|
@ -42,15 +41,6 @@ interface SpellOperator {
|
||||||
this.getChecked<T>(idx)
|
this.getChecked<T>(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure the vector is in range of the player.
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun assertVecInRange(vec: Vec3, ctx: CastingContext) {
|
|
||||||
if (vec.distanceToSqr(ctx.caster.position()) > MAX_DISTANCE * MAX_DISTANCE)
|
|
||||||
throw CastException(CastException.Reason.TOO_FAR, vec)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun spellListOf(vararg vs: Any): List<SpellDatum<*>> {
|
fun spellListOf(vararg vs: Any): List<SpellDatum<*>> {
|
||||||
val out = ArrayList<SpellDatum<*>>(vs.size)
|
val out = ArrayList<SpellDatum<*>>(vs.size)
|
||||||
|
@ -61,11 +51,12 @@ interface SpellOperator {
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun makeConstantOp(x: SpellDatum<*>): SpellOperator = object : SimpleOperator {
|
fun makeConstantOp(x: SpellDatum<*>): SpellOperator = object : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 0
|
get() = 0
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> = listOf(x)
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> =
|
||||||
|
listOf(x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@ public class RegisterClientStuff {
|
||||||
evt.enqueueWork(() -> ItemProperties.register(HexItems.FOCUS.get(), ItemFocus.PREDICATE,
|
evt.enqueueWork(() -> ItemProperties.register(HexItems.FOCUS.get(), ItemFocus.PREDICATE,
|
||||||
(stack, level, holder, holderID) -> {
|
(stack, level, holder, holderID) -> {
|
||||||
if (stack.hasTag()) {
|
if (stack.hasTag()) {
|
||||||
var tagname = stack.getTag().getAllKeys().iterator().next();
|
var tagname = stack.getTag().getCompound(ItemFocus.TAG_DATA).getAllKeys().iterator().next();
|
||||||
return switch (tagname) {
|
return switch (tagname) {
|
||||||
case SpellDatum.TAG_ENTITY -> 1f;
|
case SpellDatum.TAG_ENTITY -> 1f;
|
||||||
case SpellDatum.TAG_DOUBLE -> 2f;
|
case SpellDatum.TAG_DOUBLE -> 2f;
|
||||||
|
|
|
@ -57,6 +57,20 @@ class CastException(val reason: Reason, vararg val data: Any) : Exception() {
|
||||||
* `no args`
|
* `no args`
|
||||||
*/
|
*/
|
||||||
REQUIRES_SPELLBOOK,
|
REQUIRES_SPELLBOOK,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operator needed a data holder in the offhand.
|
||||||
|
*
|
||||||
|
* `no args`
|
||||||
|
*/
|
||||||
|
REQUIRES_DATA_HOLDER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We went too deep!
|
||||||
|
*
|
||||||
|
* `maxDepth: Int, gotDepth: Int`
|
||||||
|
*/
|
||||||
|
TOO_MANY_RECURSIVE_EVALS,
|
||||||
}
|
}
|
||||||
|
|
||||||
override val message: String
|
override val message: String
|
||||||
|
@ -68,5 +82,7 @@ class CastException(val reason: Reason, vararg val data: Any) : Exception() {
|
||||||
Reason.TOO_MANY_CLOSE_PARENS -> "too many close parentheses"
|
Reason.TOO_MANY_CLOSE_PARENS -> "too many close parentheses"
|
||||||
Reason.TOO_FAR -> "tried to interact with something too far away at ${this.data[0] as Vec3}"
|
Reason.TOO_FAR -> "tried to interact with something too far away at ${this.data[0] as Vec3}"
|
||||||
Reason.REQUIRES_SPELLBOOK -> "required a spellbook in the other hand"
|
Reason.REQUIRES_SPELLBOOK -> "required a spellbook in the other hand"
|
||||||
|
Reason.REQUIRES_DATA_HOLDER -> "required a data holder in the other hand"
|
||||||
|
Reason.TOO_MANY_RECURSIVE_EVALS -> "can only recursively call OpEval ${this.data[0] as Int} times but called it ${this.data[1] as Int} times"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,29 +1,166 @@
|
||||||
package at.petrak.hex.common.casting
|
package at.petrak.hex.common.casting
|
||||||
|
|
||||||
|
import at.petrak.hex.HexMod
|
||||||
import at.petrak.hex.HexUtils
|
import at.petrak.hex.HexUtils
|
||||||
|
import at.petrak.hex.api.SpellOperator
|
||||||
|
import at.petrak.hex.common.items.ItemDataHolder
|
||||||
import at.petrak.hex.common.items.ItemSpellbook
|
import at.petrak.hex.common.items.ItemSpellbook
|
||||||
|
import at.petrak.hex.common.items.ItemWand
|
||||||
|
import at.petrak.hex.common.lib.LibDamageSources
|
||||||
import net.minecraft.server.level.ServerLevel
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import net.minecraft.world.InteractionHand
|
import net.minecraft.world.InteractionHand
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.phys.Vec3
|
||||||
|
import java.util.function.Predicate
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Info about the moment the spell started being cast.
|
* Info about the moment the spell started being cast.
|
||||||
*/
|
*/
|
||||||
@JvmRecord
|
|
||||||
data class CastingContext(
|
data class CastingContext(
|
||||||
val caster: ServerPlayer,
|
val caster: ServerPlayer,
|
||||||
val wandHand: InteractionHand,
|
val wandHand: InteractionHand,
|
||||||
) {
|
) {
|
||||||
|
private var depth: Int = 0
|
||||||
val world: ServerLevel get() = caster.getLevel()
|
val world: ServerLevel get() = caster.getLevel()
|
||||||
|
val otherHand: InteractionHand get() = HexUtils.OtherHand(this.wandHand)
|
||||||
|
|
||||||
fun getSpellbook(): ItemStack {
|
fun getSpellbook(): ItemStack {
|
||||||
val handItem =
|
val handItem =
|
||||||
caster.getItemInHand(HexUtils.OtherHand(wandHand))
|
caster.getItemInHand(this.otherHand)
|
||||||
return if (handItem.item is ItemSpellbook) {
|
return if (handItem.item is ItemSpellbook) {
|
||||||
handItem
|
handItem
|
||||||
} else {
|
} else {
|
||||||
throw CastException(CastException.Reason.REQUIRES_SPELLBOOK)
|
throw CastException(CastException.Reason.REQUIRES_SPELLBOOK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDataHolder(): ItemStack {
|
||||||
|
val handItem =
|
||||||
|
caster.getItemInHand(this.otherHand)
|
||||||
|
return if (handItem.item is ItemDataHolder) {
|
||||||
|
handItem
|
||||||
|
} else {
|
||||||
|
throw CastException(CastException.Reason.REQUIRES_DATA_HOLDER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws if we get too deep
|
||||||
|
*/
|
||||||
|
fun withIncDepth(): CastingContext {
|
||||||
|
val next = this.copy()
|
||||||
|
next.depth++
|
||||||
|
|
||||||
|
val maxAllowedDepth = HexMod.CONFIG.maxRecurseDepth.get()
|
||||||
|
if (next.depth > maxAllowedDepth) {
|
||||||
|
throw CastException(CastException.Reason.TOO_MANY_RECURSIVE_EVALS, maxAllowedDepth, next.depth)
|
||||||
|
} else {
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Might cast from hitpoints.
|
||||||
|
* Returns the mana cost still remaining after we deplete everything. It will be <= 0 if we could pay for it. */
|
||||||
|
fun withdrawMana(manaCost: Int, allowOvercast: Boolean): Int {
|
||||||
|
var costLeft = manaCost
|
||||||
|
|
||||||
|
val held = caster.getItemInHand(this.wandHand)
|
||||||
|
if (held.item is ItemWand) {
|
||||||
|
val tag = held.orCreateTag
|
||||||
|
val manaHere = tag.getInt(ItemWand.TAG_MANA)
|
||||||
|
val manaLeft = manaHere - costLeft
|
||||||
|
tag.putInt(ItemWand.TAG_MANA, max(0, manaLeft))
|
||||||
|
costLeft = max(0, costLeft - manaHere)
|
||||||
|
}
|
||||||
|
if (allowOvercast && costLeft > 0) {
|
||||||
|
// Cast from HP!
|
||||||
|
val healthToMana = HexMod.CONFIG.healthToManaRate.get()
|
||||||
|
val healthtoRemove = healthToMana * costLeft.toDouble()
|
||||||
|
val manaAbleToCastFromHP =
|
||||||
|
if (caster.isInvulnerable) Double.POSITIVE_INFINITY else caster.health / healthToMana
|
||||||
|
caster.hurt(LibDamageSources.OVERCAST, healthtoRemove.toFloat())
|
||||||
|
costLeft = (costLeft.toDouble() - manaAbleToCastFromHP).toInt()
|
||||||
|
}
|
||||||
|
return costLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertVecInRange(vec: Vec3) {
|
||||||
|
if (vec.distanceToSqr(this.caster.position()) > SpellOperator.MAX_DISTANCE * SpellOperator.MAX_DISTANCE)
|
||||||
|
throw CastException(CastException.Reason.TOO_FAR, vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the slot from which to take blocks and items.
|
||||||
|
*/
|
||||||
|
// https://wiki.vg/Inventory is WRONG
|
||||||
|
// slots 0-8 are the hotbar
|
||||||
|
// for what purpose i cannot imagine
|
||||||
|
// http://redditpublic.com/images/b/b2/Items_slot_number.png looks right
|
||||||
|
// and offhand is 150 Inventory.java:464
|
||||||
|
fun getOperativeSlot(stackOK: Predicate<ItemStack>): Int? {
|
||||||
|
val otherHandStack = this.caster.getItemInHand(this.otherHand)
|
||||||
|
if (stackOK.test(otherHandStack)) {
|
||||||
|
return when (this.otherHand) {
|
||||||
|
InteractionHand.MAIN_HAND -> this.caster.inventory.selected
|
||||||
|
InteractionHand.OFF_HAND -> 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val anchorSlot = when (this.wandHand) {
|
||||||
|
// slot to the right of the wand
|
||||||
|
InteractionHand.MAIN_HAND -> (this.caster.inventory.selected + 1) % 9
|
||||||
|
// first hotbar slot
|
||||||
|
InteractionHand.OFF_HAND -> 0
|
||||||
|
}
|
||||||
|
for (delta in 0 until 9) {
|
||||||
|
val slot = (anchorSlot + delta) % 9
|
||||||
|
val stack = this.caster.inventory.getItem(slot)
|
||||||
|
if (stackOK.test(stack)) {
|
||||||
|
return slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given gound 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
|
||||||
|
fun withdrawItem(item: Item, count: Int, actuallyRemove: Boolean): Boolean {
|
||||||
|
if (this.caster.isCreative) return true
|
||||||
|
|
||||||
|
val inv = this.caster.inventory
|
||||||
|
// TODO: withdraw from ender chest given a specific ender charm?
|
||||||
|
val stacksToExamine = inv.items.asReversed()
|
||||||
|
|
||||||
|
fun matches(stack: ItemStack): Boolean =
|
||||||
|
!stack.isEmpty && stack.`is`(item)
|
||||||
|
|
||||||
|
val presentCount = stacksToExamine.fold(0) { acc, stack ->
|
||||||
|
acc + if (matches(stack)) stack.count else 0
|
||||||
|
}
|
||||||
|
if (presentCount < count) return false
|
||||||
|
|
||||||
|
// now that we know we have enough items, if we don't need to remove anything we're through.
|
||||||
|
if (!actuallyRemove) return true
|
||||||
|
|
||||||
|
var remaining = count
|
||||||
|
for (stack in stacksToExamine) {
|
||||||
|
if (matches(stack)) {
|
||||||
|
val toWithdraw = min(stack.count, remaining)
|
||||||
|
stack.shrink(toWithdraw)
|
||||||
|
|
||||||
|
remaining -= toWithdraw
|
||||||
|
if (remaining == 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw RuntimeException("unreachable")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import net.minecraft.nbt.ListTag
|
||||||
import net.minecraft.nbt.Tag
|
import net.minecraft.nbt.Tag
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import net.minecraft.world.InteractionHand
|
import net.minecraft.world.InteractionHand
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of a player casting a spell on the server.
|
* Keeps track of a player casting a spell on the server.
|
||||||
|
@ -63,9 +64,9 @@ class CastingHarness private constructor(
|
||||||
this.escapeNext = false
|
this.escapeNext = false
|
||||||
HexMod.LOGGER.info("Escaping onto stack")
|
HexMod.LOGGER.info("Escaping onto stack")
|
||||||
this.stack.add(SpellDatum.make(newPat))
|
this.stack.add(SpellDatum.make(newPat))
|
||||||
} else {
|
} else if (operator == SpellWidget.ESCAPE) {
|
||||||
// Plain ol operator
|
this.escapeNext = true
|
||||||
if (exn != null) {
|
} else if (exn != null) {
|
||||||
// there was a problem finding the pattern and it was NOT due to numbers
|
// there was a problem finding the pattern and it was NOT due to numbers
|
||||||
throw exn
|
throw exn
|
||||||
} else if (operator == SpellWidget.OPEN_PAREN) {
|
} else if (operator == SpellWidget.OPEN_PAREN) {
|
||||||
|
@ -74,8 +75,12 @@ class CastingHarness private constructor(
|
||||||
throw CastException(CastException.Reason.TOO_MANY_CLOSE_PARENS)
|
throw CastException(CastException.Reason.TOO_MANY_CLOSE_PARENS)
|
||||||
} else {
|
} else {
|
||||||
// we know the operator is ok here
|
// we know the operator is ok here
|
||||||
operator!!.modifyStack(this.stack, this.ctx)
|
val manaCost = operator!!.modifyStack(this.stack, this.ctx)
|
||||||
}
|
|
||||||
|
// prevent poor impls from gaining you mana
|
||||||
|
ctx.withdrawMana(max(0, manaCost), true)
|
||||||
|
if (ctx.caster.isDeadOrDying)
|
||||||
|
return CastResult.Died
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.parenCount > 0) {
|
if (this.parenCount > 0) {
|
||||||
|
@ -172,5 +177,8 @@ class CastingHarness private constructor(
|
||||||
|
|
||||||
/** uh-oh */
|
/** uh-oh */
|
||||||
data class Error(val exn: CastException) : CastResult()
|
data class Error(val exn: CastException) : CastResult()
|
||||||
|
|
||||||
|
/** YOU DIED due to casting too hard from hit points. */
|
||||||
|
object Died : CastResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package at.petrak.hex.common.casting
|
package at.petrak.hex.common.casting
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +8,7 @@ import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
*
|
*
|
||||||
* They act as operators that push themselves.
|
* They act as operators that push themselves.
|
||||||
*/
|
*/
|
||||||
enum class SpellWidget : SimpleOperator {
|
enum class SpellWidget : ConstManaOperator {
|
||||||
NULL,
|
NULL,
|
||||||
OPEN_PAREN, CLOSE_PAREN, ESCAPE;
|
OPEN_PAREN, CLOSE_PAREN, ESCAPE;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator
|
import at.petrak.hex.api.SpellOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
@ -10,8 +10,9 @@ import net.minecraft.world.level.ClipContext
|
||||||
import net.minecraft.world.phys.HitResult
|
import net.minecraft.world.phys.HitResult
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
|
||||||
object OpBlockAxisRaycast : SimpleOperator {
|
object OpBlockAxisRaycast : ConstManaOperator {
|
||||||
override val argc = 2
|
override val argc = 2
|
||||||
|
override val manaCost = 10
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
val origin: Vec3 = args.getChecked(0)
|
val origin: Vec3 = args.getChecked(0)
|
||||||
val look: Vec3 = args.getChecked(1)
|
val look: Vec3 = args.getChecked(1)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator
|
import at.petrak.hex.api.SpellOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
@ -10,8 +10,9 @@ import net.minecraft.world.level.ClipContext
|
||||||
import net.minecraft.world.phys.HitResult
|
import net.minecraft.world.phys.HitResult
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
|
||||||
object OpBlockRaycast : SimpleOperator {
|
object OpBlockRaycast : ConstManaOperator {
|
||||||
override val argc = 2
|
override val argc = 2
|
||||||
|
override val manaCost = 10
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
val origin: Vec3 = args.getChecked(0)
|
val origin: Vec3 = args.getChecked(0)
|
||||||
val look: Vec3 = args.getChecked(1)
|
val look: Vec3 = args.getChecked(1)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
|
||||||
object OpDuplicate : SimpleOperator {
|
object OpDuplicate : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 1
|
get() = 1
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.world.entity.Entity
|
import net.minecraft.world.entity.Entity
|
||||||
|
|
||||||
object OpEntityLook : SimpleOperator {
|
object OpEntityLook : ConstManaOperator {
|
||||||
override val argc = 1
|
override val argc = 1
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
@ -8,7 +8,7 @@ import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.world.entity.Entity
|
import net.minecraft.world.entity.Entity
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
|
|
||||||
object OpEntityPos : SimpleOperator {
|
object OpEntityPos : ConstManaOperator {
|
||||||
override val argc = 1
|
override val argc = 1
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator
|
import at.petrak.hex.api.SpellOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
@ -10,8 +10,9 @@ import net.minecraft.world.entity.projectile.ProjectileUtil
|
||||||
import net.minecraft.world.phys.AABB
|
import net.minecraft.world.phys.AABB
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
|
||||||
object OpEntityRaycast : SimpleOperator {
|
object OpEntityRaycast : ConstManaOperator {
|
||||||
override val argc = 2
|
override val argc = 2
|
||||||
|
override val manaCost = 10
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
val origin: Vec3 = args.getChecked(0)
|
val origin: Vec3 = args.getChecked(0)
|
||||||
val look: Vec3 = args.getChecked(1)
|
val look: Vec3 = args.getChecked(1)
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.SpellOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.CastingHarness
|
import at.petrak.hex.common.casting.CastingHarness
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
|
||||||
object OpEval : SimpleOperator {
|
object OpEval : SpellOperator {
|
||||||
override val argc: Int
|
override fun modifyStack(stack: MutableList<SpellDatum<*>>, ctx: CastingContext): Int {
|
||||||
get() = 1
|
val instrs: List<SpellDatum<*>> = stack.getChecked(stack.lastIndex)
|
||||||
|
stack.removeLastOrNull()
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
val ctxDeeper = ctx.withIncDepth()
|
||||||
val instrs: List<SpellDatum<*>> = args.getChecked(0)
|
val harness = CastingHarness.Default(ctxDeeper)
|
||||||
|
harness.stack.addAll(stack)
|
||||||
val harness = CastingHarness.Default(ctx)
|
stack.clear()
|
||||||
for (pat in instrs) {
|
for (pat in instrs) {
|
||||||
val res = harness.update(pat.tryGet())
|
val res = harness.update(pat.tryGet())
|
||||||
if (res is CastingHarness.CastResult.Error) {
|
if (res is CastingHarness.CastResult.Error) {
|
||||||
|
@ -22,6 +22,8 @@ object OpEval : SimpleOperator {
|
||||||
// in ANY OTHER CASE JUST KEEP GOING
|
// in ANY OTHER CASE JUST KEEP GOING
|
||||||
// including if there's RenderedSpells on the stack or the stack becomes clear
|
// including if there's RenderedSpells on the stack or the stack becomes clear
|
||||||
}
|
}
|
||||||
return harness.stack
|
stack.addAll(harness.stack)
|
||||||
|
|
||||||
|
return 50
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator
|
import at.petrak.hex.api.SpellOperator
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.world.entity.Entity
|
import net.minecraft.world.entity.Entity
|
||||||
|
|
||||||
object OpGetCaster : SimpleOperator {
|
object OpGetCaster : ConstManaOperator {
|
||||||
override val argc = 0
|
override val argc = 0
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> =
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> =
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import at.petrak.hex.common.casting.SpellWidget
|
import at.petrak.hex.common.casting.SpellWidget
|
||||||
import at.petrak.hex.common.items.ItemSpellbook
|
import at.petrak.hex.common.items.ItemDataHolder
|
||||||
|
|
||||||
object OpReadFromSpellbook : SimpleOperator {
|
object OpRead : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc = 0
|
||||||
get() = 0
|
override val manaCost = 10
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
val spellbook = ctx.getSpellbook()
|
val dataer = ctx.getDataHolder()
|
||||||
val datum = ItemSpellbook.ReadDatum(spellbook.orCreateTag, ctx)
|
val datum = (dataer.item as ItemDataHolder).readDatum(dataer.orCreateTag, ctx)
|
||||||
return listOf(datum ?: SpellDatum.make(SpellWidget.NULL))
|
return listOf(datum ?: SpellDatum.make(SpellWidget.NULL))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
|
||||||
object OpSwap : SimpleOperator {
|
object OpSwap : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 2
|
get() = 2
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
|
||||||
object OpUndo : SimpleOperator {
|
object OpUndo : ConstManaOperator {
|
||||||
override val argc = 1
|
override val argc = 1
|
||||||
|
|
||||||
// Do literally nothing!
|
// Do literally nothing!
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
package at.petrak.hex.common.casting.operators
|
package at.petrak.hex.common.casting.operators
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import at.petrak.hex.common.items.ItemSpellbook
|
import at.petrak.hex.common.items.ItemDataHolder
|
||||||
|
|
||||||
object OpWriteToSpellbook : SimpleOperator {
|
object OpWrite : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc = 1
|
||||||
get() = 1
|
override val manaCost = 10
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
val spellbook = ctx.getSpellbook()
|
val dataer = ctx.getDataHolder()
|
||||||
ItemSpellbook.WriteDatum(spellbook.orCreateTag, args[0])
|
(dataer.item as ItemDataHolder).writeDatum(dataer.orCreateTag, args[0])
|
||||||
return spellListOf()
|
return spellListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package at.petrak.hex.common.casting.operators.math
|
package at.petrak.hex.common.casting.operators.math
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
object OpAbsLen : SimpleOperator {
|
object OpAbsLen : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 1
|
get() = 1
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package at.petrak.hex.common.casting.operators.math
|
package at.petrak.hex.common.casting.operators.math
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
|
||||||
object OpAdd : SimpleOperator {
|
object OpAdd : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 2
|
get() = 2
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package at.petrak.hex.common.casting.operators.math
|
package at.petrak.hex.common.casting.operators.math
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
|
||||||
object OpDivCross : SimpleOperator {
|
object OpDivCross : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 2
|
get() = 2
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package at.petrak.hex.common.casting.operators.math
|
package at.petrak.hex.common.casting.operators.math
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
|
||||||
object OpMulDot : SimpleOperator {
|
object OpMulDot : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 2
|
get() = 2
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package at.petrak.hex.common.casting.operators.math
|
package at.petrak.hex.common.casting.operators.math
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
object OpPowProj : SimpleOperator {
|
object OpPowProj : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 2
|
get() = 2
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package at.petrak.hex.common.casting.operators.math
|
package at.petrak.hex.common.casting.operators.math
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
|
||||||
object OpSub : SimpleOperator {
|
object OpSub : ConstManaOperator {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 2
|
get() = 2
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,13 @@ object OpAddMotion : SimpleOperator, RenderedSpellImpl {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 2
|
get() = 2
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Pair<List<SpellDatum<*>>, Int> {
|
||||||
val target = args.getChecked<Entity>(0)
|
val target = args.getChecked<Entity>(0)
|
||||||
val motion = args.getChecked<Vec3>(1)
|
val motion = args.getChecked<Vec3>(1)
|
||||||
return spellListOf(RenderedSpell(OpAddMotion, spellListOf(target, motion)))
|
return Pair(
|
||||||
|
spellListOf(RenderedSpell(OpAddMotion, spellListOf(target, motion))),
|
||||||
|
motion.lengthSqr().toInt() * 100
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cast(args: List<SpellDatum<*>>, ctx: CastingContext) {
|
override fun cast(args: List<SpellDatum<*>>, ctx: CastingContext) {
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package at.petrak.hex.common.casting.operators.spells
|
||||||
|
|
||||||
|
import at.petrak.hex.HexMod
|
||||||
|
import at.petrak.hex.api.SimpleOperator
|
||||||
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
import at.petrak.hex.common.casting.RenderedSpell
|
||||||
|
import at.petrak.hex.common.casting.RenderedSpellImpl
|
||||||
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.world.phys.Vec3
|
||||||
|
import net.minecraftforge.common.TierSortingRegistry
|
||||||
|
|
||||||
|
object OpBreakBlock : SimpleOperator, RenderedSpellImpl {
|
||||||
|
override val argc: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Pair<List<SpellDatum<*>>, Int> {
|
||||||
|
val pos = args.getChecked<Vec3>(0)
|
||||||
|
ctx.assertVecInRange(pos)
|
||||||
|
return Pair(
|
||||||
|
spellListOf(RenderedSpell(OpBreakBlock, spellListOf(pos))),
|
||||||
|
100
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cast(args: List<SpellDatum<*>>, ctx: CastingContext) {
|
||||||
|
val pos = BlockPos(args.getChecked<Vec3>(0))
|
||||||
|
|
||||||
|
val blockstate = ctx.world.getBlockState(pos)
|
||||||
|
val tier =
|
||||||
|
HexMod.CONFIG.opBreakHarvestLevelBecauseForgeThoughtItWasAGoodIdeaToImplementHarvestTiersUsingAnHonestToGodTopoSort
|
||||||
|
|
||||||
|
if (!blockstate.isAir && (!blockstate.requiresCorrectToolForDrops() || TierSortingRegistry.isCorrectTierForDrops(
|
||||||
|
tier,
|
||||||
|
blockstate
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
ctx.world.destroyBlock(pos, true, ctx.caster)
|
||||||
|
} // TODO: else some kind of failureific particle effect?
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,41 @@
|
||||||
package at.petrak.hex.common.casting.operators.spells
|
package at.petrak.hex.common.casting.operators.spells
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.SimpleOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.assertVecInRange
|
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
import at.petrak.hex.common.casting.RenderedSpell
|
import at.petrak.hex.common.casting.RenderedSpell
|
||||||
import at.petrak.hex.common.casting.RenderedSpellImpl
|
import at.petrak.hex.common.casting.RenderedSpellImpl
|
||||||
import at.petrak.hex.common.casting.SpellDatum
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
import net.minecraft.util.Mth
|
||||||
import net.minecraft.world.level.Explosion
|
import net.minecraft.world.level.Explosion
|
||||||
import net.minecraft.world.phys.Vec3
|
import net.minecraft.world.phys.Vec3
|
||||||
|
|
||||||
object OpExplode : SimpleOperator, RenderedSpellImpl {
|
object OpExplode : SimpleOperator, RenderedSpellImpl {
|
||||||
override val argc: Int
|
override val argc: Int
|
||||||
get() = 1
|
get() = 2
|
||||||
|
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Pair<List<SpellDatum<*>>, Int> {
|
||||||
val pos = args.getChecked<Vec3>(0)
|
val pos = args.getChecked<Vec3>(0)
|
||||||
assertVecInRange(pos, ctx)
|
val strength = args.getChecked<Double>(1)
|
||||||
return spellListOf(RenderedSpell(OpExplode, spellListOf(pos)))
|
ctx.assertVecInRange(pos)
|
||||||
|
return Pair(
|
||||||
|
spellListOf(RenderedSpell(OpExplode, spellListOf(pos, strength))),
|
||||||
|
(strength * 100.0).toInt(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cast(args: List<SpellDatum<*>>, ctx: CastingContext) {
|
override fun cast(args: List<SpellDatum<*>>, ctx: CastingContext) {
|
||||||
val pos = args.getChecked<Vec3>(0)
|
val pos = args.getChecked<Vec3>(0)
|
||||||
|
val strength = args.getChecked<Double>(1)
|
||||||
|
|
||||||
// 4.0 is the strength of TNT, i guess
|
ctx.world.explode(
|
||||||
ctx.world.explode(ctx.caster, pos.x, pos.y, pos.z, 4.0f, Explosion.BlockInteraction.BREAK)
|
ctx.caster,
|
||||||
|
pos.x,
|
||||||
|
pos.y,
|
||||||
|
pos.z,
|
||||||
|
Mth.clamp(strength.toFloat(), 0f, 10f),
|
||||||
|
Explosion.BlockInteraction.BREAK
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package at.petrak.hex.common.casting.operators.spells
|
||||||
|
|
||||||
|
import at.petrak.hex.api.SimpleOperator
|
||||||
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
import at.petrak.hex.common.casting.RenderedSpell
|
||||||
|
import at.petrak.hex.common.casting.RenderedSpellImpl
|
||||||
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
import net.minecraft.world.entity.EntityType
|
||||||
|
import net.minecraft.world.entity.LightningBolt
|
||||||
|
import net.minecraft.world.phys.Vec3
|
||||||
|
|
||||||
|
object OpLightning : SimpleOperator, RenderedSpellImpl {
|
||||||
|
override val argc: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Pair<List<SpellDatum<*>>, Int> {
|
||||||
|
val target = args.getChecked<Vec3>(0)
|
||||||
|
ctx.assertVecInRange(target)
|
||||||
|
return Pair(
|
||||||
|
spellListOf(RenderedSpell(OpLightning, spellListOf(target))),
|
||||||
|
1500
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cast(args: List<SpellDatum<*>>, ctx: CastingContext) {
|
||||||
|
val target = args.getChecked<Vec3>(0)
|
||||||
|
|
||||||
|
val lightning = LightningBolt(EntityType.LIGHTNING_BOLT, ctx.world)
|
||||||
|
lightning.setPosRaw(target.x, target.y, target.z)
|
||||||
|
ctx.world.addWithUUID(lightning) // why the hell is it called this it doesnt even involve a uuid
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package at.petrak.hex.common.casting.operators.spells
|
||||||
|
|
||||||
|
import at.petrak.hex.api.SimpleOperator
|
||||||
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
import at.petrak.hex.common.casting.RenderedSpell
|
||||||
|
import at.petrak.hex.common.casting.RenderedSpellImpl
|
||||||
|
import at.petrak.hex.common.casting.SpellDatum
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.world.InteractionResult
|
||||||
|
import net.minecraft.world.item.BlockItem
|
||||||
|
import net.minecraft.world.item.context.UseOnContext
|
||||||
|
import net.minecraft.world.phys.BlockHitResult
|
||||||
|
import net.minecraft.world.phys.Vec3
|
||||||
|
import net.minecraftforge.common.MinecraftForge
|
||||||
|
import net.minecraftforge.common.util.BlockSnapshot
|
||||||
|
import net.minecraftforge.event.world.BlockEvent
|
||||||
|
|
||||||
|
object OpPlaceBlock : SimpleOperator, RenderedSpellImpl {
|
||||||
|
override val argc: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): Pair<List<SpellDatum<*>>, Int> {
|
||||||
|
val pos = args.getChecked<Vec3>(0)
|
||||||
|
ctx.assertVecInRange(pos)
|
||||||
|
return Pair(
|
||||||
|
spellListOf(RenderedSpell(OpPlaceBlock, spellListOf(pos))),
|
||||||
|
30
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cast(args: List<SpellDatum<*>>, ctx: CastingContext) {
|
||||||
|
val vec = args.getChecked<Vec3>(0)
|
||||||
|
val pos = BlockPos(vec)
|
||||||
|
val bstate = ctx.world.getBlockState(pos)
|
||||||
|
if (bstate.isAir || bstate.material.isReplaceable) {
|
||||||
|
val placeeSlot = ctx.getOperativeSlot { it.item is BlockItem }
|
||||||
|
if (placeeSlot != null) {
|
||||||
|
val placeeStack = ctx.caster.inventory.getItem(placeeSlot)
|
||||||
|
val placee = placeeStack.item as BlockItem
|
||||||
|
if (ctx.withdrawItem(placee, 1, false)) {
|
||||||
|
// https://github.com/VazkiiMods/Psi/blob/master/src/main/java/vazkii/psi/common/spell/trick/block/PieceTrickPlaceBlock.java#L143
|
||||||
|
val evt = BlockEvent.EntityPlaceEvent(
|
||||||
|
BlockSnapshot.create(ctx.world.dimension(), ctx.world, pos),
|
||||||
|
ctx.world.getBlockState(pos.above()),
|
||||||
|
ctx.caster
|
||||||
|
)
|
||||||
|
MinecraftForge.EVENT_BUS.post(evt)
|
||||||
|
|
||||||
|
// we temporarily give the player the stack, place it using mc code, then give them the old stack back.
|
||||||
|
val oldStack = ctx.caster.getItemInHand(ctx.wandHand)
|
||||||
|
val spoofedStack = placeeStack.copy()
|
||||||
|
spoofedStack.count = 1
|
||||||
|
ctx.caster.setItemInHand(ctx.wandHand, spoofedStack)
|
||||||
|
|
||||||
|
val blockHit = BlockHitResult(
|
||||||
|
Vec3.ZERO, ctx.caster.direction, pos, false
|
||||||
|
)
|
||||||
|
val itemUseCtx = UseOnContext(ctx.caster, ctx.wandHand, blockHit)
|
||||||
|
val res = spoofedStack.useOn(itemUseCtx)
|
||||||
|
|
||||||
|
ctx.caster.setItemInHand(ctx.wandHand, oldStack)
|
||||||
|
if (res != InteractionResult.FAIL) {
|
||||||
|
ctx.withdrawItem(placee, 1, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package at.petrak.hex.common.casting.operators.spells
|
package at.petrak.hex.common.casting.operators.spells
|
||||||
|
|
||||||
import at.petrak.hex.api.SimpleOperator
|
import at.petrak.hex.api.ConstManaOperator
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
import at.petrak.hex.api.SpellOperator.Companion.getChecked
|
||||||
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
import at.petrak.hex.api.SpellOperator.Companion.spellListOf
|
||||||
import at.petrak.hex.common.casting.CastingContext
|
import at.petrak.hex.common.casting.CastingContext
|
||||||
|
@ -10,7 +10,7 @@ import at.petrak.hex.common.casting.SpellDatum
|
||||||
import net.minecraft.Util
|
import net.minecraft.Util
|
||||||
import net.minecraft.network.chat.TextComponent
|
import net.minecraft.network.chat.TextComponent
|
||||||
|
|
||||||
object OpPrint : SimpleOperator, RenderedSpellImpl {
|
object OpPrint : ConstManaOperator, RenderedSpellImpl {
|
||||||
override val argc = 1
|
override val argc = 1
|
||||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||||
val datum = args.getChecked<Any>(0)
|
val datum = args.getChecked<Any>(0)
|
||||||
|
|
|
@ -2,23 +2,46 @@ package at.petrak.hex.common.items;
|
||||||
|
|
||||||
import at.petrak.hex.HexMod;
|
import at.petrak.hex.HexMod;
|
||||||
import at.petrak.hex.common.lib.LibItemNames;
|
import at.petrak.hex.common.lib.LibItemNames;
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.item.CreativeModeTab;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraftforge.registries.DeferredRegister;
|
import net.minecraftforge.registries.DeferredRegister;
|
||||||
import net.minecraftforge.registries.ForgeRegistries;
|
import net.minecraftforge.registries.ForgeRegistries;
|
||||||
import net.minecraftforge.registries.RegistryObject;
|
import net.minecraftforge.registries.RegistryObject;
|
||||||
|
|
||||||
public class HexItems {
|
public class HexItems {
|
||||||
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, HexMod.MOD_ID);
|
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, HexMod.MOD_ID);
|
||||||
|
public static final CreativeModeTab TAB = new CreativeModeTab("hex") {
|
||||||
|
@Override
|
||||||
|
public ItemStack makeIcon() {
|
||||||
|
return new ItemStack(SPELLBOOK::get);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fillItemList(NonNullList<ItemStack> items) {
|
||||||
|
// Make the wand spawn with some sensible NBT
|
||||||
|
var tag = new CompoundTag();
|
||||||
|
tag.putInt(ItemWand.TAG_MANA, 1000);
|
||||||
|
tag.putInt(ItemWand.TAG_MAX_MANA, 1000);
|
||||||
|
var stack = new ItemStack(WAND::get);
|
||||||
|
stack.setTag(tag);
|
||||||
|
items.add(stack);
|
||||||
|
|
||||||
|
super.fillItemList(items);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public static final RegistryObject<Item> WAND = ITEMS.register(LibItemNames.WAND,
|
public static final RegistryObject<Item> WAND = ITEMS.register(LibItemNames.WAND,
|
||||||
() -> new ItemWand(unstackable()));
|
() -> new ItemWand(new Item.Properties().stacksTo(1)));
|
||||||
public static final RegistryObject<Item> FOCUS = ITEMS.register(LibItemNames.FOCUS,
|
public static final RegistryObject<Item> FOCUS = ITEMS.register(LibItemNames.FOCUS,
|
||||||
() -> new ItemFocus(props()));
|
() -> new ItemFocus(props()));
|
||||||
public static final RegistryObject<Item> SPELLBOOK = ITEMS.register(LibItemNames.SPELLBOOK,
|
public static final RegistryObject<Item> SPELLBOOK = ITEMS.register(LibItemNames.SPELLBOOK,
|
||||||
() -> new ItemSpellbook(unstackable()));
|
() -> new ItemSpellbook(unstackable()));
|
||||||
|
|
||||||
public static Item.Properties props() {
|
public static Item.Properties props() {
|
||||||
return new Item.Properties();
|
return new Item.Properties().tab(TAB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Item.Properties unstackable() {
|
public static Item.Properties unstackable() {
|
||||||
|
|
|
@ -1,2 +1,18 @@
|
||||||
package at.petrak.hex.common.items;public class ItemDataDolder {
|
package at.petrak.hex.common.items;
|
||||||
|
|
||||||
|
import at.petrak.hex.common.casting.CastingContext;
|
||||||
|
import at.petrak.hex.common.casting.SpellDatum;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
abstract public class ItemDataHolder extends Item {
|
||||||
|
public ItemDataHolder(Properties pProperties) {
|
||||||
|
super(pProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public abstract SpellDatum<?> readDatum(CompoundTag tag, CastingContext ctx);
|
||||||
|
|
||||||
|
public abstract void writeDatum(CompoundTag tag, SpellDatum<?> datum);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,31 @@
|
||||||
package at.petrak.hex.common.items;
|
package at.petrak.hex.common.items;
|
||||||
|
|
||||||
import at.petrak.hex.HexMod;
|
import at.petrak.hex.HexMod;
|
||||||
|
import at.petrak.hex.common.casting.CastingContext;
|
||||||
|
import at.petrak.hex.common.casting.SpellDatum;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.Item;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class ItemFocus extends Item {
|
public class ItemFocus extends ItemDataHolder {
|
||||||
public static final ResourceLocation PREDICATE = new ResourceLocation(HexMod.MOD_ID, "datatype");
|
public static final ResourceLocation PREDICATE = new ResourceLocation(HexMod.MOD_ID, "datatype");
|
||||||
|
public static final String TAG_DATA = "data";
|
||||||
|
|
||||||
public ItemFocus(Properties pProperties) {
|
public ItemFocus(Properties pProperties) {
|
||||||
super(pProperties);
|
super(pProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable SpellDatum<?> readDatum(CompoundTag tag, CastingContext ctx) {
|
||||||
|
try {
|
||||||
|
return SpellDatum.DeserializeFromNBT(tag.getCompound(TAG_DATA), ctx);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeDatum(CompoundTag tag, SpellDatum<?> datum) {
|
||||||
|
tag.put(TAG_DATA, datum.serializeToNBT());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.chat.TextComponent;
|
import net.minecraft.network.chat.TextComponent;
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
import net.minecraft.network.chat.TranslatableComponent;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
@ -16,7 +15,7 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ItemSpellbook extends Item {
|
public class ItemSpellbook extends ItemDataHolder {
|
||||||
public static String TAG_SELECTED_PAGE = "page_idx";
|
public static String TAG_SELECTED_PAGE = "page_idx";
|
||||||
// this is a CompoundTag of string numerical keys to SpellData\
|
// this is a CompoundTag of string numerical keys to SpellData\
|
||||||
// it is 1-indexed, so that 0/0 can be the special case of "it is empty"
|
// it is 1-indexed, so that 0/0 can be the special case of "it is empty"
|
||||||
|
@ -64,7 +63,29 @@ public class ItemSpellbook extends Item {
|
||||||
tag.getCompound(ItemSpellbook.TAG_PAGES).isEmpty();
|
tag.getCompound(ItemSpellbook.TAG_PAGES).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteDatum(CompoundTag tag, SpellDatum<?> datum) {
|
|
||||||
|
@Nullable
|
||||||
|
public SpellDatum<?> readDatum(CompoundTag tag, CastingContext ctx) {
|
||||||
|
int idx;
|
||||||
|
if (tag.contains(TAG_SELECTED_PAGE)) {
|
||||||
|
idx = tag.getInt(TAG_SELECTED_PAGE);
|
||||||
|
} else {
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
var key = String.valueOf(idx);
|
||||||
|
if (tag.contains(TAG_PAGES)) {
|
||||||
|
var pagesTag = tag.getCompound(TAG_PAGES);
|
||||||
|
if (pagesTag.contains(key)) {
|
||||||
|
return SpellDatum.DeserializeFromNBT(pagesTag.getCompound(key), ctx);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeDatum(CompoundTag tag, SpellDatum<?> datum) {
|
||||||
int idx;
|
int idx;
|
||||||
if (tag.contains(TAG_SELECTED_PAGE)) {
|
if (tag.contains(TAG_SELECTED_PAGE)) {
|
||||||
idx = tag.getInt(TAG_SELECTED_PAGE);
|
idx = tag.getInt(TAG_SELECTED_PAGE);
|
||||||
|
@ -85,27 +106,6 @@ public class ItemSpellbook extends Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static SpellDatum<?> ReadDatum(CompoundTag tag, CastingContext ctx) {
|
|
||||||
int idx;
|
|
||||||
if (tag.contains(TAG_SELECTED_PAGE)) {
|
|
||||||
idx = tag.getInt(TAG_SELECTED_PAGE);
|
|
||||||
} else {
|
|
||||||
idx = 0;
|
|
||||||
}
|
|
||||||
var key = String.valueOf(idx);
|
|
||||||
if (tag.contains(TAG_PAGES)) {
|
|
||||||
var pagesTag = tag.getCompound(TAG_PAGES);
|
|
||||||
if (pagesTag.contains(key)) {
|
|
||||||
return SpellDatum.DeserializeFromNBT(pagesTag.getCompound(key), ctx);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int HighestPage(CompoundTag tag) {
|
public static int HighestPage(CompoundTag tag) {
|
||||||
var highestKey = tag.getAllKeys().stream().flatMap(s -> {
|
var highestKey = tag.getAllKeys().stream().flatMap(s -> {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
package at.petrak.hex.common.items;
|
package at.petrak.hex.common.items;
|
||||||
|
|
||||||
|
import at.petrak.hex.HexMod;
|
||||||
import at.petrak.hex.client.gui.GuiSpellcasting;
|
import at.petrak.hex.client.gui.GuiSpellcasting;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResultHolder;
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
public class ItemWand extends Item {
|
public class ItemWand extends Item {
|
||||||
|
public static final String TAG_MANA = "mana";
|
||||||
|
public static final String TAG_MAX_MANA = "maxMana";
|
||||||
|
public static final String TAG_HARNESS = "harness";
|
||||||
|
|
||||||
public ItemWand(Properties pProperties) {
|
public ItemWand(Properties pProperties) {
|
||||||
super(pProperties);
|
super(pProperties);
|
||||||
}
|
}
|
||||||
|
@ -22,4 +29,61 @@ public class ItemWand extends Item {
|
||||||
|
|
||||||
return InteractionResultHolder.success(player.getItemInHand(hand));
|
return InteractionResultHolder.success(player.getItemInHand(hand));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void inventoryTick(ItemStack pStack, Level pLevel, Entity pEntity, int pSlotId, boolean pIsSelected) {
|
||||||
|
var tag = pStack.getOrCreateTag();
|
||||||
|
var mana = tag.getInt(TAG_MANA);
|
||||||
|
var maxMana = tag.getInt(TAG_MAX_MANA);
|
||||||
|
if (mana < maxMana) {
|
||||||
|
tag.putInt(TAG_MANA, Math.min(maxMana, mana + HexMod.CONFIG.wandRechargeRate.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDamageable(ItemStack stack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canBeDepleted() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBarVisible(ItemStack pStack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBarColor(ItemStack pStack) {
|
||||||
|
var tag = pStack.getOrCreateTag();
|
||||||
|
var mana = tag.getInt(TAG_MANA);
|
||||||
|
var maxMana = tag.getInt(TAG_MAX_MANA);
|
||||||
|
float amt;
|
||||||
|
if (maxMana == 0) {
|
||||||
|
amt = 0f;
|
||||||
|
} else {
|
||||||
|
amt = ((float) mana) / ((float) maxMana);
|
||||||
|
}
|
||||||
|
|
||||||
|
var r = Mth.lerp(amt, 149f, 112f);
|
||||||
|
var g = Mth.lerp(amt, 196f, 219f);
|
||||||
|
var b = Mth.lerp(amt, 174f, 212f);
|
||||||
|
return Mth.color(r / 255f, g / 255f, b / 255f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBarWidth(ItemStack pStack) {
|
||||||
|
var tag = pStack.getOrCreateTag();
|
||||||
|
var mana = tag.getInt(TAG_MANA);
|
||||||
|
var maxMana = tag.getInt(TAG_MAX_MANA);
|
||||||
|
float amt;
|
||||||
|
if (maxMana == 0) {
|
||||||
|
amt = 0f;
|
||||||
|
} else {
|
||||||
|
amt = ((float) mana) / ((float) maxMana);
|
||||||
|
}
|
||||||
|
return Math.round(13f * amt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,7 @@
|
||||||
package at.petrak.hex.common.lib;public class LibDamage {
|
package at.petrak.hex.common.lib;
|
||||||
|
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
|
||||||
|
public class LibDamageSources {
|
||||||
|
public static final DamageSource OVERCAST = new DamageSource("hex.overcast").bypassArmor().bypassMagic().setMagic();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package at.petrak.hex.common.network;
|
package at.petrak.hex.common.network;
|
||||||
|
|
||||||
|
import at.petrak.hex.client.gui.GuiSpellcasting;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
@ -27,7 +28,7 @@ public record MsgNewSpellPatternAck(boolean quitCasting) {
|
||||||
public void handle(Supplier<NetworkEvent.Context> ctx) {
|
public void handle(Supplier<NetworkEvent.Context> ctx) {
|
||||||
ctx.get().enqueueWork(() ->
|
ctx.get().enqueueWork(() ->
|
||||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
|
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
|
||||||
if (quitCasting) {
|
if (quitCasting && Minecraft.getInstance().screen instanceof GuiSpellcasting) {
|
||||||
Minecraft.getInstance().setScreen(null);
|
Minecraft.getInstance().setScreen(null);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -42,7 +42,8 @@ public record MsgNewSpellPatternSyn(InteractionHand handUsed, HexPattern pattern
|
||||||
var held = sender.getItemInHand(this.handUsed);
|
var held = sender.getItemInHand(this.handUsed);
|
||||||
if (held.getItem() instanceof ItemWand) {
|
if (held.getItem() instanceof ItemWand) {
|
||||||
var tag = held.getOrCreateTag();
|
var tag = held.getOrCreateTag();
|
||||||
var harness = CastingHarness.DeserializeFromNBT(tag, sender, this.handUsed);
|
var harness = CastingHarness.DeserializeFromNBT(tag.getCompound(ItemWand.TAG_HARNESS), sender,
|
||||||
|
this.handUsed);
|
||||||
|
|
||||||
var res = harness.update(this.pattern);
|
var res = harness.update(this.pattern);
|
||||||
if (res instanceof CastResult.Success success) {
|
if (res instanceof CastResult.Success success) {
|
||||||
|
@ -52,15 +53,17 @@ public record MsgNewSpellPatternSyn(InteractionHand handUsed, HexPattern pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean quit;
|
boolean quit;
|
||||||
|
CompoundTag nextHarnessTag;
|
||||||
if (res instanceof CastResult.Nothing) {
|
if (res instanceof CastResult.Nothing) {
|
||||||
// save the changes
|
// save the changes
|
||||||
held.setTag(harness.serializeToNBT());
|
nextHarnessTag = harness.serializeToNBT();
|
||||||
quit = false;
|
quit = false;
|
||||||
} else {
|
} else {
|
||||||
// Else we requested to quit in some way or another
|
// Else we requested to quit in some way or another
|
||||||
held.setTag(new CompoundTag());
|
nextHarnessTag = new CompoundTag();
|
||||||
quit = true;
|
quit = true;
|
||||||
}
|
}
|
||||||
|
tag.put(ItemWand.TAG_HARNESS, nextHarnessTag);
|
||||||
HexMessages.getNetwork()
|
HexMessages.getNetwork()
|
||||||
.send(PacketDistributor.PLAYER.with(() -> sender),
|
.send(PacketDistributor.PLAYER.with(() -> sender),
|
||||||
new MsgNewSpellPatternAck(quit));
|
new MsgNewSpellPatternAck(quit));
|
||||||
|
|
|
@ -26,7 +26,7 @@ public record MsgQuitSpellcasting() {
|
||||||
var held = sender.getMainHandItem();
|
var held = sender.getMainHandItem();
|
||||||
if (held.getItem() instanceof ItemWand) {
|
if (held.getItem() instanceof ItemWand) {
|
||||||
// Todo: appropriate consequences for quitting a spell like this
|
// Todo: appropriate consequences for quitting a spell like this
|
||||||
held.setTag(new CompoundTag());
|
held.getOrCreateTag().put(ItemWand.TAG_HARNESS, new CompoundTag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,32 @@
|
||||||
package at.petrak.hex.server
|
package at.petrak.hex.server
|
||||||
|
|
||||||
|
import net.minecraftforge.event.TickEvent
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object TickScheduler {
|
object TickScheduler {
|
||||||
|
val tasks: MutableList<Task> = LinkedList()
|
||||||
|
|
||||||
|
fun schedule(task: Task) {
|
||||||
|
this.tasks.add(task)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun schedule(ticks: Int, task: Runnable) {
|
||||||
|
this.tasks.add(Task(ticks, task))
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
fun onTick(evt: TickEvent.ServerTickEvent) {
|
||||||
|
this.tasks.removeIf {
|
||||||
|
it.ticks--
|
||||||
|
if (it.ticks <= 0) {
|
||||||
|
it.task.run()
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Task(var ticks: Int, val task: Runnable)
|
||||||
}
|
}
|
|
@ -3,5 +3,7 @@
|
||||||
"item.hex.focus": "Focus",
|
"item.hex.focus": "Focus",
|
||||||
"item.hex.spellbook": "Spellbook",
|
"item.hex.spellbook": "Spellbook",
|
||||||
"hex.spellbook.tooltip.page": "Selected Page %d/%d",
|
"hex.spellbook.tooltip.page": "Selected Page %d/%d",
|
||||||
"hex.spelldata.desc.entity": "Entity %s"
|
"hex.spelldata.desc.entity": "Entity %s",
|
||||||
|
|
||||||
|
"itemGroup.hex": "Hex"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue