Merge branch 'main' into fix173+175
This commit is contained in:
commit
d327d4d943
166 changed files with 4030 additions and 1283 deletions
|
@ -38,6 +38,9 @@ dependencies {
|
|||
compileOnly "at.petra-k.paucal:paucal-common-$minecraftVersion:$paucalVersion"
|
||||
compileOnly "vazkii.patchouli:Patchouli-xplat:$minecraftVersion-$patchouliVersion"
|
||||
|
||||
compileOnly "org.jetbrains:annotations:$jetbrainsAnnotationsVersion"
|
||||
testCompileOnly "org.jetbrains:annotations:$jetbrainsAnnotationsVersion"
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.1'
|
||||
}
|
||||
|
|
|
@ -337,5 +337,5 @@ b6593ea802a692c29b5032292df31beb84878ad8 data/hexcasting/advancements/aaa_wastef
|
|||
4f4c94021adfb296e3ef3dce1acc46f724f38f92 data/hexcasting/advancements/aab_big_cast.json
|
||||
2fe3543a209fca031b1eace7ea217c76142609cc data/hexcasting/advancements/enlightenment.json
|
||||
eb6393ffc79966e4b5983a68157742b78cd12414 data/hexcasting/advancements/opened_eyes.json
|
||||
ed0e62cb81783d8eb6323dd70609067219f163ec data/hexcasting/advancements/root.json
|
||||
a66a85cef9a3195e4388ecc16786e2a9f6ed3b56 data/hexcasting/advancements/root.json
|
||||
739cbdf7f204132f2acfab4df8d21c6197aa1456 data/hexcasting/advancements/y_u_no_cast_angy.json
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"items": [
|
||||
"hexcasting:charged_amethyst"
|
||||
]
|
||||
"tag": "hexcasting:grants_root_advancement"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.spell.math.EulerPathFinder
|
|||
import at.petrak.hexcasting.api.spell.math.HexDir
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidPattern
|
||||
import at.petrak.hexcasting.api.utils.getSafe
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
@ -26,6 +27,7 @@ import java.util.concurrent.ConcurrentMap
|
|||
*/
|
||||
object PatternRegistry {
|
||||
private val operatorLookup = ConcurrentHashMap<ResourceLocation, Operator>()
|
||||
private val keyLookup = ConcurrentHashMap<Operator, ResourceLocation>()
|
||||
private val specialHandlers: ConcurrentLinkedDeque<SpecialHandlerEntry> = ConcurrentLinkedDeque()
|
||||
|
||||
// Map signatures to the "preferred" direction they start in and their operator ID.
|
||||
|
@ -47,6 +49,7 @@ object PatternRegistry {
|
|||
}
|
||||
|
||||
this.operatorLookup[id] = operator
|
||||
this.keyLookup[operator] = id
|
||||
if (isPerWorld) {
|
||||
this.perWorldPatternLookup[id] = PerWorldEntry(pattern, id)
|
||||
} else {
|
||||
|
@ -81,14 +84,6 @@ object PatternRegistry {
|
|||
*/
|
||||
@JvmStatic
|
||||
fun matchPatternAndID(pat: HexPattern, overworld: ServerLevel): Pair<Operator, ResourceLocation> {
|
||||
// Pipeline:
|
||||
// patterns are registered here every time the game boots
|
||||
// when we try to look
|
||||
for (handler in specialHandlers) {
|
||||
val op = handler.handler.handlePattern(pat)
|
||||
if (op != null) return op to handler.id
|
||||
}
|
||||
|
||||
// Is it global?
|
||||
val sig = pat.anglesSignature()
|
||||
this.regularPatternLookup[sig]?.let {
|
||||
|
@ -105,6 +100,14 @@ object PatternRegistry {
|
|||
return op to it.first
|
||||
}
|
||||
|
||||
// Lookup a special handler
|
||||
// Do this last to prevent conflicts with great spells; this has happened a few times with
|
||||
// create phial hahaha
|
||||
for (handler in specialHandlers) {
|
||||
val op = handler.handler.handlePattern(pat)
|
||||
if (op != null) return op to handler.id
|
||||
}
|
||||
|
||||
throw MishapInvalidPattern()
|
||||
}
|
||||
|
||||
|
@ -119,6 +122,12 @@ object PatternRegistry {
|
|||
return perWorldPatterns.lookup
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal use only.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun lookupPattern(op: Operator): ResourceLocation? = this.keyLookup[op]
|
||||
|
||||
/**
|
||||
* Internal use only.
|
||||
*/
|
||||
|
@ -175,7 +184,7 @@ object PatternRegistry {
|
|||
val (id, startDir) = rhs
|
||||
val entry = CompoundTag()
|
||||
entry.putString(TAG_OP_ID, id.toString())
|
||||
entry.putInt(TAG_START_DIR, startDir.ordinal)
|
||||
entry.putByte(TAG_START_DIR, startDir.ordinal.toByte())
|
||||
tag.put(sig, entry)
|
||||
}
|
||||
return tag
|
||||
|
@ -186,8 +195,8 @@ object PatternRegistry {
|
|||
val map = HashMap<String, Pair<ResourceLocation, HexDir>>()
|
||||
for (sig in tag.allKeys) {
|
||||
val entry = tag.getCompound(sig)
|
||||
val opId = ResourceLocation.tryParse(entry.getString(TAG_OP_ID))!!
|
||||
val startDir = HexDir.values()[entry.getInt(TAG_START_DIR)]
|
||||
val opId = ResourceLocation.tryParse(entry.getString(TAG_OP_ID)) ?: continue
|
||||
val startDir = HexDir.values().getSafe(entry.getByte(TAG_START_DIR))
|
||||
map[sig] = opId to startDir
|
||||
}
|
||||
return Save(map)
|
||||
|
|
|
@ -1,25 +1,69 @@
|
|||
package at.petrak.hexcasting.api.addldata;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public interface ManaHolder {
|
||||
|
||||
/**
|
||||
* Use {@code withdrawMana(-1, true)}
|
||||
*
|
||||
* @see ManaHolder#withdrawMana(int, boolean)
|
||||
*/
|
||||
@ApiStatus.OverrideOnly
|
||||
int getMana();
|
||||
|
||||
/**
|
||||
* Use {@code withdrawMana(-1, true) + insertMana(-1, true)} where possible
|
||||
*
|
||||
* @see ManaHolder#insertMana(int, boolean)
|
||||
* @see ManaHolder#withdrawMana(int, boolean)
|
||||
*/
|
||||
@ApiStatus.OverrideOnly
|
||||
int getMaxMana();
|
||||
|
||||
/**
|
||||
* Use {@code insertMana(mana - withdrawMana(-1, true), false)} where possible
|
||||
*
|
||||
* @see ManaHolder#insertMana(int, boolean)
|
||||
* @see ManaHolder#withdrawMana(int, boolean)
|
||||
*/
|
||||
@ApiStatus.OverrideOnly
|
||||
void setMana(int mana);
|
||||
|
||||
/**
|
||||
* Whether this mana holder can have mana inserted into it.
|
||||
*/
|
||||
boolean canRecharge();
|
||||
|
||||
/**
|
||||
* Whether this mana holder can be extracted from.
|
||||
*/
|
||||
boolean canProvide();
|
||||
|
||||
/**
|
||||
* The priority for this mana holder to be selected when casting a hex. Higher priorities are taken first.
|
||||
*
|
||||
* By default,
|
||||
* * Charged Amethyst has priority 1
|
||||
* * Amethyst Shards have priority 2
|
||||
* * Amethyst Dust has priority 3
|
||||
* * Items which hold mana have priority 40
|
||||
*/
|
||||
int getConsumptionPriority();
|
||||
|
||||
/**
|
||||
* Whether the mana inside this mana holder may be used to construct a battery.
|
||||
*/
|
||||
boolean canConstructBattery();
|
||||
|
||||
/**
|
||||
* Withdraws mana from the holder. Returns the amount of mana extracted, which may be less or more than the cost.
|
||||
*
|
||||
* Even if {@link ManaHolder#canProvide} is false, you can still withdraw mana this way.
|
||||
*
|
||||
* Withdrawing a negative amount will act as though you attempted to withdraw as much mana as the holder contains.
|
||||
*/
|
||||
default int withdrawMana(int cost, boolean simulate) {
|
||||
if (!canProvide()) {
|
||||
return 0;
|
||||
}
|
||||
var manaHere = getMana();
|
||||
if (cost < 0) {
|
||||
cost = manaHere;
|
||||
|
@ -30,4 +74,30 @@ public interface ManaHolder {
|
|||
}
|
||||
return Math.min(cost, manaHere);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts mana into the holder. Returns the amount of mana inserted, which may be less than the requested amount.
|
||||
*
|
||||
* Even if {@link ManaHolder#canRecharge} is false, you can still insert mana this way.
|
||||
*
|
||||
* Inserting a negative amount will act as though you attempted to insert exactly as much mana as the holder was missing.
|
||||
*/
|
||||
default int insertMana(int amount, boolean simulate) {
|
||||
var manaHere = getMana();
|
||||
int emptySpace = getMaxMana() - manaHere;
|
||||
if (emptySpace <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (amount < 0) {
|
||||
amount = emptySpace;
|
||||
}
|
||||
|
||||
int inserting = Math.min(amount, emptySpace);
|
||||
|
||||
if (!simulate) {
|
||||
var newMana = manaHere + inserting;
|
||||
setMana(newMana);
|
||||
}
|
||||
return inserting;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class OvercastTrigger extends SimpleCriterionTrigger<OvercastTrigger.Inst
|
|||
super.trigger(player, inst -> {
|
||||
var manaToHealth = HexConfig.common().manaToHealthRate();
|
||||
var healthUsed = manaGenerated / manaToHealth;
|
||||
return inst.test(manaGenerated, healthUsed / player.getMaxHealth(), player.getHealth() - (float) healthUsed);
|
||||
return inst.test(manaGenerated, healthUsed / player.getMaxHealth(), player.getHealth());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@ import at.petrak.hexcasting.common.lib.HexItems;
|
|||
import at.petrak.hexcasting.common.lib.HexSounds;
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -36,6 +34,7 @@ import net.minecraft.world.entity.player.Player;
|
|||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -44,6 +43,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implements WorldlyContainer {
|
||||
|
@ -56,6 +56,8 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
|
|||
TAG_MANA = "mana",
|
||||
TAG_LAST_MISHAP = "last_mishap";
|
||||
|
||||
private static final DecimalFormat DUST_AMOUNT = new DecimalFormat("###,###.##");
|
||||
|
||||
@Nullable
|
||||
private UUID activator = null;
|
||||
@Nullable
|
||||
|
@ -114,16 +116,15 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
|
|||
}
|
||||
|
||||
public void applyScryingLensOverlay(List<Pair<ItemStack, Component>> lines,
|
||||
BlockState state, BlockPos pos,
|
||||
LocalPlayer observer, ClientLevel world,
|
||||
Direction hitFace) {
|
||||
BlockState state, BlockPos pos,
|
||||
Player observer, Level world,
|
||||
Direction hitFace) {
|
||||
if (world.getBlockEntity(pos) instanceof BlockEntityAbstractImpetus beai) {
|
||||
if (beai.getMana() < 0) {
|
||||
lines.add(new Pair<>(new ItemStack(HexItems.AMETHYST_DUST), ItemCreativeUnlocker.infiniteMedia(world)));
|
||||
} else {
|
||||
var dustCount = (float) beai.getMana() / (float) ManaConstants.DUST_UNIT;
|
||||
var dustCmp = new TranslatableComponent("hexcasting.tooltip.lens.impetus.mana",
|
||||
String.format("%.2f", dustCount));
|
||||
var dustCmp = new TranslatableComponent("hexcasting.tooltip.mana",
|
||||
DUST_AMOUNT.format(beai.getMana() / (float) ManaConstants.DUST_UNIT));
|
||||
lines.add(new Pair<>(new ItemStack(HexItems.AMETHYST_DUST), dustCmp));
|
||||
}
|
||||
|
||||
|
@ -540,6 +541,12 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
|
|||
|
||||
@Override
|
||||
public boolean canPlaceItem(int index, ItemStack stack) {
|
||||
if (remainingManaCapacity() == 0)
|
||||
return false;
|
||||
|
||||
if (stack.is(HexItems.CREATIVE_UNLOCKER))
|
||||
return true;
|
||||
|
||||
var manamount = extractManaFromItem(stack, true);
|
||||
return manamount > 0;
|
||||
}
|
||||
|
@ -557,7 +564,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
|
|||
} else {
|
||||
var manamount = extractManaFromItem(stack, false);
|
||||
if (manamount > 0) {
|
||||
this.mana += manamount;
|
||||
this.mana = Math.min(manamount + mana, MAX_CAPACITY);
|
||||
this.sync();
|
||||
}
|
||||
}
|
||||
|
@ -571,6 +578,6 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
|
|||
public int remainingManaCapacity() {
|
||||
if (this.mana < 0)
|
||||
return 0;
|
||||
return MAX_CAPACITY - this.mana;
|
||||
return Math.max(0, MAX_CAPACITY - this.mana);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
|||
import com.google.common.collect.Lists;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -36,15 +37,22 @@ public final class ScryingLensOverlayRegistry {
|
|||
private static final List<Pair<OverlayPredicate, OverlayBuilder>> PREDICATE_LOOKUP = new Vector<>();
|
||||
|
||||
// implemented as a map to allow for weak dereferencing
|
||||
private static final Map<LocalPlayer, Pair<BlockPos, Integer>> comparatorData = new WeakHashMap<>();
|
||||
private static final Map<Player, Pair<BlockPos, Integer>> comparatorData = new WeakHashMap<>();
|
||||
private static final Map<Player, Pair<BlockPos, Integer>> beeData = new WeakHashMap<>();
|
||||
|
||||
public static void receiveComparatorValue(BlockPos pos, int value) {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
public static void receiveComparatorAndBeeValue(BlockPos pos, int comparator, int bee) {
|
||||
Player player = Minecraft.getInstance().player;
|
||||
if (player != null) {
|
||||
if (pos == null || value == -1) {
|
||||
if (pos == null || comparator == -1) {
|
||||
comparatorData.remove(player);
|
||||
} else {
|
||||
comparatorData.put(player, new Pair<>(pos, value));
|
||||
comparatorData.put(player, new Pair<>(pos, comparator));
|
||||
}
|
||||
|
||||
if (pos == null || bee == -1) {
|
||||
beeData.remove(player);
|
||||
} else {
|
||||
beeData.put(player, new Pair<>(pos, bee));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +86,34 @@ public final class ScryingLensOverlayRegistry {
|
|||
return comparatorValue.getSecond();
|
||||
}
|
||||
|
||||
public static int getBeeValue() {
|
||||
var mc = Minecraft.getInstance();
|
||||
var player = mc.player;
|
||||
var level = mc.level;
|
||||
var result = mc.hitResult;
|
||||
|
||||
if (player == null || level == null || result == null || result.getType() != HitResult.Type.BLOCK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var beeValue = beeData.get(player);
|
||||
if (beeValue == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var pos = ((BlockHitResult) result).getBlockPos();
|
||||
if (!pos.equals(beeValue.getFirst())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var state = mc.level.getBlockState(pos);
|
||||
if (!(state.getBlock() instanceof BeehiveBlock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return beeValue.getSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the block to display things when the player is holding a lens and looking at it.
|
||||
*
|
||||
|
@ -113,7 +149,7 @@ public final class ScryingLensOverlayRegistry {
|
|||
* Internal use only.
|
||||
*/
|
||||
public static @NotNull List<Pair<ItemStack, Component>> getLines(BlockState state, BlockPos pos,
|
||||
LocalPlayer observer, ClientLevel world,
|
||||
Player observer, Level world,
|
||||
Direction hitFace) {
|
||||
List<Pair<ItemStack, Component>> lines = Lists.newArrayList();
|
||||
var idLookedup = ID_LOOKUP.get(IXplatAbstractions.INSTANCE.getID(state.getBlock()));
|
||||
|
@ -138,8 +174,8 @@ public final class ScryingLensOverlayRegistry {
|
|||
@FunctionalInterface
|
||||
public interface OverlayBuilder {
|
||||
void addLines(List<Pair<ItemStack, Component>> lines,
|
||||
BlockState state, BlockPos pos, LocalPlayer observer,
|
||||
ClientLevel world,
|
||||
BlockState state, BlockPos pos, Player observer,
|
||||
Level world,
|
||||
Direction hitFace);
|
||||
}
|
||||
|
||||
|
@ -148,8 +184,8 @@ public final class ScryingLensOverlayRegistry {
|
|||
*/
|
||||
@FunctionalInterface
|
||||
public interface OverlayPredicate {
|
||||
boolean test(BlockState state, BlockPos pos, LocalPlayer observer,
|
||||
ClientLevel world,
|
||||
boolean test(BlockState state, BlockPos pos, Player observer,
|
||||
Level world,
|
||||
Direction hitFace);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ package at.petrak.hexcasting.api.item;
|
|||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@ApiStatus.OverrideOnly
|
||||
public interface ColorizerItem {
|
||||
int color(ItemStack stack, UUID owner, float time, Vec3 position);
|
||||
}
|
||||
|
|
|
@ -11,10 +11,12 @@ import net.minecraft.network.chat.TranslatableComponent;
|
|||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ApiStatus.OverrideOnly
|
||||
public interface DataHolderItem {
|
||||
String TAG_OVERRIDE_VISUALLY = "VisualOverride";
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@ package at.petrak.hexcasting.api.item;
|
|||
import at.petrak.hexcasting.api.spell.SpellDatum;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ApiStatus.OverrideOnly
|
||||
public interface HexHolderItem extends ManaHolderItem {
|
||||
|
||||
boolean canDrawManaFromInventory(ItemStack stack);
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
package at.petrak.hexcasting.api.item;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* This interface should not be accessed direc
|
||||
*/
|
||||
@ApiStatus.OverrideOnly
|
||||
public interface ManaHolderItem {
|
||||
int getMana(ItemStack stack);
|
||||
|
||||
|
@ -32,4 +37,23 @@ public interface ManaHolderItem {
|
|||
}
|
||||
return Math.min(cost, manaHere);
|
||||
}
|
||||
|
||||
default int insertMana(ItemStack stack, int amount, boolean simulate) {
|
||||
var manaHere = getMana(stack);
|
||||
int emptySpace = getMaxMana(stack) - manaHere;
|
||||
if (emptySpace <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (amount < 0) {
|
||||
amount = emptySpace;
|
||||
}
|
||||
|
||||
int inserting = Math.min(amount, emptySpace);
|
||||
|
||||
if (!simulate) {
|
||||
var newMana = manaHere + inserting;
|
||||
setMana(stack, newMana);
|
||||
}
|
||||
return inserting;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package at.petrak.hexcasting.api.misc;
|
||||
|
||||
import at.petrak.hexcasting.api.addldata.ManaHolder;
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext;
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.util.ToFloatFunction;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class DiscoveryHandlers {
|
||||
private static final List<Predicate<Player>> HAS_LENS_PREDICATE = new ArrayList<>();
|
||||
private static final List<Function<CastingHarness, List<ManaHolder>>> MANA_HOLDER_DISCOVERY = new ArrayList<>();
|
||||
private static final List<ToFloatFunction<Player>> GRID_SCALE_MODIFIERS = new ArrayList<>();
|
||||
private static final List<Function<CastingContext, List<ItemStack>>> ITEM_SLOT_DISCOVERER = new ArrayList<>();
|
||||
private static final List<Function<CastingContext, List<ItemStack>>> OPERATIVE_SLOT_DISCOVERER = new ArrayList<>();
|
||||
|
||||
public static boolean hasLens(Player player) {
|
||||
for (var predicate : HAS_LENS_PREDICATE) {
|
||||
if (predicate.test(player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<ManaHolder> collectManaHolders(CastingHarness harness) {
|
||||
List<ManaHolder> holders = Lists.newArrayList();
|
||||
for (var discoverer : MANA_HOLDER_DISCOVERY) {
|
||||
holders.addAll(discoverer.apply(harness));
|
||||
}
|
||||
return holders;
|
||||
}
|
||||
|
||||
public static float gridScaleModifier(Player player) {
|
||||
float mod = 1;
|
||||
for (var modifier : GRID_SCALE_MODIFIERS) {
|
||||
mod *= modifier.apply(player);
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
public static List<ItemStack> collectItemSlots(CastingContext ctx) {
|
||||
List<ItemStack> stacks = Lists.newArrayList();
|
||||
for (var discoverer : ITEM_SLOT_DISCOVERER) {
|
||||
stacks.addAll(discoverer.apply(ctx));
|
||||
}
|
||||
return stacks;
|
||||
}
|
||||
|
||||
public static List<ItemStack> collectOperableSlots(CastingContext ctx) {
|
||||
List<ItemStack> stacks = Lists.newArrayList();
|
||||
for (var discoverer : OPERATIVE_SLOT_DISCOVERER) {
|
||||
stacks.addAll(discoverer.apply(ctx));
|
||||
}
|
||||
return stacks;
|
||||
}
|
||||
|
||||
public static void addLensPredicate(Predicate<Player> predicate) {
|
||||
HAS_LENS_PREDICATE.add(predicate);
|
||||
}
|
||||
|
||||
public static void addManaHolderDiscoverer(Function<CastingHarness, List<ManaHolder>> discoverer) {
|
||||
MANA_HOLDER_DISCOVERY.add(discoverer);
|
||||
}
|
||||
|
||||
public static void addGridScaleModifier(ToFloatFunction<Player> modifier) {
|
||||
GRID_SCALE_MODIFIERS.add(modifier);
|
||||
}
|
||||
|
||||
public static void addItemSlotDiscoverer(Function<CastingContext, List<ItemStack>> discoverer) {
|
||||
ITEM_SLOT_DISCOVERER.add(discoverer);
|
||||
}
|
||||
|
||||
public static void addOperativeSlotDiscoverer(Function<CastingContext, List<ItemStack>> discoverer) {
|
||||
OPERATIVE_SLOT_DISCOVERER.add(discoverer);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ public class HexItemTags {
|
|||
public static final TagKey<Item> AKASHIC_PLANKS = create("akashic_planks");
|
||||
public static final TagKey<Item> WANDS = create("wands");
|
||||
public static final TagKey<Item> PHIAL_BASE = create("phial_base");
|
||||
public static final TagKey<Item> GRANTS_ROOT_ADVANCEMENT = create("grants_root_advancement");
|
||||
|
||||
public static TagKey<Item> create(String name) {
|
||||
return create(modLoc(name));
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
package at.petrak.hexcasting.api.spell
|
||||
|
||||
import at.petrak.hexcasting.api.PatternRegistry
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.utils.asTranslatedComponent
|
||||
import at.petrak.hexcasting.api.utils.lightPurple
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.text.DecimalFormat
|
||||
|
||||
/**
|
||||
* Manipulates the stack in some way, usually by popping some number of values off the stack
|
||||
|
@ -40,6 +46,11 @@ interface Operator {
|
|||
*/
|
||||
val causesBlindDiversion: Boolean get() = this is SpellOperator
|
||||
|
||||
/**
|
||||
* The component for displaying this pattern's name. Override for dynamic patterns.
|
||||
*/
|
||||
val displayName: Component get() = "hexcasting.spell.${PatternRegistry.lookupPattern(this)}".asTranslatedComponent.lightPurple
|
||||
|
||||
companion object {
|
||||
// I see why vzakii did this: you can't raycast out to infinity!
|
||||
const val MAX_DISTANCE: Double = 32.0
|
||||
|
@ -57,6 +68,20 @@ interface Operator {
|
|||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> =
|
||||
listOf(x)
|
||||
}
|
||||
|
||||
private val DOUBLE_FORMATTER = DecimalFormat("####.####")
|
||||
|
||||
@JvmStatic
|
||||
fun makeConstantOp(x: Double, key: ResourceLocation): Operator = object : ConstManaOperator {
|
||||
override val argc: Int
|
||||
get() = 0
|
||||
|
||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> =
|
||||
x.asSpellResult
|
||||
|
||||
override val displayName: Component
|
||||
get() = "hexcasting.spell.$key".asTranslatedComponent(DOUBLE_FORMATTER.format(x)).lightPurple
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
TAG_PATTERN -> {
|
||||
val pat = HexPattern.fromNBT(nbt.getCompound(TAG_PATTERN))
|
||||
var angleDesc = pat.anglesSignature()
|
||||
if (angleDesc.isNotBlank()) angleDesc = " $angleDesc";
|
||||
if (angleDesc.isNotBlank()) angleDesc = " $angleDesc"
|
||||
out += "HexPattern(".gold
|
||||
out += "${pat.startDir}$angleDesc".white
|
||||
out += ")".gold
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.api.spell
|
||||
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import java.util.*
|
||||
import at.petrak.hexcasting.api.utils.getSafe
|
||||
|
||||
/**
|
||||
* Miscellaneous spell datums used as markers, etc.
|
||||
|
@ -22,8 +22,7 @@ enum class Widget : ConstManaOperator {
|
|||
companion object {
|
||||
@JvmStatic
|
||||
fun fromString(key: String): Widget {
|
||||
val lowercaseKey = key.lowercase(Locale.ROOT)
|
||||
return values().firstOrNull { it.name.lowercase(Locale.ROOT) == lowercaseKey } ?: GARBAGE
|
||||
return values().getSafe(key, GARBAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package at.petrak.hexcasting.api.spell.casting
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI.modLoc
|
||||
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
import at.petrak.hexcasting.api.spell.Operator
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapEntityTooFarAway
|
||||
|
@ -14,8 +15,8 @@ import net.minecraft.server.level.ServerPlayer
|
|||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.GameType
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.function.Predicate
|
||||
import kotlin.math.min
|
||||
|
@ -39,10 +40,14 @@ data class CastingContext(
|
|||
private val entitiesGivenMotion = mutableSetOf<Entity>()
|
||||
|
||||
inline fun getHeldItemToOperateOn(acceptItemIf: (ItemStack) -> Boolean): Pair<ItemStack, InteractionHand> {
|
||||
val handItem = caster.getItemInHand(castingHand)
|
||||
if (!acceptItemIf(handItem))
|
||||
return caster.getItemInHand(otherHand) to otherHand
|
||||
return handItem to castingHand
|
||||
val handItem = caster.getItemInHand(otherHand)
|
||||
if (!acceptItemIf(handItem)) {
|
||||
val castingItem = caster.getItemInHand(castingHand)
|
||||
if (acceptItemIf(castingItem)) {
|
||||
return castingItem to castingHand
|
||||
}
|
||||
}
|
||||
return handItem to otherHand
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,7 +88,8 @@ data class CastingContext(
|
|||
return entitiesGivenMotion.contains(target)
|
||||
}
|
||||
|
||||
fun isVecInWorld(vec: Vec3) = world.isInWorldBounds(BlockPos(vec)) && world.worldBorder.isWithinBounds(vec.x, vec.z, 0.5)
|
||||
fun isVecInWorld(vec: Vec3) =
|
||||
world.isInWorldBounds(BlockPos(vec)) && world.worldBorder.isWithinBounds(vec.x, vec.z, 0.5)
|
||||
|
||||
fun isVecInRange(vec: Vec3): Boolean {
|
||||
val sentinel = IXplatAbstractions.INSTANCE.getSentinel(caster)
|
||||
|
@ -117,6 +123,12 @@ data class CastingContext(
|
|||
return isVecInRange(entity.position())
|
||||
}
|
||||
|
||||
fun canEditBlockAt(pos: BlockPos): Boolean {
|
||||
return this.isVecInRange(Vec3.atCenterOf(pos))
|
||||
&& this.caster.gameMode.gameModeForPlayer != GameType.ADVENTURE
|
||||
&& this.world.mayInteract(this.caster, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slot from which to take blocks and items.
|
||||
*/
|
||||
|
@ -125,25 +137,12 @@ data class CastingContext(
|
|||
// 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.castingHand) {
|
||||
// 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)
|
||||
fun getOperativeSlot(stackOK: Predicate<ItemStack>): ItemStack? {
|
||||
val operable = DiscoveryHandlers.collectOperableSlots(this)
|
||||
|
||||
for (stack in operable) {
|
||||
if (stackOK.test(stack)) {
|
||||
return slot
|
||||
return stack
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
@ -154,17 +153,14 @@ data class CastingContext(
|
|||
* 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 {
|
||||
fun withdrawItem(item: ItemStack, 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.toMutableList().apply { removeAt(inv.selected) }.asReversed().toMutableList()
|
||||
stacksToExamine.addAll(inv.offhand)
|
||||
stacksToExamine.add(inv.getSelected())
|
||||
val stacksToExamine = DiscoveryHandlers.collectItemSlots(this)
|
||||
|
||||
fun matches(stack: ItemStack): Boolean =
|
||||
!stack.isEmpty && stack.`is`(item)
|
||||
!stack.isEmpty && ItemStack.isSameItemSameTags(item, stack)
|
||||
|
||||
val presentCount = stacksToExamine.fold(0) { acc, stack ->
|
||||
acc + if (matches(stack)) stack.count else 0
|
||||
|
@ -206,4 +202,28 @@ data class CastingContext(
|
|||
val advs = this.caster.advancements
|
||||
return advs.getOrStartProgress(adv!!).isDone
|
||||
}
|
||||
|
||||
companion object {
|
||||
init {
|
||||
DiscoveryHandlers.addItemSlotDiscoverer {
|
||||
val inv = it.caster.inventory
|
||||
inv.items.toMutableList().apply { removeAt(inv.selected) }.asReversed().toMutableList().apply {
|
||||
addAll(inv.offhand)
|
||||
add(inv.getSelected())
|
||||
}
|
||||
}
|
||||
|
||||
DiscoveryHandlers.addOperativeSlotDiscoverer {
|
||||
val slots = mutableListOf<ItemStack>()
|
||||
val anchorSlot = if (it.castingHand == InteractionHand.MAIN_HAND) (it.caster.inventory.selected + 1) % 9 else 0
|
||||
|
||||
slots.add(it.caster.getItemInHand(it.otherHand))
|
||||
for (delta in 0 until 9) {
|
||||
val slot = (anchorSlot + delta) % 9
|
||||
slots.add(it.caster.inventory.getItem(slot))
|
||||
}
|
||||
slots
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package at.petrak.hexcasting.api.spell.casting
|
|||
import at.petrak.hexcasting.api.PatternRegistry
|
||||
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers
|
||||
import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus
|
||||
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer
|
||||
import at.petrak.hexcasting.api.misc.HexDamageSources
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
|
@ -13,7 +14,6 @@ import at.petrak.hexcasting.api.spell.math.HexDir
|
|||
import at.petrak.hexcasting.api.spell.math.HexPattern
|
||||
import at.petrak.hexcasting.api.spell.mishaps.*
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
|
@ -47,6 +47,24 @@ class CastingHarness private constructor(
|
|||
*/
|
||||
fun executeIota(iota: SpellDatum<*>, world: ServerLevel): ControllerInfo = executeIotas(listOf(iota), world)
|
||||
|
||||
private fun getOperatorForPattern(iota: SpellDatum<*>, world: ServerLevel): Operator? {
|
||||
if (iota.getType() == DatumType.PATTERN)
|
||||
return PatternRegistry.matchPattern(iota.payload as HexPattern, world)
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getPatternForFrame(frame: ContinuationFrame): HexPattern? {
|
||||
if (frame !is ContinuationFrame.Evaluate) return null
|
||||
|
||||
return frame.list.car.payload as? HexPattern
|
||||
}
|
||||
|
||||
private fun getOperatorForFrame(frame: ContinuationFrame, world: ServerLevel): Operator? {
|
||||
if (frame !is ContinuationFrame.Evaluate) return null
|
||||
|
||||
return getOperatorForPattern(frame.list.car, world)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of iotas, execute them in sequence.
|
||||
*/
|
||||
|
@ -60,7 +78,23 @@ class CastingHarness private constructor(
|
|||
// Take the top of the continuation stack...
|
||||
val next = continuation.frame
|
||||
// ...and execute it.
|
||||
val result = next.evaluate(continuation.next, world, this)
|
||||
val result = try {
|
||||
next.evaluate(continuation.next, world, this)
|
||||
} catch (mishap: Mishap) {
|
||||
val pattern = getPatternForFrame(next)
|
||||
val operator = getOperatorForFrame(next, world)
|
||||
CastResult(
|
||||
continuation,
|
||||
null,
|
||||
mishap.resolutionType(ctx),
|
||||
listOf(
|
||||
OperatorSideEffect.DoMishap(
|
||||
mishap,
|
||||
Mishap.Context(pattern ?: HexPattern(HexDir.WEST), operator)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
// Then write all pertinent data back to the harness for the next iteration.
|
||||
if (result.newData != null) {
|
||||
this.applyFunctionalData(result.newData)
|
||||
|
@ -112,7 +146,7 @@ class CastingHarness private constructor(
|
|||
listOf(
|
||||
OperatorSideEffect.DoMishap(
|
||||
mishap,
|
||||
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null)
|
||||
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), getOperatorForPattern(iota, world))
|
||||
)
|
||||
),
|
||||
)
|
||||
|
@ -125,7 +159,7 @@ class CastingHarness private constructor(
|
|||
listOf(
|
||||
OperatorSideEffect.DoMishap(
|
||||
MishapError(exception),
|
||||
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null)
|
||||
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), getOperatorForPattern(iota, world))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -204,7 +238,7 @@ class CastingHarness private constructor(
|
|||
continuation,
|
||||
null,
|
||||
mishap.resolutionType(ctx),
|
||||
listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.second))),
|
||||
listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.first))),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
exception.printStackTrace()
|
||||
|
@ -215,7 +249,7 @@ class CastingHarness private constructor(
|
|||
listOf(
|
||||
OperatorSideEffect.DoMishap(
|
||||
MishapError(exception),
|
||||
Mishap.Context(newPat, operatorIdPair?.second)
|
||||
Mishap.Context(newPat, operatorIdPair?.first)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -381,21 +415,21 @@ class CastingHarness private constructor(
|
|||
val casterHexHolder = IXplatAbstractions.INSTANCE.findHexHolder(casterStack)
|
||||
val hexHolderDrawsFromInventory = if (casterHexHolder != null) {
|
||||
if (casterManaHolder != null) {
|
||||
val manaAvailable = casterManaHolder.mana
|
||||
val manaAvailable = casterManaHolder.withdrawMana(-1, true)
|
||||
val manaToTake = min(costLeft, manaAvailable)
|
||||
if (!fake) casterManaHolder.mana = manaAvailable - manaToTake
|
||||
if (!fake) casterManaHolder.withdrawMana(manaToTake, false)
|
||||
costLeft -= manaToTake
|
||||
}
|
||||
casterHexHolder.canDrawManaFromInventory()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
if (casterStack.`is`(HexItemTags.WANDS) || hexHolderDrawsFromInventory) {
|
||||
val manableItems = this.ctx.caster.inventory.items
|
||||
.filter(::isManaItem)
|
||||
val manaSources = DiscoveryHandlers.collectManaHolders(this)
|
||||
.sortedWith(Comparator(::compareManaItem).reversed())
|
||||
for (stack in manableItems) {
|
||||
costLeft -= extractMana(stack, costLeft, simulate = fake && !ItemCreativeUnlocker.isDebug(stack))
|
||||
for (source in manaSources) {
|
||||
costLeft -= extractMana(source, costLeft, simulate = fake)
|
||||
if (costLeft <= 0)
|
||||
break
|
||||
}
|
||||
|
@ -407,13 +441,17 @@ class CastingHarness private constructor(
|
|||
val manaAbleToCastFromHP = this.ctx.caster.health * manaToHealth
|
||||
|
||||
val manaToActuallyPayFor = min(manaAbleToCastFromHP.toInt(), costLeft)
|
||||
if (!fake) {
|
||||
HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.ctx.caster, manaToActuallyPayFor)
|
||||
this.ctx.caster.awardStat(HexStatistics.MANA_OVERCASTED, manaCost - costLeft)
|
||||
|
||||
costLeft -= if (!fake) {
|
||||
Mishap.trulyHurt(this.ctx.caster, HexDamageSources.OVERCAST, healthtoRemove.toFloat())
|
||||
|
||||
val actuallyTaken = (manaAbleToCastFromHP - (this.ctx.caster.health * manaToHealth)).toInt()
|
||||
|
||||
HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.ctx.caster, actuallyTaken)
|
||||
this.ctx.caster.awardStat(HexStatistics.MANA_OVERCASTED, manaCost - costLeft)
|
||||
actuallyTaken
|
||||
} else {
|
||||
manaToActuallyPayFor
|
||||
}
|
||||
costLeft -= manaToActuallyPayFor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -461,6 +499,24 @@ class CastingHarness private constructor(
|
|||
const val TAG_ESCAPE_NEXT = "escape_next"
|
||||
const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer"
|
||||
|
||||
init {
|
||||
DiscoveryHandlers.addManaHolderDiscoverer {
|
||||
it.ctx.caster.inventory.items
|
||||
.filter(::isManaItem)
|
||||
.mapNotNull(IXplatAbstractions.INSTANCE::findManaHolder)
|
||||
}
|
||||
DiscoveryHandlers.addManaHolderDiscoverer {
|
||||
it.ctx.caster.inventory.armor
|
||||
.filter(::isManaItem)
|
||||
.mapNotNull(IXplatAbstractions.INSTANCE::findManaHolder)
|
||||
}
|
||||
DiscoveryHandlers.addManaHolderDiscoverer {
|
||||
it.ctx.caster.inventory.offhand
|
||||
.filter(::isManaItem)
|
||||
.mapNotNull(IXplatAbstractions.INSTANCE::findManaHolder)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness {
|
||||
return try {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package at.petrak.hexcasting.api.spell.casting
|
||||
|
||||
import java.util.*
|
||||
import at.petrak.hexcasting.api.utils.getSafe
|
||||
|
||||
enum class ResolvedPatternType(val color: Int, val fadeColor: Int, val success: Boolean) {
|
||||
UNRESOLVED(0x7f7f7f, 0xcccccc, false),
|
||||
|
@ -12,8 +12,7 @@ enum class ResolvedPatternType(val color: Int, val fadeColor: Int, val success:
|
|||
companion object {
|
||||
@JvmStatic
|
||||
fun fromString(key: String): ResolvedPatternType {
|
||||
val lowercaseKey = key.lowercase(Locale.ROOT)
|
||||
return values().firstOrNull { it.name.lowercase(Locale.ROOT) == lowercaseKey } ?: UNRESOLVED
|
||||
return values().getSafe(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package at.petrak.hexcasting.api.spell.math
|
||||
|
||||
import java.util.*
|
||||
import at.petrak.hexcasting.api.utils.getSafe
|
||||
|
||||
enum class HexDir {
|
||||
NORTH_EAST, EAST, SOUTH_EAST, SOUTH_WEST, WEST, NORTH_WEST;
|
||||
|
@ -28,8 +28,7 @@ enum class HexDir {
|
|||
companion object {
|
||||
@JvmStatic
|
||||
fun fromString(key: String): HexDir {
|
||||
val lowercaseKey = key.lowercase(Locale.ROOT)
|
||||
return values().firstOrNull { it.name.lowercase(Locale.ROOT) == lowercaseKey } ?: WEST
|
||||
return values().getSafe(key, WEST)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package at.petrak.hexcasting.api.spell.math
|
|||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import at.petrak.hexcasting.api.utils.coordToPx
|
||||
import at.petrak.hexcasting.api.utils.findCenter
|
||||
import at.petrak.hexcasting.api.utils.getSafe
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.world.phys.Vec2
|
||||
|
@ -134,8 +135,8 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
|
|||
|
||||
@JvmStatic
|
||||
fun fromNBT(tag: CompoundTag): HexPattern {
|
||||
val startDir = HexDir.values()[tag.getByte(TAG_START_DIR).toInt()]
|
||||
val angles = tag.getByteArray(TAG_ANGLES).map { HexAngle.values()[it.toInt()] }
|
||||
val startDir = HexDir.values().getSafe(tag.getByte(TAG_START_DIR))
|
||||
val angles = tag.getByteArray(TAG_ANGLES).map(HexAngle.values()::getSafe)
|
||||
return HexPattern(startDir, angles.toMutableList())
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package at.petrak.hexcasting.api.spell.mishaps
|
|||
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer
|
||||
import at.petrak.hexcasting.api.mod.HexItemTags
|
||||
import at.petrak.hexcasting.api.spell.Operator
|
||||
import at.petrak.hexcasting.api.spell.ParticleSpray
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
|
@ -10,11 +11,11 @@ import at.petrak.hexcasting.api.spell.math.HexPattern
|
|||
import at.petrak.hexcasting.api.utils.asTranslatedComponent
|
||||
import at.petrak.hexcasting.api.utils.lightPurple
|
||||
import at.petrak.hexcasting.common.lib.HexItems
|
||||
import at.petrak.hexcasting.ktxt.lastHurt
|
||||
import at.petrak.hexcasting.ktxt.*
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
@ -53,8 +54,8 @@ sealed class Mishap : Throwable() {
|
|||
protected fun error(stub: String, vararg args: Any): Component =
|
||||
"hexcasting.mishap.$stub".asTranslatedComponent(*args)
|
||||
|
||||
protected fun actionName(action: ResourceLocation?): Component =
|
||||
"hexcasting.spell.${action ?: "unknown"}".asTranslatedComponent.lightPurple
|
||||
protected fun actionName(action: Operator?): Component =
|
||||
action?.displayName ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple
|
||||
|
||||
protected fun yeetHeldItemsTowards(ctx: CastingContext, targetPos: Vec3) {
|
||||
// Knock the player's items out of their hands
|
||||
|
@ -75,6 +76,8 @@ sealed class Mishap : Throwable() {
|
|||
|
||||
protected fun yeetHeldItem(ctx: CastingContext, hand: InteractionHand) {
|
||||
val item = ctx.caster.getItemInHand(hand).copy()
|
||||
if (hand == ctx.castingHand && IXplatAbstractions.INSTANCE.findHexHolder(item) != null)
|
||||
return
|
||||
ctx.caster.setItemInHand(hand, ItemStack.EMPTY)
|
||||
|
||||
val delta = ctx.caster.lookAngle.scale(0.5)
|
||||
|
@ -98,10 +101,11 @@ sealed class Mishap : Throwable() {
|
|||
return ctx.world.getBlockState(pos).block.name
|
||||
}
|
||||
|
||||
data class Context(val pattern: HexPattern, val action: ResourceLocation?)
|
||||
data class Context(val pattern: HexPattern, val action: Operator?)
|
||||
|
||||
companion object {
|
||||
fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {
|
||||
val targetHealth = entity.health - amount
|
||||
if (entity.invulnerableTime > 10) {
|
||||
val lastHurt = entity.lastHurt
|
||||
if (lastHurt < amount)
|
||||
|
@ -109,7 +113,25 @@ sealed class Mishap : Throwable() {
|
|||
else
|
||||
entity.lastHurt -= amount
|
||||
}
|
||||
entity.hurt(source, amount)
|
||||
if (!entity.hurt(source, amount)) {
|
||||
// Ok, if you REALLY don't want to play nice...
|
||||
entity.health = targetHealth
|
||||
entity.markHurt()
|
||||
|
||||
if (entity.isDeadOrDying) {
|
||||
if (!entity.checkTotemDeathProtection(source)) {
|
||||
val sound = entity.deathSoundAccessor
|
||||
if (sound != null) {
|
||||
entity.playSound(sound, entity.soundVolumeAccessor, entity.voicePitch)
|
||||
}
|
||||
entity.die(source)
|
||||
}
|
||||
} else {
|
||||
entity.playHurtSound(source)
|
||||
}
|
||||
|
||||
entity.setHurtWithStamp(source, entity.level.gameTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,18 @@ fun pxToCoord(px: Vec2, size: Float, offset: Vec2): HexCoord {
|
|||
HexCoord(q, r + (rf + 0.5 * qf).roundToInt())
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun <T : Enum<T>> Array<T>.getSafe(key: String, default: T = this[0]): T {
|
||||
val lowercaseKey = key.lowercase(Locale.ROOT)
|
||||
return firstOrNull { it.name.lowercase(Locale.ROOT) == lowercaseKey } ?: default
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun <T : Enum<T>> Array<T>.getSafe(index: Byte, default: T = this[0]) = getSafe(index.toInt(), default)
|
||||
|
||||
@JvmOverloads
|
||||
fun <T : Enum<T>> Array<T>.getSafe(index: Int, default: T = this[0]) = if (index in indices) this[index] else default
|
||||
|
||||
fun String.withStyle(op: (Style) -> Style): MutableComponent = asTextComponent.withStyle(op)
|
||||
fun String.withStyle(style: Style): MutableComponent = asTextComponent.withStyle(style)
|
||||
fun String.withStyle(formatting: ChatFormatting): MutableComponent = asTextComponent.withStyle(formatting)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
@file:JvmName("ManaHelper")
|
||||
package at.petrak.hexcasting.api.utils
|
||||
|
||||
import at.petrak.hexcasting.api.addldata.ManaHolder
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
@ -30,26 +31,38 @@ fun extractMana(
|
|||
): Int {
|
||||
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return 0
|
||||
|
||||
if (drainForBatteries && !manaHolder.canConstructBattery())
|
||||
return extractMana(manaHolder, cost, drainForBatteries, simulate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract [cost] mana from [holder]. If [cost] is less than zero, extract all mana instead.
|
||||
* This may mutate the stack underlying [holder] (and may consume it) unless [simulate] is set.
|
||||
*
|
||||
* If [drainForBatteries] is false, this will only consider forms of mana that can be used to make new batteries.
|
||||
*
|
||||
* Return the amount of mana extracted. This may be over [cost] if mana is wasted.
|
||||
*/
|
||||
fun extractMana(
|
||||
holder: ManaHolder,
|
||||
cost: Int = -1,
|
||||
drainForBatteries: Boolean = false,
|
||||
simulate: Boolean = false
|
||||
): Int {
|
||||
if (drainForBatteries && !holder.canConstructBattery())
|
||||
return 0
|
||||
|
||||
return manaHolder.withdrawMana(cost, simulate)
|
||||
return holder.withdrawMana(cost, simulate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorted from least important to most important
|
||||
*/
|
||||
fun compareManaItem(astack: ItemStack, bstack: ItemStack): Int {
|
||||
val aMana = IXplatAbstractions.INSTANCE.findManaHolder(astack)
|
||||
val bMana = IXplatAbstractions.INSTANCE.findManaHolder(bstack)
|
||||
fun compareManaItem(aMana: ManaHolder, bMana: ManaHolder): Int {
|
||||
val priority = aMana.consumptionPriority - bMana.consumptionPriority
|
||||
if (priority != 0)
|
||||
return priority
|
||||
|
||||
return if (astack.item != bstack.item) {
|
||||
(aMana?.consumptionPriority ?: 0) - (bMana?.consumptionPriority ?: 0)
|
||||
} else if (aMana != null && bMana != null) {
|
||||
aMana.mana - bMana.mana
|
||||
} else {
|
||||
astack.count - bstack.count
|
||||
}
|
||||
return aMana.withdrawMana(-1, true) - bMana.withdrawMana(-1, true)
|
||||
}
|
||||
|
||||
fun manaBarColor(mana: Int, maxMana: Int): Int {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package at.petrak.hexcasting.client;
|
||||
|
||||
import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry;
|
||||
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
|
||||
import at.petrak.hexcasting.api.player.Sentinel;
|
||||
import at.petrak.hexcasting.common.items.ItemLens;
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
@ -155,7 +155,7 @@ public class HexAdditionalRenderers {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!ItemLens.hasLensHUD(player))
|
||||
if (!DiscoveryHandlers.hasLens(player))
|
||||
return;
|
||||
|
||||
var hitRes = mc.hitResult;
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.mojang.datafixers.util.Pair;
|
|||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.network.chat.TextColor;
|
||||
|
@ -40,11 +41,14 @@ import net.minecraft.util.Mth;
|
|||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.*;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.ComparatorMode;
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
|
||||
import net.minecraft.world.level.block.state.properties.RailShape;
|
||||
import net.minecraft.world.level.material.MaterialColor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -184,12 +188,32 @@ public class RegisterClientStuff {
|
|||
.withStyle(redstoneColor(compare ? 0 : 15))));
|
||||
});
|
||||
|
||||
ScryingLensOverlayRegistry.addDisplayer(Blocks.POWERED_RAIL,
|
||||
(lines, state, pos, observer, world, direction) -> {
|
||||
int power = getPoweredRailStrength(world, pos, state);
|
||||
lines.add(new Pair<>(
|
||||
new ItemStack(Items.POWERED_RAIL),
|
||||
new TextComponent(String.valueOf(power))
|
||||
.withStyle(redstoneColor(power, 9))));
|
||||
});
|
||||
|
||||
ScryingLensOverlayRegistry.addDisplayer(Blocks.REPEATER,
|
||||
(lines, state, pos, observer, world, direction) -> lines.add(new Pair<>(
|
||||
new ItemStack(Items.CLOCK),
|
||||
new TextComponent(String.valueOf(state.getValue(RepeaterBlock.DELAY)))
|
||||
.withStyle(ChatFormatting.YELLOW))));
|
||||
|
||||
ScryingLensOverlayRegistry.addPredicateDisplayer(
|
||||
(state, pos, observer, world, direction) -> state.getBlock() instanceof BeehiveBlock,
|
||||
(lines, state, pos, observer, world, direction) -> {
|
||||
int count = ScryingLensOverlayRegistry.getBeeValue();
|
||||
lines.add(new Pair<>(new ItemStack(Items.BEE_NEST), count == -1 ? new TextComponent("") :
|
||||
new TranslatableComponent(
|
||||
"hexcasting.tooltip.lens.bee" + (count == 1 ? ".single" : ""),
|
||||
count
|
||||
)));
|
||||
});
|
||||
|
||||
ScryingLensOverlayRegistry.addPredicateDisplayer(
|
||||
(state, pos, observer, world, direction) -> state.isSignalSource() && !state.is(
|
||||
Blocks.COMPARATOR),
|
||||
|
@ -226,7 +250,11 @@ public class RegisterClientStuff {
|
|||
}
|
||||
|
||||
private static UnaryOperator<Style> redstoneColor(int power) {
|
||||
return color(RedStoneWireBlock.getColorForPower(Mth.clamp(power, 0, 15)));
|
||||
return redstoneColor(power, 15);
|
||||
}
|
||||
|
||||
private static UnaryOperator<Style> redstoneColor(int power, int max) {
|
||||
return color(RedStoneWireBlock.getColorForPower(Mth.clamp((power * max) / 15, 0, 15)));
|
||||
}
|
||||
|
||||
private static int instrumentColor(NoteBlockInstrument instrument) {
|
||||
|
@ -248,6 +276,114 @@ public class RegisterClientStuff {
|
|||
};
|
||||
}
|
||||
|
||||
private static int getPoweredRailStrength(Level level, BlockPos pos, BlockState state) {
|
||||
if (level.hasNeighborSignal(pos))
|
||||
return 9;
|
||||
int positiveValue = findPoweredRailSignal(level, pos, state, true, 0);
|
||||
int negativeValue = findPoweredRailSignal(level, pos, state, false, 0);
|
||||
return Math.max(positiveValue, negativeValue);
|
||||
}
|
||||
|
||||
// Copypasta from PoweredRailBlock.class
|
||||
private static int findPoweredRailSignal(Level level, BlockPos pos, BlockState state, boolean travelPositive, int depth) {
|
||||
if (depth >= 8) {
|
||||
return 0;
|
||||
} else {
|
||||
int x = pos.getX();
|
||||
int y = pos.getY();
|
||||
int z = pos.getZ();
|
||||
boolean descending = true;
|
||||
RailShape shape = state.getValue(PoweredRailBlock.SHAPE);
|
||||
switch(shape) {
|
||||
case NORTH_SOUTH:
|
||||
if (travelPositive) {
|
||||
++z;
|
||||
} else {
|
||||
--z;
|
||||
}
|
||||
break;
|
||||
case EAST_WEST:
|
||||
if (travelPositive) {
|
||||
--x;
|
||||
} else {
|
||||
++x;
|
||||
}
|
||||
break;
|
||||
case ASCENDING_EAST:
|
||||
if (travelPositive) {
|
||||
--x;
|
||||
} else {
|
||||
++x;
|
||||
++y;
|
||||
descending = false;
|
||||
}
|
||||
|
||||
shape = RailShape.EAST_WEST;
|
||||
break;
|
||||
case ASCENDING_WEST:
|
||||
if (travelPositive) {
|
||||
--x;
|
||||
++y;
|
||||
descending = false;
|
||||
} else {
|
||||
++x;
|
||||
}
|
||||
|
||||
shape = RailShape.EAST_WEST;
|
||||
break;
|
||||
case ASCENDING_NORTH:
|
||||
if (travelPositive) {
|
||||
++z;
|
||||
} else {
|
||||
--z;
|
||||
++y;
|
||||
descending = false;
|
||||
}
|
||||
|
||||
shape = RailShape.NORTH_SOUTH;
|
||||
break;
|
||||
case ASCENDING_SOUTH:
|
||||
if (travelPositive) {
|
||||
++z;
|
||||
++y;
|
||||
descending = false;
|
||||
} else {
|
||||
--z;
|
||||
}
|
||||
|
||||
shape = RailShape.NORTH_SOUTH;
|
||||
}
|
||||
|
||||
int power = getPowerFromRail(level, new BlockPos(x, y, z), travelPositive, depth, shape);
|
||||
|
||||
if (power > 0) {
|
||||
return power;
|
||||
} else if (descending) {
|
||||
return getPowerFromRail(level, new BlockPos(x, y - 1, z), travelPositive, depth, shape);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getPowerFromRail(Level level, BlockPos pos, boolean travelPositive, int depth, RailShape shape) {
|
||||
BlockState otherState = level.getBlockState(pos);
|
||||
if (!otherState.is(Blocks.POWERED_RAIL)) {
|
||||
return 0;
|
||||
} else {
|
||||
RailShape otherShape = otherState.getValue(PoweredRailBlock.SHAPE);
|
||||
if (shape == RailShape.EAST_WEST && (otherShape == RailShape.NORTH_SOUTH || otherShape == RailShape.ASCENDING_NORTH || otherShape == RailShape.ASCENDING_SOUTH)) {
|
||||
return 0;
|
||||
} else if (shape == RailShape.NORTH_SOUTH && (otherShape == RailShape.EAST_WEST || otherShape == RailShape.ASCENDING_EAST || otherShape == RailShape.ASCENDING_WEST)) {
|
||||
return 0;
|
||||
} else if (otherState.getValue(PoweredRailBlock.POWERED)) {
|
||||
return level.hasNeighborSignal(pos) ? 8 - depth : findPoweredRailSignal(level, pos, otherState, travelPositive, depth + 1);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerScollOverrides(ItemScroll scroll) {
|
||||
IClientXplatAbstractions.INSTANCE.registerItemProperty(scroll, ItemScroll.ANCIENT_PREDICATE,
|
||||
(stack, level, holder, holderID) -> NBTHelper.hasString(stack, ItemScroll.TAG_OP_ID) ? 1f : 0f);
|
||||
|
|
|
@ -125,7 +125,7 @@ public class WallScrollRenderer extends EntityRenderer<EntityWallScroll> {
|
|||
if (wallScroll.getShowsStrokeOrder()) {
|
||||
var spotFrac = 0.8f * wallScroll.blockSize;
|
||||
|
||||
var animTime = wallScroll.tickCount;
|
||||
var animTime = wallScroll.tickCount + partialTicks;
|
||||
var pointCircuit =
|
||||
(animTime * HexConfig.client().patternPointSpeedMultiplier()) % (points.size() + 10);
|
||||
if (pointCircuit < points.size() - 1) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package at.petrak.hexcasting.client.gui
|
||||
|
||||
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
import at.petrak.hexcasting.api.mod.HexItemTags
|
||||
import at.petrak.hexcasting.api.spell.casting.ControllerInfo
|
||||
|
@ -10,13 +11,11 @@ import at.petrak.hexcasting.api.spell.math.HexCoord
|
|||
import at.petrak.hexcasting.api.spell.math.HexDir
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern
|
||||
import at.petrak.hexcasting.api.utils.asTranslatedComponent
|
||||
import at.petrak.hexcasting.api.utils.otherHand
|
||||
import at.petrak.hexcasting.client.ShiftScrollListener
|
||||
import at.petrak.hexcasting.client.drawPatternFromPoints
|
||||
import at.petrak.hexcasting.client.drawSpot
|
||||
import at.petrak.hexcasting.client.ktxt.accumulatedScroll
|
||||
import at.petrak.hexcasting.client.sound.GridSoundInstance
|
||||
import at.petrak.hexcasting.common.lib.HexItems
|
||||
import at.petrak.hexcasting.common.lib.HexSounds
|
||||
import at.petrak.hexcasting.common.network.MsgNewSpellPatternSyn
|
||||
import at.petrak.hexcasting.xplat.IClientXplatAbstractions
|
||||
|
@ -208,10 +207,6 @@ class GuiSpellcasting(
|
|||
is PatternDrawState.JustStarted -> {
|
||||
// Well, we never managed to get anything on the stack this go-around.
|
||||
this.drawState = PatternDrawState.BetweenPatterns
|
||||
if (this.patterns.isEmpty()) {
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
Minecraft.getInstance().soundManager.stop(HexSounds.CASTING_AMBIANCE.location, null)
|
||||
}
|
||||
}
|
||||
is PatternDrawState.Drawing -> {
|
||||
val (start, _, pat) = this.drawState as PatternDrawState.Drawing
|
||||
|
@ -352,13 +347,12 @@ class GuiSpellcasting(
|
|||
|
||||
/** Distance between adjacent hex centers */
|
||||
fun hexSize(): Float {
|
||||
val hasLens = Minecraft.getInstance().player!!
|
||||
.getItemInHand(otherHand(this.handOpenedWith)).`is`(HexItems.SCRYING_LENS)
|
||||
val scaleModifier = DiscoveryHandlers.gridScaleModifier(Minecraft.getInstance().player)
|
||||
|
||||
// Originally, we allowed 32 dots across. Assuming a 1920x1080 screen this allowed like 500-odd area.
|
||||
// Let's be generous and give them 512.
|
||||
val baseScale = sqrt(this.width.toDouble() * this.height / 512.0)
|
||||
return baseScale.toFloat() * if (hasLens) 0.75f else 1f
|
||||
return baseScale.toFloat() * scaleModifier
|
||||
}
|
||||
|
||||
fun coordsOffset(): Vec2 = Vec2(this.width.toFloat() * 0.5f, this.height.toFloat() * 0.5f)
|
||||
|
|
|
@ -37,10 +37,9 @@ public class BlockAkashicFloodfiller extends Block {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static @Nullable
|
||||
BlockPos floodFillFor(BlockPos start, Level world,
|
||||
TriPredicate<BlockPos, BlockState, Level> isValid, TriPredicate<BlockPos, BlockState, Level> isTarget) {
|
||||
@Nullable
|
||||
public static BlockPos floodFillFor(BlockPos start, Level world,
|
||||
TriPredicate<BlockPos, BlockState, Level> isValid, TriPredicate<BlockPos, BlockState, Level> isTarget, int maxRange) {
|
||||
var seenBlocks = new HashSet<BlockPos>();
|
||||
var todo = new ArrayDeque<BlockPos>();
|
||||
todo.add(start);
|
||||
|
@ -50,6 +49,10 @@ public class BlockAkashicFloodfiller extends Block {
|
|||
|
||||
for (var dir : Direction.values()) {
|
||||
var neighbor = here.relative(dir);
|
||||
|
||||
if (neighbor.distSqr(start) > maxRange * maxRange)
|
||||
continue;
|
||||
|
||||
if (seenBlocks.add(neighbor)) {
|
||||
var bs = world.getBlockState(neighbor);
|
||||
if (isTarget.test(neighbor, bs, world)) {
|
||||
|
@ -64,10 +67,10 @@ public class BlockAkashicFloodfiller extends Block {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable
|
||||
BlockPos floodFillFor(BlockPos start, Level world,
|
||||
@Nullable
|
||||
public static BlockPos floodFillFor(BlockPos start, Level world,
|
||||
TriPredicate<BlockPos, BlockState, Level> isTarget) {
|
||||
return floodFillFor(start, world, BlockAkashicFloodfiller::canItBeFloodedThrough, isTarget);
|
||||
return floodFillFor(start, world, BlockAkashicFloodfiller::canItBeFloodedThrough, isTarget, 32);
|
||||
}
|
||||
|
||||
public static boolean canItBeFloodedThrough(BlockPos pos, BlockState state, Level world) {
|
||||
|
|
|
@ -5,8 +5,6 @@ import at.petrak.hexcasting.api.utils.NBTHelper;
|
|||
import at.petrak.hexcasting.common.lib.HexBlockEntities;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
@ -17,6 +15,7 @@ import net.minecraft.network.chat.TranslatableComponent;
|
|||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -79,9 +78,9 @@ public class BlockEntityStoredPlayerImpetus extends BlockEntityAbstractImpetus {
|
|||
}
|
||||
|
||||
public void applyScryingLensOverlay(List<Pair<ItemStack, Component>> lines,
|
||||
BlockState state, BlockPos pos, LocalPlayer observer,
|
||||
ClientLevel world,
|
||||
Direction hitFace) {
|
||||
BlockState state, BlockPos pos, Player observer,
|
||||
Level world,
|
||||
Direction hitFace) {
|
||||
super.applyScryingLensOverlay(lines, state, pos, observer, world, hitFace);
|
||||
|
||||
var name = this.getPlayerName();
|
||||
|
|
|
@ -38,6 +38,10 @@ import at.petrak.hexcasting.common.casting.operators.stack.*;
|
|||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LayeredCauldronBlock;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
|
@ -201,10 +205,13 @@ public class RegisterPatterns {
|
|||
modLoc("colorize"),
|
||||
OpColorize.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aqawqadaq", HexDir.SOUTH_EAST), modLoc("create_water"),
|
||||
OpCreateWater.INSTANCE);
|
||||
new OpCreateFluid(false, ManaConstants.DUST_UNIT,
|
||||
Items.WATER_BUCKET,
|
||||
Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, LayeredCauldronBlock.MAX_FILL_LEVEL),
|
||||
Fluids.WATER));
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("dedwedade", HexDir.SOUTH_WEST),
|
||||
modLoc("destroy_water"),
|
||||
OpDestroyWater.INSTANCE);
|
||||
OpDestroyFluid.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aaqawawa", HexDir.SOUTH_EAST), modLoc("ignite"),
|
||||
OpIgnite.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"),
|
||||
|
@ -292,7 +299,10 @@ public class RegisterPatterns {
|
|||
PatternRegistry.mapPattern(HexPattern.fromAngles("eawwaeawawaa", HexDir.NORTH_WEST),
|
||||
modLoc("flight"), OpFlight.INSTANCE, true);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eaqawqadaqd", HexDir.EAST),
|
||||
modLoc("create_lava"), OpCreateLava.INSTANCE, true);
|
||||
modLoc("create_lava"), new OpCreateFluid(true, ManaConstants.CRYSTAL_UNIT,
|
||||
Items.LAVA_BUCKET,
|
||||
Blocks.LAVA_CAULDRON.defaultBlockState(),
|
||||
Fluids.LAVA), true);
|
||||
PatternRegistry.mapPattern(
|
||||
HexPattern.fromAngles("wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq", HexDir.EAST),
|
||||
modLoc("teleport"), OpTeleport.INSTANCE, true);
|
||||
|
@ -490,7 +500,7 @@ public class RegisterPatterns {
|
|||
if (negate) {
|
||||
accumulator = -accumulator;
|
||||
}
|
||||
return Operator.makeConstantOp(SpellDatum.make(accumulator));
|
||||
return Operator.makeConstantOp(accumulator, modLoc("number"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -526,7 +536,7 @@ public class RegisterPatterns {
|
|||
return null;
|
||||
}
|
||||
|
||||
return new OpMask(mask);
|
||||
return new OpMask(mask, modLoc("mask"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package at.petrak.hexcasting.common.casting.operators
|
||||
|
||||
import at.petrak.hexcasting.api.addldata.DataHolder
|
||||
import at.petrak.hexcasting.api.spell.ParticleSpray
|
||||
import at.petrak.hexcasting.api.spell.RenderedSpell
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
|
@ -35,22 +36,15 @@ object OpWrite : SpellOperator {
|
|||
throw MishapOthersName(trueName)
|
||||
|
||||
return Triple(
|
||||
Spell(datum),
|
||||
Spell(datum, datumHolder),
|
||||
0,
|
||||
listOf()
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val datum: SpellDatum<*>) : RenderedSpell {
|
||||
private data class Spell(val datum: SpellDatum<*>, val datumHolder: DataHolder) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val (handStack) = ctx.getHeldItemToOperateOn {
|
||||
val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(it)
|
||||
|
||||
datumHolder != null && datumHolder.writeDatum(datum, true)
|
||||
}
|
||||
|
||||
val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack)
|
||||
datumHolder?.writeDatum(datum, false)
|
||||
datumHolder.writeDatum(datum, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ object OpRemove : ConstManaOperator {
|
|||
val list = args.getChecked<SpellList>(0, argc).toMutableList()
|
||||
val index = args.getChecked<Double>(1, argc).toInt()
|
||||
if (index < 0 || index >= list.size)
|
||||
return list
|
||||
return list.asSpellResult
|
||||
list.removeAt(index)
|
||||
return list.asSpellResult
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.math
|
||||
|
||||
import at.petrak.hexcasting.api.spell.ConstManaOperator
|
||||
import at.petrak.hexcasting.api.spell.numOrVec
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapDivideByZero
|
||||
import at.petrak.hexcasting.api.spell.numOrVec
|
||||
import at.petrak.hexcasting.api.spell.spellListOf
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.pow
|
||||
|
@ -40,7 +40,7 @@ object OpPowProj : ConstManaOperator {
|
|||
{ rvec ->
|
||||
if (lvec == Vec3.ZERO)
|
||||
throw MishapDivideByZero.of(lvec, rvec, "project")
|
||||
rvec.scale(rvec.dot(lvec) / lvec.dot(lvec))
|
||||
lvec.scale(rvec.dot(lvec) / lvec.dot(lvec))
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -5,9 +5,7 @@ import at.petrak.hexcasting.api.spell.*
|
|||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapImmuneEntity
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway
|
||||
import at.petrak.hexcasting.common.network.MsgBlinkAck
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import at.petrak.hexcasting.common.casting.operators.spells.great.OpTeleport
|
||||
import net.minecraft.world.entity.Entity
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
@ -47,12 +45,8 @@ object OpBlink : SpellOperator {
|
|||
|
||||
private data class Spell(val target: Entity, val delta: Double) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val dvec = target.lookAngle.scale(delta)
|
||||
target.setPos(target.position().add(dvec))
|
||||
if (target is ServerPlayer) {
|
||||
target.connection.resetPosition()
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(target, MsgBlinkAck(dvec))
|
||||
}
|
||||
val delta = target.lookAngle.scale(delta)
|
||||
OpTeleport.teleportRespectSticky(target, delta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,23 +15,22 @@ object OpBreakBlock : SpellOperator {
|
|||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
ctx: CastingContext
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
|
||||
val pos = args.getChecked<Vec3>(0, argc)
|
||||
ctx.assertVecInRange(pos)
|
||||
|
||||
val centered = Vec3.atCenterOf(BlockPos(pos))
|
||||
val bpos = BlockPos(pos)
|
||||
val centered = Vec3.atCenterOf(bpos)
|
||||
return Triple(
|
||||
Spell(pos),
|
||||
Spell(bpos),
|
||||
(ManaConstants.DUST_UNIT * 1.125).toInt(),
|
||||
listOf(ParticleSpray.burst(centered, 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val v: Vec3) : RenderedSpell {
|
||||
private data class Spell(val pos: BlockPos) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(v)
|
||||
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos))
|
||||
if (!ctx.canEditBlockAt(pos))
|
||||
return
|
||||
|
||||
val blockstate = ctx.world.getBlockState(pos)
|
||||
|
|
|
@ -9,6 +9,7 @@ import at.petrak.hexcasting.api.spell.SpellOperator
|
|||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
object OpColorize : SpellOperator {
|
||||
override val argc = 0
|
||||
|
@ -26,22 +27,19 @@ object OpColorize : SpellOperator {
|
|||
)
|
||||
}
|
||||
return Triple(
|
||||
Spell,
|
||||
Spell(handStack),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf()
|
||||
)
|
||||
}
|
||||
|
||||
private object Spell : RenderedSpell {
|
||||
private data class Spell(val stack: ItemStack) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val handStack = ctx.getHeldItemToOperateOn(IXplatAbstractions.INSTANCE::isColorizer).first.copy()
|
||||
if (IXplatAbstractions.INSTANCE.isColorizer(handStack)) {
|
||||
if (ctx.withdrawItem(handStack.item, 1, true)) {
|
||||
IXplatAbstractions.INSTANCE.setColorizer(
|
||||
ctx.caster,
|
||||
FrozenColorizer(handStack, ctx.caster.uuid)
|
||||
)
|
||||
}
|
||||
if (ctx.withdrawItem(stack, 1, true)) {
|
||||
IXplatAbstractions.INSTANCE.setColorizer(
|
||||
ctx.caster,
|
||||
FrozenColorizer(stack, ctx.caster.uuid)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class OpConjure(val light: Boolean) : SpellOperator {
|
|||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(target)
|
||||
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos))
|
||||
if (!ctx.canEditBlockAt(pos))
|
||||
return
|
||||
|
||||
val placeContext = DirectionalPlaceContext(ctx.world, pos, Direction.DOWN, ItemStack.EMPTY, Direction.UP)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.spells
|
||||
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.item.BucketItem
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.material.Fluid
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class OpCreateFluid(override val isGreat: Boolean, val cost: Int, val bucket: Item, val cauldron: BlockState, val fluid: Fluid) : SpellOperator {
|
||||
override val argc = 1
|
||||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
ctx: CastingContext
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||
val target = args.getChecked<Vec3>(0, argc)
|
||||
ctx.assertVecInRange(target)
|
||||
|
||||
return Triple(
|
||||
Spell(target, bucket, cauldron, fluid),
|
||||
cost,
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val target: Vec3, val bucket: Item, val cauldron: BlockState, val fluid: Fluid) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(target)
|
||||
|
||||
if (!ctx.canEditBlockAt(pos) || !IXplatAbstractions.INSTANCE.isPlacingAllowed(
|
||||
ctx.world,
|
||||
pos,
|
||||
ItemStack(bucket),
|
||||
ctx.caster
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
val state = ctx.world.getBlockState(pos)
|
||||
|
||||
if (state.block == Blocks.CAULDRON)
|
||||
ctx.world.setBlock(pos, cauldron, 3)
|
||||
else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid(
|
||||
ctx.world,
|
||||
ctx.castingHand,
|
||||
pos,
|
||||
fluid
|
||||
) && bucket is BucketItem) {
|
||||
// make the player null so we don't give them a usage statistic for example
|
||||
bucket.emptyContents(null, ctx.world, pos, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.spells
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.item.BucketItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.AbstractCauldronBlock
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.LayeredCauldronBlock
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object OpCreateWater : SpellOperator {
|
||||
override val argc = 1
|
||||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
ctx: CastingContext
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||
val target = args.getChecked<Vec3>(0, argc)
|
||||
ctx.assertVecInRange(target)
|
||||
|
||||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val target: Vec3) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(target)
|
||||
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos)|| !IXplatAbstractions.INSTANCE.isPlacingAllowed(ctx.world, pos, ItemStack(Items.WATER_BUCKET), ctx.caster))
|
||||
return
|
||||
val state = ctx.world.getBlockState(pos)
|
||||
|
||||
if (state.block is AbstractCauldronBlock)
|
||||
ctx.world.setBlock(
|
||||
pos,
|
||||
Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3),
|
||||
3
|
||||
)
|
||||
else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid(
|
||||
ctx.world,
|
||||
ctx.castingHand,
|
||||
pos,
|
||||
ItemStack(Items.WATER_BUCKET),
|
||||
Fluids.WATER
|
||||
)
|
||||
) {
|
||||
// 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, pos, null)
|
||||
} else {
|
||||
HexAPI.LOGGER.warn("Items.WATER_BUCKET wasn't a BucketItem?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,16 +9,13 @@ import net.minecraft.core.Direction
|
|||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.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.*
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.material.Material
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object OpDestroyWater : SpellOperator {
|
||||
object OpDestroyFluid : SpellOperator {
|
||||
override val argc = 1
|
||||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
|
@ -39,10 +36,24 @@ object OpDestroyWater : SpellOperator {
|
|||
private data class Spell(val target: Vec3) : RenderedSpell {
|
||||
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val basePos = BlockPos(target)
|
||||
|
||||
// Try draining from fluid handlers first, and if so, don't do the normal behavior
|
||||
if (ctx.canEditBlockAt(basePos)) {
|
||||
if (IXplatAbstractions.INSTANCE.drainAllFluid(ctx.world, basePos)) {
|
||||
return
|
||||
} else {
|
||||
val state = ctx.world.getBlockState(basePos)
|
||||
if (state.block is AbstractCauldronBlock && state.block != Blocks.CAULDRON) {
|
||||
ctx.world.setBlock(basePos, Blocks.CAULDRON.defaultBlockState(), 3)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SpongeBlock.java
|
||||
val todo = ArrayDeque<BlockPos>()
|
||||
val seen = HashSet<BlockPos>()
|
||||
val basePos = BlockPos(target)
|
||||
|
||||
// a little extra range on the initial cast to make it feel more intuitive
|
||||
for (xShift in -2..2) for (yShift in -2..2) for (zShift in -2..2) {
|
||||
|
@ -52,9 +63,7 @@ object OpDestroyWater : SpellOperator {
|
|||
var successes = 0
|
||||
while (todo.isNotEmpty() && successes <= MAX_DESTROY_COUNT) {
|
||||
val here = todo.removeFirst()
|
||||
val distFromFocus =
|
||||
ctx.caster.position().distanceToSqr(Vec3.atCenterOf(here))
|
||||
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here) && ctx.world.mayInteract(ctx.caster, here)) {
|
||||
if (ctx.canEditBlockAt(here) && seen.add(here)) {
|
||||
// never seen this pos in my life
|
||||
val fluid = ctx.world.getFluidState(here)
|
||||
if (fluid != Fluids.EMPTY.defaultFluidState()) {
|
||||
|
@ -88,25 +97,25 @@ object OpDestroyWater : SpellOperator {
|
|||
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 (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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -35,8 +35,9 @@ object OpEdifySapling : SpellOperator {
|
|||
private data class Spell(val pos: BlockPos) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val blockstate = ctx.world.getBlockState(pos)
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos) ||
|
||||
!IXplatAbstractions.INSTANCE.isBreakingAllowed(ctx.world, pos, blockstate, ctx.caster))
|
||||
if (!ctx.canEditBlockAt(pos) ||
|
||||
!IXplatAbstractions.INSTANCE.isBreakingAllowed(ctx.world, pos, blockstate, ctx.caster)
|
||||
)
|
||||
return
|
||||
|
||||
val bs = ctx.world.getBlockState(pos)
|
||||
|
|
|
@ -8,6 +8,7 @@ import at.petrak.hexcasting.api.spell.SpellOperator
|
|||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
class OpErase : SpellOperator {
|
||||
override val argc = 0
|
||||
|
@ -33,22 +34,15 @@ class OpErase : SpellOperator {
|
|||
}
|
||||
|
||||
return Triple(
|
||||
Spell,
|
||||
Spell(handStack),
|
||||
ManaConstants.DUST_UNIT, listOf()
|
||||
)
|
||||
}
|
||||
|
||||
private object Spell : RenderedSpell {
|
||||
private data class Spell(val stack: ItemStack) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val (handStack) = ctx.getHeldItemToOperateOn {
|
||||
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(it)
|
||||
val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(it)
|
||||
|
||||
(hexHolder?.hasHex() == true) ||
|
||||
(datumHolder?.writeDatum(null, true) == true)
|
||||
}
|
||||
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(handStack)
|
||||
val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack)
|
||||
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(stack)
|
||||
val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(stack)
|
||||
|
||||
if (hexHolder?.hasHex() == true)
|
||||
hexHolder.clearHex()
|
||||
|
|
|
@ -20,7 +20,7 @@ class OpExplode(val fire: Boolean) : SpellOperator {
|
|||
val strength = args.getChecked<Double>(1, argc)
|
||||
ctx.assertVecInRange(pos)
|
||||
val clampedStrength = Mth.clamp(strength, 0.0, 10.0)
|
||||
val cost = ManaConstants.DUST_UNIT * (3 * clampedStrength + if (fire) 0.125 else 1.0)
|
||||
val cost = ManaConstants.DUST_UNIT * (3 * clampedStrength + if (fire) 1.0 else 0.125)
|
||||
return Triple(
|
||||
Spell(pos, clampedStrength, this.fire),
|
||||
cost.toInt(),
|
||||
|
@ -30,7 +30,8 @@ class OpExplode(val fire: Boolean) : SpellOperator {
|
|||
|
||||
private data class Spell(val pos: Vec3, val strength: Double, val fire: Boolean) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
if (!ctx.world.mayInteract(ctx.caster, BlockPos(pos)))
|
||||
// TODO: you can use this to explode things *outside* of the worldborder?
|
||||
if (!ctx.canEditBlockAt(BlockPos(pos)))
|
||||
return
|
||||
|
||||
ctx.world.explode(
|
||||
|
|
|
@ -50,11 +50,7 @@ object OpExtinguish : SpellOperator {
|
|||
ctx.caster.position().distanceToSqr(Vec3.atCenterOf(here))
|
||||
val distFromTarget =
|
||||
target.distanceTo(Vec3.atCenterOf(here)) // max distance to prevent runaway shenanigans
|
||||
if (distFromFocus < Operator.MAX_DISTANCE * Operator.MAX_DISTANCE && seen.add(here) && distFromTarget < 10 && ctx.world.mayInteract(
|
||||
ctx.caster,
|
||||
here
|
||||
)
|
||||
) {
|
||||
if (ctx.canEditBlockAt(here) && distFromTarget < 10 && seen.add(here)) {
|
||||
// never seen this pos in my life
|
||||
val blockstate = ctx.world.getBlockState(here)
|
||||
if (IXplatAbstractions.INSTANCE.isBreakingAllowed(ctx.world, here, blockstate, ctx.caster)) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.spells
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
|
@ -9,7 +8,7 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions
|
|||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.item.FireChargeItem
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
|
@ -35,26 +34,26 @@ object OpIgnite : SpellOperator {
|
|||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(target)
|
||||
|
||||
// steal petra code that steals bucket code
|
||||
val maxwell = Items.FIRE_CHARGE
|
||||
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos) || !IXplatAbstractions.INSTANCE.isPlacingAllowed(ctx.world, pos, ItemStack(maxwell), ctx.caster))
|
||||
if (!ctx.canEditBlockAt(pos))
|
||||
return
|
||||
|
||||
if (maxwell is FireChargeItem) {
|
||||
// help
|
||||
maxwell.useOn(
|
||||
UseOnContext(
|
||||
ctx.world,
|
||||
null,
|
||||
InteractionHand.MAIN_HAND,
|
||||
ItemStack(maxwell),
|
||||
BlockHitResult(target, Direction.UP, pos, false)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
HexAPI.LOGGER.warn("Items.FIRE_CHARGE wasn't a FireChargeItem?")
|
||||
// help
|
||||
if (!tryToClick(ctx, pos, Items.FIRE_CHARGE)) {
|
||||
tryToClick(ctx, pos, Items.FLINT_AND_STEEL)
|
||||
}
|
||||
}
|
||||
|
||||
fun tryToClick(ctx: CastingContext, pos: BlockPos, item: Item): Boolean {
|
||||
return IXplatAbstractions.INSTANCE.isPlacingAllowed(ctx.world, pos, ItemStack(item), ctx.caster) &&
|
||||
item.useOn(
|
||||
UseOnContext(
|
||||
ctx.world,
|
||||
null,
|
||||
InteractionHand.MAIN_HAND,
|
||||
ItemStack(item),
|
||||
BlockHitResult(target, Direction.UP, pos, false)
|
||||
)
|
||||
).consumesAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,7 @@ package at.petrak.hexcasting.common.casting.operators.spells
|
|||
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants
|
||||
import at.petrak.hexcasting.api.mod.HexItemTags
|
||||
import at.petrak.hexcasting.api.spell.getChecked
|
||||
import at.petrak.hexcasting.api.spell.ParticleSpray
|
||||
import at.petrak.hexcasting.api.spell.RenderedSpell
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.SpellOperator
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
|
||||
|
@ -14,6 +10,7 @@ import at.petrak.hexcasting.api.utils.extractMana
|
|||
import at.petrak.hexcasting.api.utils.isManaItem
|
||||
import at.petrak.hexcasting.common.items.magic.ItemManaHolder
|
||||
import at.petrak.hexcasting.common.lib.HexItems
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
|
@ -59,14 +56,13 @@ object OpMakeBattery : SpellOperator {
|
|||
)
|
||||
}
|
||||
|
||||
return Triple(Spell(entity),
|
||||
return Triple(Spell(entity, hand),
|
||||
ManaConstants.CRYSTAL_UNIT, listOf(ParticleSpray.burst(entity.position(), 0.5)))
|
||||
}
|
||||
|
||||
private data class Spell(val itemEntity: ItemEntity) : RenderedSpell {
|
||||
private data class Spell(val itemEntity: ItemEntity, val hand: InteractionHand) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val (handStack, hand) = ctx.getHeldItemToOperateOn { it.`is`(HexItemTags.PHIAL_BASE) }
|
||||
if (handStack.`is`(HexItemTags.PHIAL_BASE) && itemEntity.isAlive) {
|
||||
if (itemEntity.isAlive) {
|
||||
val entityStack = itemEntity.item.copy()
|
||||
val manaAmt = extractMana(entityStack, drainForBatteries = true)
|
||||
if (manaAmt > 0) {
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.spells
|
||||
|
||||
import at.petrak.hexcasting.api.spell.getChecked
|
||||
import at.petrak.hexcasting.api.spell.ParticleSpray
|
||||
import at.petrak.hexcasting.api.spell.RenderedSpell
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.SpellOperator
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
|
||||
|
@ -15,6 +10,7 @@ import at.petrak.hexcasting.api.utils.isManaItem
|
|||
import at.petrak.hexcasting.common.items.magic.ItemPackagedHex
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) : SpellOperator {
|
||||
override val argc = 2
|
||||
|
@ -53,13 +49,12 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
|
|||
if (trueName != null)
|
||||
throw MishapOthersName(trueName)
|
||||
|
||||
return Triple(Spell(entity, patterns), cost, listOf(ParticleSpray.burst(entity.position(), 0.5)))
|
||||
return Triple(Spell(entity, patterns, handStack), cost, listOf(ParticleSpray.burst(entity.position(), 0.5)))
|
||||
}
|
||||
|
||||
private inner class Spell(val itemEntity: ItemEntity, val patterns: List<SpellDatum<*>>) : RenderedSpell {
|
||||
private inner class Spell(val itemEntity: ItemEntity, val patterns: List<SpellDatum<*>>, val stack: ItemStack) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val (handStack) = ctx.getHeldItemToOperateOn { it.`is`(itemType) }
|
||||
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(handStack)
|
||||
val hexHolder = IXplatAbstractions.INSTANCE.findHexHolder(stack)
|
||||
if (hexHolder != null
|
||||
&& !hexHolder.hasHex()
|
||||
&& itemEntity.isAlive
|
||||
|
|
|
@ -29,12 +29,8 @@ object OpPlaceBlock : SpellOperator {
|
|||
|
||||
val pos = BlockPos(target)
|
||||
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos))
|
||||
return null
|
||||
|
||||
|
||||
val blockHit = BlockHitResult(
|
||||
Vec3.ZERO, ctx.caster.direction, pos, false
|
||||
target, ctx.caster.direction, pos, false
|
||||
)
|
||||
val itemUseCtx = UseOnContext(ctx.caster, ctx.castingHand, blockHit)
|
||||
val placeContext = BlockPlaceContext(itemUseCtx)
|
||||
|
@ -54,17 +50,16 @@ object OpPlaceBlock : SpellOperator {
|
|||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(vec)
|
||||
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos))
|
||||
if (!ctx.canEditBlockAt(pos))
|
||||
return
|
||||
|
||||
val blockHit = BlockHitResult(
|
||||
Vec3.ZERO, ctx.caster.direction, pos, false
|
||||
vec, ctx.caster.direction, pos, false
|
||||
)
|
||||
|
||||
val bstate = ctx.world.getBlockState(pos)
|
||||
val placeeSlot = ctx.getOperativeSlot { it.item is BlockItem }
|
||||
if (placeeSlot != null) {
|
||||
val placeeStack = ctx.caster.inventory.getItem(placeeSlot).copy()
|
||||
val placeeStack = ctx.getOperativeSlot { it.item is BlockItem }?.copy()
|
||||
if (placeeStack != null) {
|
||||
if (!IXplatAbstractions.INSTANCE.isPlacingAllowed(ctx.world, pos, placeeStack, ctx.caster))
|
||||
return
|
||||
|
||||
|
@ -80,13 +75,12 @@ object OpPlaceBlock : SpellOperator {
|
|||
val itemUseCtx = UseOnContext(ctx.caster, ctx.castingHand, blockHit)
|
||||
val placeContext = BlockPlaceContext(itemUseCtx)
|
||||
if (bstate.canBeReplaced(placeContext)) {
|
||||
val placee = placeeStack.item as BlockItem
|
||||
if (ctx.withdrawItem(placee, 1, false)) {
|
||||
if (ctx.withdrawItem(placeeStack, 1, false)) {
|
||||
val res = spoofedStack.useOn(placeContext)
|
||||
|
||||
ctx.caster.setItemInHand(ctx.castingHand, oldStack)
|
||||
if (res != InteractionResult.FAIL) {
|
||||
ctx.withdrawItem(placee, 1, true)
|
||||
ctx.withdrawItem(placeeStack, 1, true)
|
||||
|
||||
ctx.world.playSound(
|
||||
ctx.caster,
|
||||
|
|
|
@ -26,11 +26,15 @@ class OpPotionEffect(
|
|||
val target = args.getChecked<LivingEntity>(0, argc)
|
||||
if (target is ArmorStand)
|
||||
throw MishapInvalidIota.ofClass(SpellDatum.make(target), 0, LivingEntity::class.java)
|
||||
|
||||
val duration = max(args.getChecked(1, argc), 0.0)
|
||||
ctx.assertEntityInRange(target)
|
||||
|
||||
val potency = if (this.allowPotency)
|
||||
args.getChecked<Double>(2, argc).coerceIn(1.0, 128.0)
|
||||
else 1.0
|
||||
else
|
||||
1.0
|
||||
|
||||
ctx.assertEntityInRange(target)
|
||||
|
||||
val cost = this.baseCost * duration * if (potencyCubic) {
|
||||
potency * potency * potency
|
||||
|
@ -47,8 +51,10 @@ class OpPotionEffect(
|
|||
private class Spell(val effect: MobEffect, val target: LivingEntity, val duration: Double, val potency: Double) :
|
||||
RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val effectInst = MobEffectInstance(effect, (duration * 20).toInt(), potency.toInt() - 1)
|
||||
target.addEffect(effectInst)
|
||||
if (duration > 1.0 / 20.0) {
|
||||
val effectInst = MobEffectInstance(effect, (duration * 20).toInt(), potency.toInt() - 1)
|
||||
target.addEffect(effectInst)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import at.petrak.hexcasting.api.utils.extractMana
|
|||
import at.petrak.hexcasting.api.utils.isManaItem
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
object OpRecharge : SpellOperator {
|
||||
override val argc = 1
|
||||
|
@ -18,7 +19,7 @@ object OpRecharge : SpellOperator {
|
|||
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
|
||||
val (handStack, hand) = ctx.getHeldItemToOperateOn {
|
||||
val mana = IXplatAbstractions.INSTANCE.findManaHolder(it)
|
||||
mana != null && mana.canRecharge() && mana.mana /* doo doo da do doo */ < mana.maxMana
|
||||
mana != null && mana.canRecharge() && mana.insertMana(-1, true) != 0
|
||||
}
|
||||
|
||||
val mana = IXplatAbstractions.INSTANCE.findManaHolder(handStack)
|
||||
|
@ -40,33 +41,28 @@ object OpRecharge : SpellOperator {
|
|||
)
|
||||
}
|
||||
|
||||
if (mana.mana >= mana.maxMana)
|
||||
if (mana.insertMana(-1, true) == 0)
|
||||
return null
|
||||
|
||||
return Triple(
|
||||
Spell(entity),
|
||||
Spell(entity, handStack),
|
||||
ManaConstants.SHARD_UNIT,
|
||||
listOf(ParticleSpray.burst(entity.position(), 0.5))
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val itemEntity: ItemEntity) : RenderedSpell {
|
||||
private data class Spell(val itemEntity: ItemEntity, val stack: ItemStack) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val (handStack) = ctx.getHeldItemToOperateOn {
|
||||
val mana = IXplatAbstractions.INSTANCE.findManaHolder(it)
|
||||
mana != null && mana.canRecharge() && mana.mana < mana.maxMana
|
||||
}
|
||||
val mana = IXplatAbstractions.INSTANCE.findManaHolder(handStack)
|
||||
val mana = IXplatAbstractions.INSTANCE.findManaHolder(stack)
|
||||
|
||||
if (mana != null && itemEntity.isAlive) {
|
||||
val entityStack = itemEntity.item.copy()
|
||||
|
||||
val maxMana = mana.maxMana
|
||||
val existingMana = mana.mana
|
||||
val emptySpace = mana.insertMana(-1, true)
|
||||
|
||||
val manaAmt = extractMana(entityStack, maxMana - existingMana)
|
||||
val manaAmt = extractMana(entityStack, emptySpace)
|
||||
|
||||
mana.mana = manaAmt + existingMana
|
||||
mana.insertMana(manaAmt, false)
|
||||
|
||||
itemEntity.item = entityStack
|
||||
if (entityStack.isEmpty)
|
||||
|
|
|
@ -25,7 +25,7 @@ object OpBrainsweep : SpellOperator {
|
|||
override fun execute(
|
||||
args: List<SpellDatum<*>>,
|
||||
ctx: CastingContext
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
|
||||
val sacrifice = args.getChecked<Villager>(0, argc)
|
||||
val pos = args.getChecked<Vec3>(1, argc)
|
||||
ctx.assertVecInRange(pos)
|
||||
|
@ -35,6 +35,10 @@ object OpBrainsweep : SpellOperator {
|
|||
throw MishapAlreadyBrainswept(sacrifice)
|
||||
|
||||
val bpos = BlockPos(pos)
|
||||
|
||||
if (!ctx.canEditBlockAt(bpos))
|
||||
return null
|
||||
|
||||
val state = ctx.world.getBlockState(bpos)
|
||||
|
||||
val recman = ctx.world.recipeManager
|
||||
|
@ -49,9 +53,15 @@ object OpBrainsweep : SpellOperator {
|
|||
)
|
||||
}
|
||||
|
||||
private data class Spell(val pos: BlockPos, val state: BlockState, val sacrifice: Villager, val recipe: BrainsweepRecipe) : RenderedSpell {
|
||||
private data class Spell(
|
||||
val pos: BlockPos,
|
||||
val state: BlockState,
|
||||
val sacrifice: Villager,
|
||||
val recipe: BrainsweepRecipe
|
||||
) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
ctx.world.setBlockAndUpdate(pos, BrainsweepRecipe.copyProperties(state, recipe.result))
|
||||
|
||||
Brainsweeping.brainsweep(sacrifice)
|
||||
if (HexConfig.server().doVillagersTakeOffenseAtMindMurder()) {
|
||||
sacrifice.tellWitnessesThatIWasMurdered(ctx.caster)
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.spells.great
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants
|
||||
import at.petrak.hexcasting.api.spell.*
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.item.BucketItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.AbstractCauldronBlock
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
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
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||
val target = args.getChecked<Vec3>(0, argc)
|
||||
ctx.assertVecInRange(target)
|
||||
|
||||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.CRYSTAL_UNIT,
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0)),
|
||||
)
|
||||
}
|
||||
|
||||
private data class Spell(val target: Vec3) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val pos = BlockPos(target)
|
||||
|
||||
if (!ctx.world.mayInteract(ctx.caster, pos)|| !IXplatAbstractions.INSTANCE.isPlacingAllowed(ctx.world, pos, ItemStack(Items.LAVA_BUCKET), ctx.caster))
|
||||
return
|
||||
|
||||
val state = ctx.world.getBlockState(pos)
|
||||
|
||||
if (state.block is AbstractCauldronBlock)
|
||||
ctx.world.setBlock(pos, Blocks.LAVA_CAULDRON.defaultBlockState(), 3)
|
||||
else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid(
|
||||
ctx.world,
|
||||
ctx.castingHand,
|
||||
pos,
|
||||
ItemStack(Items.LAVA_BUCKET),
|
||||
Fluids.LAVA
|
||||
)
|
||||
) {
|
||||
// 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, pos, null)
|
||||
} else {
|
||||
HexAPI.LOGGER.warn("Items.LAVA_BUCKET wasn't a BucketItem?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,12 @@ import at.petrak.hexcasting.api.spell.*
|
|||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapImmuneEntity
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway
|
||||
import at.petrak.hexcasting.common.lib.HexEntityTags
|
||||
import at.petrak.hexcasting.common.network.MsgBlinkAck
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object OpTeleport : SpellOperator {
|
||||
|
@ -43,12 +45,8 @@ object OpTeleport : SpellOperator {
|
|||
private data class Spell(val teleportee: Entity, val delta: Vec3) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
val distance = delta.length()
|
||||
|
||||
if (distance < 32768.0) {
|
||||
teleportee.setPos(teleportee.position().add(delta))
|
||||
if (teleportee is ServerPlayer) {
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(teleportee, MsgBlinkAck(delta))
|
||||
}
|
||||
teleportRespectSticky(teleportee, delta)
|
||||
}
|
||||
|
||||
if (teleportee is ServerPlayer && teleportee == ctx.caster) {
|
||||
|
@ -61,6 +59,9 @@ object OpTeleport : SpellOperator {
|
|||
// having to rearrange those. Also it makes sense for LORE REASONS probably, since the caster is more
|
||||
// aware of items they use often.
|
||||
for (armorItem in teleportee.inventory.armor) {
|
||||
if (EnchantmentHelper.hasBindingCurse(armorItem))
|
||||
continue
|
||||
|
||||
if (Math.random() < baseDropChance * 0.25) {
|
||||
teleportee.drop(armorItem.copy(), true, false)
|
||||
armorItem.shrink(armorItem.count)
|
||||
|
@ -79,6 +80,34 @@ object OpTeleport : SpellOperator {
|
|||
// we also don't drop the offhand just to be nice
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun teleportRespectSticky(teleportee: Entity, delta: Vec3) {
|
||||
|
||||
val base = teleportee.rootVehicle
|
||||
|
||||
val playersToUpdate = mutableListOf<ServerPlayer>()
|
||||
|
||||
if (base.indirectPassengers.any { it.type.`is`(HexEntityTags.STICKY_TELEPORTERS) }) {
|
||||
// this handles teleporting the passengers
|
||||
val target = base.position().add(delta)
|
||||
base.teleportTo(target.x, target.y, target.z)
|
||||
base.indirectPassengers
|
||||
.filterIsInstance<ServerPlayer>()
|
||||
.forEach(playersToUpdate::add)
|
||||
} else {
|
||||
// Break it into two stacks
|
||||
teleportee.stopRiding()
|
||||
teleportee.passengers.forEach(Entity::stopRiding)
|
||||
teleportee.setPos(teleportee.position().add(delta))
|
||||
if (teleportee is ServerPlayer) {
|
||||
playersToUpdate.add(teleportee)
|
||||
}
|
||||
}
|
||||
|
||||
for (player in playersToUpdate) {
|
||||
player.connection.resetPosition()
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(player, MsgBlinkAck(delta))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,12 @@ class OpWeather(val rain: Boolean) : SpellOperator {
|
|||
val w = ctx.world
|
||||
if (w.isRaining != rain) {
|
||||
w.levelData.isRaining = rain // i hex the rains down in minecraftia
|
||||
|
||||
if (rain) {
|
||||
w.setWeatherParameters(0, 6000, true, w.random.nextDouble() < 0.05)
|
||||
} else {
|
||||
w.setWeatherParameters(6000, 0, false, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class OpCreateSentinel(val extendsRange: Boolean) : SpellOperator {
|
|||
|
||||
return Triple(
|
||||
Spell(target, this.extendsRange),
|
||||
ManaConstants.DUST_UNIT,
|
||||
ManaConstants.DUST_UNIT * if (extendsRange) 2 else 1,
|
||||
listOf(ParticleSpray.burst(target, 2.0))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.stack
|
||||
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.Operator
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.getChecked
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota
|
||||
|
@ -13,7 +11,6 @@ import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
|||
import at.petrak.hexcasting.api.utils.asTranslatedComponent
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
// "lehmer code"
|
||||
|
@ -58,13 +55,13 @@ object OpAlwinfyHasAscendedToABeingOfPureMath : Operator {
|
|||
editTarget = editTarget.subList(1, editTarget.size)
|
||||
}
|
||||
|
||||
val cost = (ln((strides.lastOrNull() ?: 0).toFloat()) * ManaConstants.DUST_UNIT).toInt()
|
||||
// val cost = (ln((strides.lastOrNull() ?: 0).toFloat()) * ManaConstants.DUST_UNIT).toInt()
|
||||
|
||||
return OperationResult(
|
||||
continuation,
|
||||
stack,
|
||||
local,
|
||||
listOf(OperatorSideEffect.ConsumeMana(cost))
|
||||
listOf() // OperatorSideEffect.ConsumeMana(cost)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,13 @@ package at.petrak.hexcasting.common.casting.operators.stack
|
|||
import at.petrak.hexcasting.api.spell.ConstManaOperator
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.utils.asTranslatedComponent
|
||||
import at.petrak.hexcasting.api.utils.lightPurple
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanList
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class OpMask(val mask: BooleanList) : ConstManaOperator {
|
||||
class OpMask(val mask: BooleanList, val key: ResourceLocation) : ConstManaOperator {
|
||||
override val argc: Int
|
||||
get() = mask.size
|
||||
|
||||
|
@ -17,4 +21,7 @@ class OpMask(val mask: BooleanList) : ConstManaOperator {
|
|||
}
|
||||
return out
|
||||
}
|
||||
|
||||
override val displayName: Component
|
||||
get() = "hexcasting.spell.$key".asTranslatedComponent(mask.map { if (it) '-' else 'v' }.joinToString("")).lightPurple
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package at.petrak.hexcasting.common.items;
|
||||
|
||||
import at.petrak.hexcasting.annotations.SoftImplement;
|
||||
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
|
||||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import at.petrak.hexcasting.common.network.MsgUpdateComparatorVisualsAck;
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
|
@ -14,45 +15,32 @@ import net.minecraft.sounds.SoundEvent;
|
|||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Wearable;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ItemLens extends Item implements Wearable {
|
||||
|
||||
private static final List<Predicate<Player>> HAS_HUD_PREDICATE = new ArrayList<>();
|
||||
static {
|
||||
addLensHUDPredicate(player -> player.getItemBySlot(EquipmentSlot.MAINHAND).is(HexItems.SCRYING_LENS));
|
||||
addLensHUDPredicate(player -> player.getItemBySlot(EquipmentSlot.OFFHAND).is(HexItems.SCRYING_LENS));
|
||||
addLensHUDPredicate(player -> player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS));
|
||||
}
|
||||
DiscoveryHandlers.addLensPredicate(player -> player.getItemBySlot(EquipmentSlot.MAINHAND).is(HexItems.SCRYING_LENS));
|
||||
DiscoveryHandlers.addLensPredicate(player -> player.getItemBySlot(EquipmentSlot.OFFHAND).is(HexItems.SCRYING_LENS));
|
||||
DiscoveryHandlers.addLensPredicate(player -> player.getItemBySlot(EquipmentSlot.HEAD).is(HexItems.SCRYING_LENS));
|
||||
|
||||
public static boolean hasLensHUD(Player player) {
|
||||
for (Predicate<Player> predicate : HAS_HUD_PREDICATE) {
|
||||
if (predicate.test(player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void addLensHUDPredicate(Predicate<Player> predicate) {
|
||||
HAS_HUD_PREDICATE.add(predicate);
|
||||
DiscoveryHandlers.addGridScaleModifier(player -> player.getItemBySlot(EquipmentSlot.MAINHAND).is(HexItems.SCRYING_LENS) ? 0.75f : 1);
|
||||
DiscoveryHandlers.addGridScaleModifier(player -> player.getItemBySlot(EquipmentSlot.OFFHAND).is(HexItems.SCRYING_LENS) ? 0.75f : 1);
|
||||
}
|
||||
|
||||
public ItemLens(Properties pProperties) {
|
||||
|
@ -80,12 +68,13 @@ public class ItemLens extends Item implements Wearable {
|
|||
}
|
||||
|
||||
public static void tickLens(Entity pEntity) {
|
||||
if (!pEntity.getLevel().isClientSide() && pEntity instanceof ServerPlayer player && hasLensHUD(player)) {
|
||||
if (!pEntity.getLevel().isClientSide() && pEntity instanceof ServerPlayer player && DiscoveryHandlers.hasLens(player)) {
|
||||
sendComparatorDataToClient(player);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<ServerPlayer, Pair<BlockPos, Integer>> comparatorDataMap = new WeakHashMap<>();
|
||||
private static final Map<ServerPlayer, Pair<BlockPos, Integer>> beeDataMap = new WeakHashMap<>();
|
||||
|
||||
private static void sendComparatorDataToClient(ServerPlayer player) {
|
||||
double reachAttribute = IXplatAbstractions.INSTANCE.getReachDistance(player);
|
||||
|
@ -94,29 +83,40 @@ public class ItemLens extends Item implements Wearable {
|
|||
if (hitResult.getType() == HitResult.Type.BLOCK) {
|
||||
var pos = ((BlockHitResult) hitResult).getBlockPos();
|
||||
var state = player.level.getBlockState(pos);
|
||||
|
||||
int bee = -1;
|
||||
|
||||
if (state.getBlock() instanceof BeehiveBlock && player.level.getBlockEntity(pos) instanceof BeehiveBlockEntity bees) {
|
||||
bee = bees.getOccupantCount();
|
||||
}
|
||||
|
||||
if (state.is(Blocks.COMPARATOR)) {
|
||||
syncComparatorValue(player, pos,
|
||||
state.getDirectSignal(player.level, pos, state.getValue(BlockStateProperties.HORIZONTAL_FACING)));
|
||||
state.getDirectSignal(player.level, pos, state.getValue(BlockStateProperties.HORIZONTAL_FACING)), bee);
|
||||
} else if (state.hasAnalogOutputSignal()) {
|
||||
syncComparatorValue(player, pos, state.getAnalogOutputSignal(player.level, pos));
|
||||
syncComparatorValue(player, pos, state.getAnalogOutputSignal(player.level, pos), bee);
|
||||
} else {
|
||||
syncComparatorValue(player, null, -1);
|
||||
syncComparatorValue(player, null, -1, bee);
|
||||
}
|
||||
} else {
|
||||
syncComparatorValue(player, null, -1);
|
||||
syncComparatorValue(player, null, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void syncComparatorValue(ServerPlayer player, BlockPos pos, int value) {
|
||||
var previous = comparatorDataMap.get(player);
|
||||
if (value == -1) {
|
||||
if (previous != null) {
|
||||
private static void syncComparatorValue(ServerPlayer player, BlockPos pos, int comparator, int bee) {
|
||||
var previousComparator = comparatorDataMap.get(player);
|
||||
var previousBee = beeDataMap.get(player);
|
||||
if (comparator == -1 && bee == -1) {
|
||||
if (previousComparator != null || previousBee != null) {
|
||||
comparatorDataMap.remove(player);
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(player, new MsgUpdateComparatorVisualsAck(null, -1));
|
||||
beeDataMap.remove(player);
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(player, new MsgUpdateComparatorVisualsAck(null, -1, -1));
|
||||
}
|
||||
} else if (previous == null || (!pos.equals(previous.getFirst()) || value != previous.getSecond())) {
|
||||
comparatorDataMap.put(player, new Pair<>(pos, value));
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(player, new MsgUpdateComparatorVisualsAck(pos, value));
|
||||
} else if (previousComparator == null || !pos.equals(previousComparator.getFirst()) || comparator != previousComparator.getSecond() ||
|
||||
previousBee == null || !pos.equals(previousBee.getFirst()) || bee != previousBee.getSecond()) {
|
||||
comparatorDataMap.put(player, new Pair<>(pos, comparator));
|
||||
beeDataMap.put(player, new Pair<>(pos, bee));
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(player, new MsgUpdateComparatorVisualsAck(pos, comparator, bee));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package at.petrak.hexcasting.common.items.magic;
|
||||
|
||||
import at.petrak.hexcasting.api.addldata.ManaHolder;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public record DebugUnlockerHolder(ItemStack creativeUnlocker) implements ManaHolder {
|
||||
@Override
|
||||
public int getMana() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxMana() {
|
||||
return Integer.MAX_VALUE - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMana(int mana) {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRecharge() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProvide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConsumptionPriority() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConstructBattery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int withdrawMana(int cost, boolean simulate) {
|
||||
ItemCreativeUnlocker.addToIntArray(creativeUnlocker, ItemCreativeUnlocker.TAG_EXTRACTIONS, cost);
|
||||
|
||||
return cost < 0 ? getMana() : cost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertMana(int amount, boolean simulate) {
|
||||
ItemCreativeUnlocker.addToIntArray(creativeUnlocker, ItemCreativeUnlocker.TAG_INSERTIONS, amount);
|
||||
|
||||
return amount;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
package at.petrak.hexcasting.common.items.magic;
|
||||
|
||||
import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus;
|
||||
import at.petrak.hexcasting.api.item.ManaHolderItem;
|
||||
import at.petrak.hexcasting.api.misc.DiscoveryHandlers;
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants;
|
||||
import at.petrak.hexcasting.api.utils.NBTHelper;
|
||||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import at.petrak.hexcasting.common.lib.HexSounds;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
|
@ -11,13 +14,17 @@ import net.minecraft.locale.Language;
|
|||
import net.minecraft.network.chat.*;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -29,6 +36,36 @@ import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
|||
|
||||
public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
|
||||
|
||||
static {
|
||||
DiscoveryHandlers.addManaHolderDiscoverer(harness -> {
|
||||
var player = harness.getCtx().getCaster();
|
||||
if (!player.isCreative())
|
||||
return List.of();
|
||||
|
||||
for (ItemStack item : player.getInventory().items) {
|
||||
if (isDebug(item)) {
|
||||
return List.of(new DebugUnlockerHolder(item));
|
||||
}
|
||||
}
|
||||
|
||||
// Technically possible with commands!
|
||||
for (ItemStack item : player.getInventory().armor) {
|
||||
if (isDebug(item)) {
|
||||
return List.of(new DebugUnlockerHolder(item));
|
||||
}
|
||||
}
|
||||
|
||||
for (ItemStack item : player.getInventory().offhand) {
|
||||
if (isDebug(item)) {
|
||||
return List.of(new DebugUnlockerHolder(item));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return List.of();
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isDebug(ItemStack stack) {
|
||||
return stack.is(HexItems.CREATIVE_UNLOCKER)
|
||||
&& stack.hasCustomHoverName()
|
||||
|
@ -47,7 +84,8 @@ public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
|
|||
return emphasized;
|
||||
}
|
||||
|
||||
private static final String TAG_EXTRACTIONS = "extractions";
|
||||
public static final String TAG_EXTRACTIONS = "extractions";
|
||||
public static final String TAG_INSERTIONS = "insertions";
|
||||
|
||||
public ItemCreativeUnlocker(Properties properties) {
|
||||
super(properties);
|
||||
|
@ -75,22 +113,37 @@ public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
|
|||
|
||||
@Override
|
||||
public boolean canRecharge(ItemStack stack) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void addToIntArray(ItemStack stack, String tag, int n) {
|
||||
int[] arr = NBTHelper.getIntArray(stack, tag);
|
||||
if (arr == null) {
|
||||
arr = new int[0];
|
||||
}
|
||||
int[] newArr = Arrays.copyOf(arr, arr.length + 1);
|
||||
newArr[newArr.length - 1] = n;
|
||||
NBTHelper.putIntArray(stack, tag, newArr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int withdrawMana(ItemStack stack, int cost, boolean simulate) {
|
||||
// In case it's withdrawn through other means
|
||||
if (!simulate && isDebug(stack)) {
|
||||
int[] arr = NBTHelper.getIntArray(stack, TAG_EXTRACTIONS);
|
||||
if (arr == null) {
|
||||
arr = new int[0];
|
||||
}
|
||||
int[] newArr = Arrays.copyOf(arr, arr.length + 1);
|
||||
newArr[newArr.length - 1] = cost;
|
||||
NBTHelper.putIntArray(stack, TAG_EXTRACTIONS, newArr);
|
||||
addToIntArray(stack, TAG_EXTRACTIONS, cost);
|
||||
}
|
||||
|
||||
return cost < 0 ? 1 : cost;
|
||||
return cost < 0 ? getMana(stack) : cost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertMana(ItemStack stack, int amount, boolean simulate) {
|
||||
// In case it's inserted through other means
|
||||
if (!simulate && isDebug(stack)) {
|
||||
addToIntArray(stack, TAG_INSERTIONS, amount);
|
||||
}
|
||||
|
||||
return amount < 0 ? getMaxMana(stack) : amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,28 +154,44 @@ public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
|
|||
@Override
|
||||
public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, boolean selected) {
|
||||
if (isDebug(stack) && !level.isClientSide) {
|
||||
int[] arr = NBTHelper.getIntArray(stack, TAG_EXTRACTIONS);
|
||||
if (arr != null) {
|
||||
NBTHelper.remove(stack, TAG_EXTRACTIONS);
|
||||
for (int i : arr) {
|
||||
if (i < 0) {
|
||||
entity.sendMessage(new TranslatableComponent("hexcasting.debug.mana_withdrawn",
|
||||
stack.getDisplayName(),
|
||||
new TranslatableComponent("hexcasting.debug.all_mana").withStyle(ChatFormatting.GRAY))
|
||||
.withStyle(ChatFormatting.LIGHT_PURPLE), Util.NIL_UUID);
|
||||
} else {
|
||||
entity.sendMessage(new TranslatableComponent("hexcasting.debug.mana_withdrawn.with_dust",
|
||||
stack.getDisplayName(),
|
||||
new TextComponent("" + i).withStyle(ChatFormatting.WHITE),
|
||||
new TextComponent(String.format("%.2f", i * 1.0 / ManaConstants.DUST_UNIT)).withStyle(
|
||||
ChatFormatting.WHITE))
|
||||
.withStyle(ChatFormatting.LIGHT_PURPLE), Util.NIL_UUID);
|
||||
}
|
||||
debugDisplay(stack, TAG_EXTRACTIONS, "withdrawn", "all_mana", entity);
|
||||
debugDisplay(stack, TAG_INSERTIONS, "inserted", "infinite_mana", entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void debugDisplay(ItemStack stack, String tag, String langKey, String allKey, Entity entity) {
|
||||
int[] arr = NBTHelper.getIntArray(stack, tag);
|
||||
if (arr != null) {
|
||||
NBTHelper.remove(stack, tag);
|
||||
for (int i : arr) {
|
||||
if (i < 0) {
|
||||
entity.sendMessage(new TranslatableComponent("hexcasting.debug.mana_" + langKey,
|
||||
stack.getDisplayName(),
|
||||
new TranslatableComponent("hexcasting.debug." + allKey).withStyle(ChatFormatting.GRAY))
|
||||
.withStyle(ChatFormatting.LIGHT_PURPLE), Util.NIL_UUID);
|
||||
} else {
|
||||
entity.sendMessage(new TranslatableComponent("hexcasting.debug.mana_" + langKey + ".with_dust",
|
||||
stack.getDisplayName(),
|
||||
new TextComponent("" + i).withStyle(ChatFormatting.WHITE),
|
||||
new TextComponent(String.format("%.2f", i * 1.0 / ManaConstants.DUST_UNIT)).withStyle(
|
||||
ChatFormatting.WHITE))
|
||||
.withStyle(ChatFormatting.LIGHT_PURPLE), Util.NIL_UUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
BlockEntity be = context.getLevel().getBlockEntity(context.getClickedPos());
|
||||
if (be instanceof BlockEntityAbstractImpetus impetus) {
|
||||
impetus.setInfiniteMana();
|
||||
context.getLevel().playSound(null, context.getClickedPos(), HexSounds.SPELL_CIRCLE_FIND_BLOCK, SoundSource.PLAYERS, 1f, 1f);
|
||||
return InteractionResult.sidedSuccess(context.getLevel().isClientSide());
|
||||
}
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity consumer) {
|
||||
if (level instanceof ServerLevel slevel && consumer instanceof ServerPlayer player) {
|
||||
|
@ -150,8 +219,6 @@ public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
|
|||
return copy;
|
||||
}
|
||||
|
||||
private static final TextColor HEX_COLOR = TextColor.fromRgb(0xb38ef3);
|
||||
|
||||
private static MutableComponent rainbow(MutableComponent component, int shift, Level level) {
|
||||
if (level == null) {
|
||||
return component.withStyle(ChatFormatting.WHITE);
|
||||
|
@ -164,16 +231,14 @@ public class ItemCreativeUnlocker extends Item implements ManaHolderItem {
|
|||
@Override
|
||||
public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltipComponents,
|
||||
TooltipFlag isAdvanced) {
|
||||
String prefix = "item.hexcasting.creative_unlocker.";
|
||||
|
||||
Component emphasized = infiniteMedia(level);
|
||||
|
||||
MutableComponent modName = new TranslatableComponent(prefix + "mod_name").withStyle(
|
||||
(s) -> s.withColor(HEX_COLOR));
|
||||
MutableComponent modName = new TranslatableComponent("item.hexcasting.creative_unlocker.mod_name").withStyle(
|
||||
(s) -> s.withColor(ItemManaHolder.HEX_COLOR));
|
||||
|
||||
tooltipComponents.add(
|
||||
new TranslatableComponent(prefix + "tooltip.0", emphasized).withStyle(ChatFormatting.GRAY));
|
||||
tooltipComponents.add(new TranslatableComponent(prefix + "tooltip.1", modName).withStyle(ChatFormatting.GRAY));
|
||||
new TranslatableComponent("hexcasting.spelldata.onitem", emphasized).withStyle(ChatFormatting.GRAY));
|
||||
tooltipComponents.add(new TranslatableComponent("item.hexcasting.creative_unlocker.tooltip", modName).withStyle(ChatFormatting.GRAY));
|
||||
}
|
||||
|
||||
private static void addChildren(Advancement root, List<Advancement> out) {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package at.petrak.hexcasting.common.items.magic;
|
||||
|
||||
import at.petrak.hexcasting.api.item.ManaHolderItem;
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants;
|
||||
import at.petrak.hexcasting.api.utils.ManaHelper;
|
||||
import at.petrak.hexcasting.api.utils.NBTHelper;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TextColor;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
@ -13,12 +15,24 @@ import net.minecraft.world.item.TooltipFlag;
|
|||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ItemManaHolder extends Item implements ManaHolderItem {
|
||||
public static final String TAG_MANA = "hexcasting:mana";
|
||||
public static final String TAG_MAX_MANA = "hexcasting:start_mana";
|
||||
|
||||
public static final TextColor HEX_COLOR = TextColor.fromRgb(0xb38ef3);
|
||||
|
||||
private static final DecimalFormat PERCENTAGE = new DecimalFormat("####");
|
||||
|
||||
static {
|
||||
PERCENTAGE.setRoundingMode(RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
private static final DecimalFormat DUST_AMOUNT = new DecimalFormat("###,###.##");
|
||||
|
||||
public ItemManaHolder(Properties pProperties) {
|
||||
super(pProperties);
|
||||
}
|
||||
|
@ -75,12 +89,24 @@ public abstract class ItemManaHolder extends Item implements ManaHolderItem {
|
|||
@Override
|
||||
public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List<Component> pTooltipComponents,
|
||||
TooltipFlag pIsAdvanced) {
|
||||
if (pIsAdvanced.isAdvanced() && getMaxMana(pStack) > 0) {
|
||||
var maxMana = getMaxMana(pStack);
|
||||
if (maxMana > 0) {
|
||||
var mana = getMana(pStack);
|
||||
var fullness = getManaFullness(pStack);
|
||||
|
||||
var color = TextColor.fromRgb(ManaHelper.manaBarColor(mana, maxMana));
|
||||
|
||||
var manaAmount = new TextComponent(DUST_AMOUNT.format(mana / (float) ManaConstants.DUST_UNIT));
|
||||
var percentFull = new TextComponent(PERCENTAGE.format(100f * fullness) + "%");
|
||||
var maxCapacity = new TranslatableComponent("hexcasting.tooltip.mana", DUST_AMOUNT.format(maxMana / (float) ManaConstants.DUST_UNIT));
|
||||
|
||||
manaAmount.withStyle(style -> style.withColor(HEX_COLOR));
|
||||
maxCapacity.withStyle(style -> style.withColor(HEX_COLOR));
|
||||
percentFull.withStyle(style -> style.withColor(color));
|
||||
|
||||
pTooltipComponents.add(
|
||||
new TranslatableComponent("item.hexcasting.manaholder.amount",
|
||||
String.format("%,d", getMana(pStack)),
|
||||
String.format("%,d", getMaxMana(pStack)),
|
||||
100f * getManaFullness(pStack)).withStyle(ChatFormatting.GRAY));
|
||||
new TranslatableComponent("hexcasting.tooltip.mana_amount.advanced",
|
||||
manaAmount, maxCapacity, percentFull));
|
||||
}
|
||||
|
||||
super.appendHoverText(pStack, pLevel, pTooltipComponents, pIsAdvanced);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package at.petrak.hexcasting.common.lib;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
|
||||
public class HexEntityTags {
|
||||
public static final TagKey<EntityType<?>> STICKY_TELEPORTERS = create("sticky_teleporters");
|
||||
|
||||
public static TagKey<EntityType<?>> create(String name) {
|
||||
return TagKey.create(Registry.ENTITY_TYPE_REGISTRY, modLoc(name));
|
||||
}
|
||||
}
|
|
@ -65,7 +65,7 @@ public class HexItems {
|
|||
public static final ItemSlate SLATE = make("slate", new ItemSlate(HexBlocks.SLATE, props()));
|
||||
|
||||
public static final ItemManaBattery BATTERY = make("battery",
|
||||
new ItemManaBattery(new Item.Properties().stacksTo(1)));
|
||||
new ItemManaBattery(unstackable()));
|
||||
|
||||
public static final EnumMap<DyeColor, ItemDyeColorizer> DYE_COLORIZERS = Util.make(() -> {
|
||||
var out = new EnumMap<DyeColor, ItemDyeColorizer>(DyeColor.class);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package at.petrak.hexcasting.common.network;
|
||||
|
||||
import at.petrak.hexcasting.api.utils.HexUtils;
|
||||
import at.petrak.hexcasting.common.entities.EntityWallScroll;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -34,7 +35,7 @@ public record MsgNewWallScrollAck(ClientboundAddEntityPacket inner, BlockPos pos
|
|||
public static MsgNewWallScrollAck deserialize(FriendlyByteBuf buf) {
|
||||
var inner = new ClientboundAddEntityPacket(buf);
|
||||
var pos = buf.readBlockPos();
|
||||
var dir = Direction.values()[buf.readByte()];
|
||||
var dir = HexUtils.getSafe(Direction.values(), buf.readByte());
|
||||
var scroll = buf.readItem();
|
||||
var strokeOrder = buf.readBoolean();
|
||||
var blockSize = buf.readVarInt();
|
||||
|
|
|
@ -12,7 +12,7 @@ import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
|||
/**
|
||||
* Sent server->client when a player is looking at a block through a lens whose comparator value is not the same as what they last saw.
|
||||
*/
|
||||
public record MsgUpdateComparatorVisualsAck(BlockPos pos, int value) implements IMessage {
|
||||
public record MsgUpdateComparatorVisualsAck(BlockPos pos, int comparator, int bee) implements IMessage {
|
||||
public static final ResourceLocation ID = modLoc("cmp");
|
||||
|
||||
@Override
|
||||
|
@ -23,15 +23,17 @@ public record MsgUpdateComparatorVisualsAck(BlockPos pos, int value) implements
|
|||
public static MsgUpdateComparatorVisualsAck deserialize(ByteBuf buffer) {
|
||||
var buf = new FriendlyByteBuf(buffer);
|
||||
|
||||
int value = buf.readInt();
|
||||
BlockPos pos = value == -1 ? null : buf.readBlockPos();
|
||||
int comparator = buf.readInt();
|
||||
int bee = buf.readInt();
|
||||
BlockPos pos = comparator == -1 && bee == -1 ? null : buf.readBlockPos();
|
||||
|
||||
return new MsgUpdateComparatorVisualsAck(pos, value);
|
||||
return new MsgUpdateComparatorVisualsAck(pos, comparator, bee);
|
||||
}
|
||||
|
||||
public void serialize(FriendlyByteBuf buf) {
|
||||
buf.writeInt(this.value);
|
||||
if (this.value != -1) {
|
||||
buf.writeInt(this.comparator);
|
||||
buf.writeInt(this.bee);
|
||||
if (this.comparator != -1 || this.bee != -1) {
|
||||
buf.writeBlockPos(this.pos);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +42,7 @@ public record MsgUpdateComparatorVisualsAck(BlockPos pos, int value) implements
|
|||
Minecraft.getInstance().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ScryingLensOverlayRegistry.receiveComparatorValue(msg.pos(), msg.value());
|
||||
ScryingLensOverlayRegistry.receiveComparatorAndBeeValue(msg.pos(), msg.comparator(), msg.bee());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.advancements.FailToCastGreatSpellTrigger;
|
|||
import at.petrak.hexcasting.api.advancements.OvercastTrigger;
|
||||
import at.petrak.hexcasting.api.advancements.SpendManaTrigger;
|
||||
import at.petrak.hexcasting.api.misc.ManaConstants;
|
||||
import at.petrak.hexcasting.api.mod.HexItemTags;
|
||||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import at.petrak.paucal.api.datagen.PaucalAdvancementProvider;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
|
@ -12,6 +13,7 @@ import net.minecraft.advancements.DisplayInfo;
|
|||
import net.minecraft.advancements.FrameType;
|
||||
import net.minecraft.advancements.critereon.EntityPredicate;
|
||||
import net.minecraft.advancements.critereon.InventoryChangeTrigger;
|
||||
import net.minecraft.advancements.critereon.ItemPredicate;
|
||||
import net.minecraft.advancements.critereon.MinMaxBounds;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
|
@ -37,8 +39,8 @@ public class HexAdvancements extends PaucalAdvancementProvider {
|
|||
new ResourceLocation("minecraft", "textures/block/calcite.png"),
|
||||
FrameType.TASK, true, true, true))
|
||||
// the only thing making this vaguely tolerable is the knowledge the json files are worse somehow
|
||||
.addCriterion("has_charged_amethyst",
|
||||
InventoryChangeTrigger.TriggerInstance.hasItems(HexItems.CHARGED_AMETHYST))
|
||||
.addCriterion("has_charged_amethyst", InventoryChangeTrigger.TriggerInstance.hasItems(
|
||||
ItemPredicate.Builder.item().of(HexItemTags.GRANTS_ROOT_ADVANCEMENT).build()))
|
||||
.save(consumer, prefix("root")); // how the hell does one even read this
|
||||
|
||||
// weird names so we have alphabetical parity
|
||||
|
|
|
@ -26,10 +26,12 @@ public class HexItemTagProvider extends PaucalItemTagProvider {
|
|||
tag(xtags.amethystDust()).add(HexItems.AMETHYST_DUST);
|
||||
|
||||
tag(HexItemTags.WANDS).add(HexItems.WAND_AKASHIC,
|
||||
HexItems.WAND_OAK, HexItems.WAND_SPRUCE, HexItems.WAND_BIRCH,
|
||||
HexItems.WAND_JUNGLE, HexItems.WAND_ACACIA, HexItems.WAND_DARK_OAK,
|
||||
HexItems.WAND_CRIMSON, HexItems.WAND_WARPED);
|
||||
HexItems.WAND_OAK, HexItems.WAND_SPRUCE, HexItems.WAND_BIRCH,
|
||||
HexItems.WAND_JUNGLE, HexItems.WAND_ACACIA, HexItems.WAND_DARK_OAK,
|
||||
HexItems.WAND_CRIMSON, HexItems.WAND_WARPED);
|
||||
tag(HexItemTags.PHIAL_BASE).add(Items.GLASS_BOTTLE);
|
||||
tag(HexItemTags.GRANTS_ROOT_ADVANCEMENT).add(HexItems.AMETHYST_DUST, Items.AMETHYST_SHARD,
|
||||
HexItems.CHARGED_AMETHYST);
|
||||
|
||||
this.copy(HexBlockTags.AKASHIC_LOGS, HexItemTags.AKASHIC_LOGS);
|
||||
this.copy(HexBlockTags.AKASHIC_PLANKS, HexItemTags.AKASHIC_PLANKS);
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package at.petrak.hexcasting.datagen;
|
||||
|
||||
import net.minecraft.data.recipes.RecipeBuilder;
|
||||
|
||||
public interface IXplatConditionsBuilder extends RecipeBuilder {
|
||||
IXplatConditionsBuilder whenModLoaded(String modid);
|
||||
|
||||
IXplatConditionsBuilder whenModMissing(String modid);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package at.petrak.hexcasting.datagen;
|
||||
|
||||
import at.petrak.hexcasting.datagen.recipe.builders.ToolIngredient;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
|
||||
|
@ -23,4 +24,10 @@ public interface IXplatIngredients {
|
|||
EnumMap<DyeColor, Ingredient> dyes();
|
||||
|
||||
Ingredient stick();
|
||||
|
||||
Ingredient whenModIngredient(Ingredient defaultIngredient, String modid, Ingredient modIngredient);
|
||||
|
||||
ToolIngredient axeStrip();
|
||||
|
||||
ToolIngredient axeDig();
|
||||
}
|
||||
|
|
|
@ -1,69 +1,66 @@
|
|||
package at.petrak.hexcasting.datagen.recipe;
|
||||
package at.petrak.hexcasting.datagen.recipe
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI;
|
||||
import at.petrak.hexcasting.api.advancements.OvercastTrigger;
|
||||
import at.petrak.hexcasting.api.mod.HexItemTags;
|
||||
import at.petrak.hexcasting.common.items.ItemWand;
|
||||
import at.petrak.hexcasting.common.items.colorizer.ItemPrideColorizer;
|
||||
import at.petrak.hexcasting.common.lib.HexBlocks;
|
||||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import at.petrak.hexcasting.common.recipe.SealFocusRecipe;
|
||||
import at.petrak.hexcasting.common.recipe.SealSpellbookRecipe;
|
||||
import at.petrak.hexcasting.common.recipe.ingredient.StateIngredientHelper;
|
||||
import at.petrak.hexcasting.common.recipe.ingredient.VillagerIngredient;
|
||||
import at.petrak.hexcasting.datagen.IXplatIngredients;
|
||||
import at.petrak.hexcasting.datagen.recipe.builders.BrainsweepRecipeBuilder;
|
||||
import at.petrak.hexcasting.datagen.recipe.builders.CreateCrushingRecipeBuilder;
|
||||
import at.petrak.paucal.api.datagen.PaucalRecipeProvider;
|
||||
import net.minecraft.advancements.critereon.EntityPredicate;
|
||||
import net.minecraft.advancements.critereon.MinMaxBounds;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.recipes.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
import net.minecraft.world.item.DyeItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.item.crafting.SimpleRecipeSerializer;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.advancements.OvercastTrigger
|
||||
import at.petrak.hexcasting.api.mod.HexItemTags
|
||||
import at.petrak.hexcasting.common.items.ItemWand
|
||||
import at.petrak.hexcasting.common.items.colorizer.ItemPrideColorizer
|
||||
import at.petrak.hexcasting.common.lib.HexBlocks
|
||||
import at.petrak.hexcasting.common.lib.HexItems
|
||||
import at.petrak.hexcasting.common.recipe.SealFocusRecipe
|
||||
import at.petrak.hexcasting.common.recipe.SealSpellbookRecipe
|
||||
import at.petrak.hexcasting.common.recipe.ingredient.StateIngredientHelper
|
||||
import at.petrak.hexcasting.common.recipe.ingredient.VillagerIngredient
|
||||
import at.petrak.hexcasting.datagen.IXplatConditionsBuilder
|
||||
import at.petrak.hexcasting.datagen.IXplatIngredients
|
||||
import at.petrak.hexcasting.datagen.recipe.builders.BrainsweepRecipeBuilder
|
||||
import at.petrak.hexcasting.datagen.recipe.builders.CompatIngredientValue
|
||||
import at.petrak.hexcasting.datagen.recipe.builders.CreateCrushingRecipeBuilder
|
||||
import at.petrak.hexcasting.datagen.recipe.builders.FarmersDelightCuttingRecipeBuilder
|
||||
import at.petrak.paucal.api.datagen.PaucalRecipeProvider
|
||||
import net.minecraft.advancements.critereon.EntityPredicate
|
||||
import net.minecraft.advancements.critereon.MinMaxBounds
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.data.DataGenerator
|
||||
import net.minecraft.data.recipes.*
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.tags.ItemTags
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.item.DyeItem
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.crafting.Ingredient
|
||||
import net.minecraft.world.item.crafting.SimpleRecipeSerializer
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import java.util.function.Consumer
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
class HexplatRecipes(
|
||||
val generator: DataGenerator,
|
||||
val ingredients: IXplatIngredients,
|
||||
val conditions: (RecipeBuilder) -> IXplatConditionsBuilder
|
||||
) : PaucalRecipeProvider(generator, HexAPI.MOD_ID) {
|
||||
|
||||
override fun makeRecipes(recipes: Consumer<FinishedRecipe>) {
|
||||
specialRecipe(recipes, SealFocusRecipe.SERIALIZER)
|
||||
specialRecipe(recipes, SealSpellbookRecipe.SERIALIZER)
|
||||
|
||||
public class HexplatRecipes extends PaucalRecipeProvider {
|
||||
public DataGenerator generator;
|
||||
public IXplatIngredients ingredients;
|
||||
public Supplier<CreateCrushingRecipeBuilder> createCrushing;
|
||||
wandRecipe(recipes, HexItems.WAND_OAK, Items.OAK_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_BIRCH, Items.BIRCH_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_SPRUCE, Items.SPRUCE_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_JUNGLE, Items.JUNGLE_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_DARK_OAK, Items.DARK_OAK_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_ACACIA, Items.ACACIA_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_CRIMSON, Items.CRIMSON_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_WARPED, Items.WARPED_PLANKS)
|
||||
wandRecipe(recipes, HexItems.WAND_AKASHIC, HexBlocks.AKASHIC_PLANKS.asItem())
|
||||
|
||||
public HexplatRecipes(DataGenerator pGenerator, IXplatIngredients ingredients, Supplier<CreateCrushingRecipeBuilder> createCrushing) {
|
||||
super(pGenerator, HexAPI.MOD_ID);
|
||||
this.generator = pGenerator;
|
||||
this.ingredients = ingredients;
|
||||
this.createCrushing = createCrushing;
|
||||
}
|
||||
|
||||
protected void makeRecipes(Consumer<FinishedRecipe> recipes) {
|
||||
specialRecipe(recipes, SealFocusRecipe.SERIALIZER);
|
||||
specialRecipe(recipes, SealSpellbookRecipe.SERIALIZER);
|
||||
|
||||
wandRecipe(recipes, HexItems.WAND_OAK, Items.OAK_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_BIRCH, Items.BIRCH_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_SPRUCE, Items.SPRUCE_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_JUNGLE, Items.JUNGLE_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_DARK_OAK, Items.DARK_OAK_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_ACACIA, Items.ACACIA_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_CRIMSON, Items.CRIMSON_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_WARPED, Items.WARPED_PLANKS);
|
||||
wandRecipe(recipes, HexItems.WAND_AKASHIC, HexBlocks.AKASHIC_PLANKS.asItem());
|
||||
|
||||
ringCornered(HexItems.FOCUS, 1, ingredients.glowstoneDust(),
|
||||
ingredients.leather(), Ingredient.of(HexItems.CHARGED_AMETHYST))
|
||||
ringCornered(HexItems.FOCUS, 1,
|
||||
ingredients.glowstoneDust(),
|
||||
ingredients.leather(),
|
||||
Ingredient.of(HexItems.CHARGED_AMETHYST))
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS))
|
||||
.save(recipes);
|
||||
.save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.SPELLBOOK)
|
||||
.define('N', ingredients.goldNugget())
|
||||
|
@ -75,17 +72,19 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern("NFA")
|
||||
.pattern("NBA")
|
||||
.unlockedBy("has_focus", hasItem(HexItems.FOCUS))
|
||||
.unlockedBy("has_chorus", hasItem(Items.CHORUS_FRUIT)).save(recipes);
|
||||
.unlockedBy("has_chorus", hasItem(Items.CHORUS_FRUIT)).save(recipes)
|
||||
|
||||
ringCornerless(HexItems.CYPHER, 1,
|
||||
ringCornerless(
|
||||
HexItems.CYPHER, 1,
|
||||
ingredients.copperIngot(),
|
||||
Ingredient.of(HexItems.AMETHYST_DUST))
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes)
|
||||
|
||||
ringCornerless(HexItems.TRINKET, 1,
|
||||
ringCornerless(
|
||||
HexItems.TRINKET, 1,
|
||||
ingredients.ironIngot(),
|
||||
Ingredient.of(Items.AMETHYST_SHARD))
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.ARTIFACT)
|
||||
.define('F', ingredients.goldIngot())
|
||||
|
@ -95,10 +94,10 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern(" F ")
|
||||
.pattern("FAF")
|
||||
.pattern(" D ")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes)
|
||||
|
||||
ringCornerless(HexItems.SCRYING_LENS, 1, Items.GLASS, HexItems.AMETHYST_DUST)
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.ABACUS)
|
||||
.define('S', Items.STICK)
|
||||
|
@ -107,7 +106,7 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern("WAW")
|
||||
.pattern("SAS")
|
||||
.pattern("WAW")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.WANDS)).save(recipes)
|
||||
|
||||
// Why am I like this
|
||||
ShapedRecipeBuilder.shaped(HexItems.SUBMARINE_SANDWICH)
|
||||
|
@ -118,35 +117,39 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern(" SA")
|
||||
.pattern(" C ")
|
||||
.pattern(" B ")
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes)
|
||||
|
||||
for (var dye : DyeColor.values()) {
|
||||
var item = HexItems.DYE_COLORIZERS.get(dye);
|
||||
for (dye in DyeColor.values()) {
|
||||
val item = HexItems.DYE_COLORIZERS[dye]!!
|
||||
ShapedRecipeBuilder.shaped(item)
|
||||
.define('D', HexItems.AMETHYST_DUST)
|
||||
.define('C', DyeItem.byColor(dye))
|
||||
.pattern(" D ")
|
||||
.pattern("DCD")
|
||||
.pattern(" D ")
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes)
|
||||
}
|
||||
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.AGENDER, Items.GLASS);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.AROACE, Items.WHEAT_SEEDS);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.AROMANTIC, Items.ARROW);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.ASEXUAL, Items.BREAD);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.BISEXUAL, Items.WHEAT);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.DEMIBOY, Items.RAW_IRON);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.DEMIGIRL, Items.RAW_COPPER);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.GAY, Items.STONE_BRICK_WALL);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.GENDERFLUID, Items.WATER_BUCKET);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.GENDERQUEER, Items.GLASS_BOTTLE);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.INTERSEX, Items.AZALEA);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.LESBIAN, Items.HONEYCOMB);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.NONBINARY, Items.MOSS_BLOCK);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.PANSEXUAL, Items.CARROT);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.PLURAL, Items.REPEATER);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.TRANSGENDER, Items.EGG);
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.AGENDER, Ingredient.of(Items.GLASS))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.AROACE, Ingredient.of(Items.WHEAT_SEEDS))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.AROMANTIC, Ingredient.of(Items.ARROW))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.ASEXUAL, Ingredient.of(Items.BREAD))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.BISEXUAL, Ingredient.of(Items.WHEAT))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.DEMIBOY, Ingredient.of(Items.RAW_IRON))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.DEMIGIRL, Ingredient.of(Items.RAW_COPPER))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.GAY, Ingredient.of(Items.STONE_BRICK_WALL))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.GENDERFLUID, Ingredient.of(Items.WATER_BUCKET))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.GENDERQUEER, Ingredient.of(Items.GLASS_BOTTLE))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.INTERSEX, Ingredient.of(Items.AZALEA))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.LESBIAN, Ingredient.of(Items.HONEYCOMB))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.NONBINARY, Ingredient.of(Items.MOSS_BLOCK))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.PANSEXUAL, ingredients.whenModIngredient(
|
||||
Ingredient.of(Items.CARROT),
|
||||
"farmersdelight",
|
||||
CompatIngredientValue.of("farmersdelight:skillet")
|
||||
))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.PLURAL, Ingredient.of(Items.REPEATER))
|
||||
gayRecipe(recipes, ItemPrideColorizer.Type.TRANSGENDER, Ingredient.of(Items.EGG))
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.UUID_COLORIZER)
|
||||
.define('B', Items.BOWL)
|
||||
|
@ -155,35 +158,37 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern(" C ")
|
||||
.pattern(" D ")
|
||||
.pattern(" B ")
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.SCROLL_SMOL)
|
||||
.define('P', Items.PAPER)
|
||||
.define('A', Items.AMETHYST_SHARD)
|
||||
.pattern(" A")
|
||||
.pattern("P ")
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.SCROLL_MEDIUM)
|
||||
.define('P', Items.PAPER)
|
||||
.define('A', Items.AMETHYST_SHARD)
|
||||
.pattern(" A")
|
||||
.pattern("PP ")
|
||||
.pattern("PP ")
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.SCROLL_LARGE)
|
||||
.define('P', Items.PAPER)
|
||||
.define('A', Items.AMETHYST_SHARD)
|
||||
.pattern("PPA")
|
||||
.pattern("PPP")
|
||||
.pattern("PPP")
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.SLATE, 6)
|
||||
.define('S', Items.DEEPSLATE)
|
||||
.define('A', HexItems.AMETHYST_DUST)
|
||||
.pattern(" A ")
|
||||
.pattern("SSS")
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexItems.JEWELER_HAMMER)
|
||||
.define('I', ingredients.ironIngot())
|
||||
|
@ -193,103 +198,120 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern("IAN")
|
||||
.pattern(" S ")
|
||||
.pattern(" S ")
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.SLATE_BLOCK)
|
||||
.define('S', HexItems.SLATE)
|
||||
.pattern("S")
|
||||
.pattern("S")
|
||||
.unlockedBy("has_item", hasItem(HexItems.SLATE))
|
||||
.save(recipes, modLoc("slate_block_from_slates"));
|
||||
.save(recipes, modLoc("slate_block_from_slates"))
|
||||
|
||||
ringAll(HexBlocks.SLATE_BLOCK, 8, Blocks.DEEPSLATE, HexItems.AMETHYST_DUST)
|
||||
.unlockedBy("has_item", hasItem(HexItems.SLATE)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItems.SLATE)).save(recipes)
|
||||
|
||||
packing(HexItems.AMETHYST_DUST, HexBlocks.AMETHYST_DUST_BLOCK.asItem(), "amethyst_dust",
|
||||
false, recipes);
|
||||
false, recipes)
|
||||
|
||||
ringAll(HexBlocks.AMETHYST_TILES, 8, Blocks.AMETHYST_BLOCK, HexItems.AMETHYST_DUST)
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes)
|
||||
|
||||
SingleItemRecipeBuilder.stonecutting(Ingredient.of(Blocks.AMETHYST_BLOCK), HexBlocks.AMETHYST_TILES)
|
||||
.unlockedBy("has_item", hasItem(Blocks.AMETHYST_BLOCK))
|
||||
.save(recipes, modLoc("stonecutting/amethyst_tiles"));
|
||||
.save(recipes, modLoc("stonecutting/amethyst_tiles"))
|
||||
|
||||
ringAll(HexBlocks.SCROLL_PAPER, 8, Items.PAPER, Items.AMETHYST_SHARD)
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(Items.AMETHYST_SHARD)).save(recipes)
|
||||
|
||||
ShapelessRecipeBuilder.shapeless(HexBlocks.ANCIENT_SCROLL_PAPER, 8)
|
||||
.requires(ingredients.dyes().get(DyeColor.BROWN))
|
||||
.requires(ingredients.dyes()[DyeColor.BROWN]!!)
|
||||
.requires(HexBlocks.SCROLL_PAPER, 8)
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.SCROLL_PAPER)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.SCROLL_PAPER)).save(recipes)
|
||||
|
||||
stack(HexBlocks.SCROLL_PAPER_LANTERN, 1, HexBlocks.SCROLL_PAPER, Items.TORCH)
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.SCROLL_PAPER)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.SCROLL_PAPER)).save(recipes)
|
||||
|
||||
stack(HexBlocks.ANCIENT_SCROLL_PAPER_LANTERN, 1, HexBlocks.ANCIENT_SCROLL_PAPER, Items.TORCH)
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.ANCIENT_SCROLL_PAPER)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.ANCIENT_SCROLL_PAPER)).save(recipes)
|
||||
|
||||
ShapelessRecipeBuilder.shapeless(HexBlocks.ANCIENT_SCROLL_PAPER_LANTERN, 8)
|
||||
.requires(ingredients.dyes().get(DyeColor.BROWN))
|
||||
.requires(ingredients.dyes()[DyeColor.BROWN]!!)
|
||||
.requires(HexBlocks.SCROLL_PAPER_LANTERN, 8)
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.SCROLL_PAPER_LANTERN))
|
||||
.save(recipes, modLoc("ageing_scroll_paper_lantern"));
|
||||
.save(recipes, modLoc("ageing_scroll_paper_lantern"))
|
||||
|
||||
stack(HexBlocks.SCONCE, 4, Ingredient.of(HexItems.CHARGED_AMETHYST),
|
||||
stack(HexBlocks.SCONCE, 4,
|
||||
Ingredient.of(HexItems.CHARGED_AMETHYST),
|
||||
ingredients.copperIngot())
|
||||
.unlockedBy("has_item", hasItem(HexItems.CHARGED_AMETHYST)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItems.CHARGED_AMETHYST)).save(recipes)
|
||||
|
||||
ShapelessRecipeBuilder.shapeless(HexBlocks.AKASHIC_PLANKS, 4)
|
||||
.requires(HexItemTags.AKASHIC_LOGS)
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_LOGS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_LOGS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_WOOD, 3)
|
||||
.define('W', HexBlocks.AKASHIC_LOG)
|
||||
.pattern("WW")
|
||||
.pattern("WW")
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.AKASHIC_LOG)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.AKASHIC_LOG)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_WOOD_STRIPPED, 3)
|
||||
.define('W', HexBlocks.AKASHIC_LOG_STRIPPED)
|
||||
.pattern("WW")
|
||||
.pattern("WW")
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.AKASHIC_LOG_STRIPPED)).save(recipes);
|
||||
ring(HexBlocks.AKASHIC_PANEL, 8, HexItemTags.AKASHIC_PLANKS, null)
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexBlocks.AKASHIC_LOG_STRIPPED)).save(recipes)
|
||||
|
||||
ring(HexBlocks.AKASHIC_PANEL, 8,
|
||||
HexItemTags.AKASHIC_PLANKS, null)
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_TILE, 6)
|
||||
.define('W', HexItemTags.AKASHIC_PLANKS)
|
||||
.pattern("WW ")
|
||||
.pattern("W W")
|
||||
.pattern(" WW")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_DOOR, 3)
|
||||
.define('W', HexItemTags.AKASHIC_PLANKS)
|
||||
.pattern("WW")
|
||||
.pattern("WW")
|
||||
.pattern("WW")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_TRAPDOOR, 2)
|
||||
.define('W', HexItemTags.AKASHIC_PLANKS)
|
||||
.pattern("WWW")
|
||||
.pattern("WWW")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_STAIRS, 4)
|
||||
.define('W', HexItemTags.AKASHIC_PLANKS)
|
||||
.pattern("W ")
|
||||
.pattern("WW ")
|
||||
.pattern("WWW")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_SLAB, 6)
|
||||
.define('W', HexItemTags.AKASHIC_PLANKS)
|
||||
.pattern("WWW")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_PRESSURE_PLATE, 1)
|
||||
.define('W', HexItemTags.AKASHIC_PLANKS)
|
||||
.pattern("WW")
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
ShapelessRecipeBuilder.shapeless(HexBlocks.AKASHIC_BUTTON)
|
||||
.requires(HexItemTags.AKASHIC_PLANKS)
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItemTags.AKASHIC_PLANKS)).save(recipes)
|
||||
|
||||
var enlightenment = new OvercastTrigger.Instance(EntityPredicate.Composite.ANY,
|
||||
MinMaxBounds.Ints.ANY,
|
||||
// add a little bit of slop here
|
||||
val enlightenment = OvercastTrigger.Instance(
|
||||
EntityPredicate.Composite.ANY,
|
||||
MinMaxBounds.Ints.ANY, // add a little bit of slop here
|
||||
MinMaxBounds.Doubles.atLeast(0.8),
|
||||
MinMaxBounds.Doubles.between(0.1, 2.05));
|
||||
|
||||
MinMaxBounds.Doubles.between(0.1, 2.05)
|
||||
)
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.EMPTY_IMPETUS)
|
||||
.define('B', Items.IRON_BARS)
|
||||
.define('A', HexItems.CHARGED_AMETHYST)
|
||||
|
@ -298,7 +320,7 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern("PSS")
|
||||
.pattern("BAB")
|
||||
.pattern("SSP")
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes);
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.EMPTY_DIRECTRIX)
|
||||
.define('C', Items.COMPARATOR)
|
||||
|
@ -308,16 +330,17 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern("CSS")
|
||||
.pattern("OAO")
|
||||
.pattern("SSC")
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes);
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_BOOKSHELF)
|
||||
.define('L', HexItemTags.AKASHIC_LOGS)
|
||||
.define('P', HexItemTags.AKASHIC_PLANKS)
|
||||
.define('C', Items.BOOK)
|
||||
/*this is the*/.pattern("LPL") // and what i have for you today is
|
||||
/*this is the*/ .pattern("LPL") // and what i have for you today is
|
||||
.pattern("CCC")
|
||||
.pattern("LPL")
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes);
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes)
|
||||
|
||||
ShapedRecipeBuilder.shaped(HexBlocks.AKASHIC_CONNECTOR)
|
||||
.define('L', HexItemTags.AKASHIC_LOGS)
|
||||
.define('P', HexItemTags.AKASHIC_PLANKS)
|
||||
|
@ -325,68 +348,112 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern("LPL")
|
||||
.pattern("CCC")
|
||||
.pattern("LPL")
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes);
|
||||
.unlockedBy("enlightenment", enlightenment).save(recipes)
|
||||
|
||||
new BrainsweepRecipeBuilder(StateIngredientHelper.of(Blocks.AMETHYST_BLOCK),
|
||||
new VillagerIngredient(null, null, 3),
|
||||
BrainsweepRecipeBuilder(StateIngredientHelper.of(Blocks.AMETHYST_BLOCK),
|
||||
VillagerIngredient(null, null, 3),
|
||||
Blocks.BUDDING_AMETHYST.defaultBlockState())
|
||||
.unlockedBy("enlightenment", enlightenment)
|
||||
.save(recipes, modLoc("brainsweep/budding_amethyst"));
|
||||
.save(recipes, modLoc("brainsweep/budding_amethyst"))
|
||||
|
||||
new BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
|
||||
new VillagerIngredient(new ResourceLocation("toolsmith"), null, 2),
|
||||
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
|
||||
VillagerIngredient(ResourceLocation("toolsmith"), null, 2),
|
||||
HexBlocks.IMPETUS_RIGHTCLICK.defaultBlockState())
|
||||
.unlockedBy("enlightenment", enlightenment)
|
||||
.save(recipes, modLoc("brainsweep/impetus_rightclick"));
|
||||
new BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
|
||||
new VillagerIngredient(new ResourceLocation("fletcher"), null, 2),
|
||||
.save(recipes, modLoc("brainsweep/impetus_rightclick"))
|
||||
|
||||
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
|
||||
VillagerIngredient(ResourceLocation("fletcher"), null, 2),
|
||||
HexBlocks.IMPETUS_LOOK.defaultBlockState())
|
||||
.unlockedBy("enlightenment", enlightenment)
|
||||
.save(recipes, modLoc("brainsweep/impetus_look"));
|
||||
new BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
|
||||
new VillagerIngredient(new ResourceLocation("cleric"), null, 2),
|
||||
.save(recipes, modLoc("brainsweep/impetus_look"))
|
||||
|
||||
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
|
||||
VillagerIngredient(ResourceLocation("cleric"), null, 2),
|
||||
HexBlocks.IMPETUS_STOREDPLAYER.defaultBlockState())
|
||||
.unlockedBy("enlightenment", enlightenment)
|
||||
.save(recipes, modLoc("brainsweep/impetus_storedplayer"));
|
||||
.save(recipes, modLoc("brainsweep/impetus_storedplayer"))
|
||||
|
||||
new BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_DIRECTRIX),
|
||||
new VillagerIngredient(new ResourceLocation("mason"), null, 1),
|
||||
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_DIRECTRIX),
|
||||
VillagerIngredient(ResourceLocation("mason"), null, 1),
|
||||
HexBlocks.DIRECTRIX_REDSTONE.defaultBlockState())
|
||||
.unlockedBy("enlightenment", enlightenment)
|
||||
.save(recipes, modLoc("brainsweep/directrix_redstone"));
|
||||
.save(recipes, modLoc("brainsweep/directrix_redstone"))
|
||||
|
||||
new BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.AKASHIC_CONNECTOR),
|
||||
new VillagerIngredient(new ResourceLocation("librarian"), null, 5),
|
||||
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.AKASHIC_CONNECTOR),
|
||||
VillagerIngredient(ResourceLocation("librarian"), null, 5),
|
||||
HexBlocks.AKASHIC_RECORD.defaultBlockState())
|
||||
.unlockedBy("enlightenment", enlightenment)
|
||||
.save(recipes, modLoc("brainsweep/akashic_record"));
|
||||
.save(recipes, modLoc("brainsweep/akashic_record"))
|
||||
|
||||
// Create compat
|
||||
|
||||
createCrushing.get()
|
||||
CreateCrushingRecipeBuilder()
|
||||
.withInput(Blocks.AMETHYST_CLUSTER)
|
||||
.duration(150)
|
||||
.withOutput(Items.AMETHYST_SHARD, 7)
|
||||
.withOutput(HexItems.AMETHYST_DUST, 5)
|
||||
.withOutput(0.25f, HexItems.CHARGED_AMETHYST)
|
||||
.save(recipes, new ResourceLocation("create", "crushing/amethyst_cluster"));
|
||||
.withConditions()
|
||||
.whenModLoaded("create")
|
||||
.save(recipes, ResourceLocation("create", "crushing/amethyst_cluster"))
|
||||
|
||||
createCrushing.get()
|
||||
CreateCrushingRecipeBuilder()
|
||||
.withInput(Blocks.AMETHYST_BLOCK)
|
||||
.duration(150)
|
||||
.withOutput(Items.AMETHYST_SHARD, 3)
|
||||
.withOutput(0.5f, HexItems.AMETHYST_DUST, 4)
|
||||
.save(recipes, new ResourceLocation("create", "crushing/amethyst_block"));
|
||||
.withConditions()
|
||||
.whenModLoaded("create")
|
||||
.save(recipes, ResourceLocation("create", "crushing/amethyst_block"))
|
||||
|
||||
createCrushing.get()
|
||||
CreateCrushingRecipeBuilder()
|
||||
.withInput(Items.AMETHYST_SHARD)
|
||||
.duration(150)
|
||||
.withOutput(HexItems.AMETHYST_DUST, 4)
|
||||
.withOutput(0.5f, HexItems.AMETHYST_DUST)
|
||||
.save(recipes, modLoc("compat/create/crushing/amethyst_shard"));
|
||||
.withConditions()
|
||||
.whenModLoaded("create")
|
||||
.save(recipes, modLoc("compat/create/crushing/amethyst_shard"))
|
||||
|
||||
// FD compat
|
||||
FarmersDelightCuttingRecipeBuilder()
|
||||
.withInput(HexBlocks.AKASHIC_LOG)
|
||||
.withTool(ingredients.axeStrip())
|
||||
.withOutput(HexBlocks.AKASHIC_LOG_STRIPPED)
|
||||
.withOutput("farmersdelight:tree_bark")
|
||||
.withSound(SoundEvents.AXE_STRIP)
|
||||
.withConditions()
|
||||
.whenModLoaded("farmersdelight")
|
||||
.save(recipes, modLoc("compat/farmersdelight/cutting/akashic_log"))
|
||||
|
||||
FarmersDelightCuttingRecipeBuilder()
|
||||
.withInput(HexBlocks.AKASHIC_WOOD)
|
||||
.withTool(ingredients.axeStrip())
|
||||
.withOutput(HexBlocks.AKASHIC_WOOD_STRIPPED)
|
||||
.withOutput("farmersdelight:tree_bark")
|
||||
.withSound(SoundEvents.AXE_STRIP)
|
||||
.withConditions()
|
||||
.whenModLoaded("farmersdelight")
|
||||
.save(recipes, modLoc("compat/farmersdelight/cutting/akashic_wood"))
|
||||
|
||||
FarmersDelightCuttingRecipeBuilder()
|
||||
.withInput(HexBlocks.AKASHIC_TRAPDOOR)
|
||||
.withTool(ingredients.axeDig())
|
||||
.withOutput(HexBlocks.AKASHIC_PLANKS)
|
||||
.withConditions()
|
||||
.whenModLoaded("farmersdelight")
|
||||
.save(recipes, modLoc("compat/farmersdelight/cutting/akashic_trapdoor"))
|
||||
|
||||
FarmersDelightCuttingRecipeBuilder()
|
||||
.withInput(HexBlocks.AKASHIC_DOOR)
|
||||
.withTool(ingredients.axeDig())
|
||||
.withOutput(HexBlocks.AKASHIC_PLANKS)
|
||||
.withConditions()
|
||||
.whenModLoaded("farmersdelight")
|
||||
.save(recipes, modLoc("compat/farmersdelight/cutting/akashic_door"))
|
||||
}
|
||||
|
||||
private void wandRecipe(Consumer<FinishedRecipe> recipes, ItemWand wand, Item plank) {
|
||||
private fun wandRecipe(recipes: Consumer<FinishedRecipe>, wand: ItemWand, plank: Item) {
|
||||
ShapedRecipeBuilder.shaped(wand)
|
||||
.define('W', plank)
|
||||
.define('S', Items.STICK)
|
||||
|
@ -395,22 +462,25 @@ public class HexplatRecipes extends PaucalRecipeProvider {
|
|||
.pattern(" WS")
|
||||
.pattern("S ")
|
||||
.unlockedBy("has_item", hasItem(HexItems.CHARGED_AMETHYST))
|
||||
.save(recipes);
|
||||
.save(recipes)
|
||||
}
|
||||
|
||||
private void gayRecipe(Consumer<FinishedRecipe> recipes, ItemPrideColorizer.Type type, Item material) {
|
||||
var colorizer = HexItems.PRIDE_COLORIZERS.get(type);
|
||||
private fun gayRecipe(recipes: Consumer<FinishedRecipe>, type: ItemPrideColorizer.Type, material: Ingredient) {
|
||||
val colorizer = HexItems.PRIDE_COLORIZERS[type]!!
|
||||
ShapedRecipeBuilder.shaped(colorizer)
|
||||
.define('D', HexItems.AMETHYST_DUST)
|
||||
.define('C', material)
|
||||
.pattern(" D ")
|
||||
.pattern("DCD")
|
||||
.pattern(" D ")
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST)).save(recipes);
|
||||
.unlockedBy("has_item", hasItem(HexItems.AMETHYST_DUST))
|
||||
.save(recipes)
|
||||
}
|
||||
|
||||
protected void specialRecipe(Consumer<FinishedRecipe> consumer, SimpleRecipeSerializer<?> serializer) {
|
||||
var name = Registry.RECIPE_SERIALIZER.getKey(serializer);
|
||||
SpecialRecipeBuilder.special(serializer).save(consumer, HexAPI.MOD_ID + ":dynamic/" + name.getPath());
|
||||
private fun specialRecipe(consumer: Consumer<FinishedRecipe>, serializer: SimpleRecipeSerializer<*>) {
|
||||
val name = Registry.RECIPE_SERIALIZER.getKey(serializer)
|
||||
SpecialRecipeBuilder.special(serializer).save(consumer, HexAPI.MOD_ID + ":dynamic/" + name!!.path)
|
||||
}
|
||||
|
||||
private fun RecipeBuilder.withConditions(): IXplatConditionsBuilder = conditions(this)
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package at.petrak.hexcasting.datagen.recipe.builders;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CompatIngredientValue implements Ingredient.Value {
|
||||
public final String item;
|
||||
|
||||
public CompatIngredientValue(String name) {
|
||||
this.item = name;
|
||||
}
|
||||
|
||||
public @NotNull Collection<ItemStack> getItems() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public @NotNull JsonObject serialize() {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("item", item);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public static Ingredient of(String itemName) {
|
||||
return new Ingredient(Stream.of(new CompatIngredientValue(itemName)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package at.petrak.hexcasting.datagen.recipe.builders;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public record CompatProcessingOutput(String name, int count, float chance) implements ProcessingOutput {
|
||||
@Override
|
||||
public JsonObject serialize() {
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("item", name);
|
||||
if (count != 1) {
|
||||
json.addProperty("count", count);
|
||||
}
|
||||
if (chance != 1) {
|
||||
json.addProperty("chance", chance);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -2,9 +2,7 @@ package at.petrak.hexcasting.datagen.recipe.builders;
|
|||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.minecraft.advancements.CriterionTriggerInstance;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.data.recipes.FinishedRecipe;
|
||||
import net.minecraft.data.recipes.RecipeBuilder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -26,7 +24,7 @@ import java.util.function.Consumer;
|
|||
// https://github.com/Creators-of-Create/Create/blob/82be76d8934af03b4e52cad6a9f74a4175ba7b05/src/main/java/com/simibubi/create/foundation/data/recipe/ProcessingRecipeGen.java
|
||||
// https://github.com/Creators-of-Create/Create/blob/82be76d8934af03b4e52cad6a9f74a4175ba7b05/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingRecipeBuilder.java
|
||||
// https://github.com/Creators-of-Create/Create/blob/82be76d8934af03b4e52cad6a9f74a4175ba7b05/src/main/java/com/simibubi/create/content/contraptions/processing/ProcessingRecipeSerializer.java
|
||||
public abstract class CreateCrushingRecipeBuilder implements RecipeBuilder {
|
||||
public class CreateCrushingRecipeBuilder implements RecipeBuilder {
|
||||
private String group = "";
|
||||
private Ingredient input;
|
||||
private final List<ProcessingOutput> results = new ArrayList<>();
|
||||
|
@ -78,7 +76,24 @@ public abstract class CreateCrushingRecipeBuilder implements RecipeBuilder {
|
|||
}
|
||||
|
||||
public CreateCrushingRecipeBuilder withOutput(ItemStack output, float chance) {
|
||||
this.results.add(new ProcessingOutput(output, chance));
|
||||
this.results.add(new ItemProcessingOutput(output, chance));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CreateCrushingRecipeBuilder withOutput(String name) {
|
||||
return withOutput(1f, name, 1);
|
||||
}
|
||||
|
||||
public CreateCrushingRecipeBuilder withOutput(String name, int count) {
|
||||
return withOutput(1f, name, count);
|
||||
}
|
||||
|
||||
public CreateCrushingRecipeBuilder withOutput(float chance, String name) {
|
||||
return withOutput(chance, name, 1);
|
||||
}
|
||||
|
||||
public CreateCrushingRecipeBuilder withOutput(float chance, String name, int count) {
|
||||
this.results.add(new CompatProcessingOutput(name, count, chance));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -92,12 +107,6 @@ public abstract class CreateCrushingRecipeBuilder implements RecipeBuilder {
|
|||
consumer.accept(new CrushingRecipe(resourceLocation));
|
||||
}
|
||||
|
||||
public abstract void serializeConditions(JsonObject object);
|
||||
|
||||
public abstract CreateCrushingRecipeBuilder whenModLoaded(String modid);
|
||||
|
||||
public abstract CreateCrushingRecipeBuilder whenModMissing(String modid);
|
||||
|
||||
public class CrushingRecipe implements FinishedRecipe {
|
||||
|
||||
private final ResourceLocation id;
|
||||
|
@ -128,8 +137,6 @@ public abstract class CreateCrushingRecipeBuilder implements RecipeBuilder {
|
|||
if (processingDuration > 0) {
|
||||
json.addProperty("processingTime", processingDuration);
|
||||
}
|
||||
|
||||
serializeConditions(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,22 +160,4 @@ public abstract class CreateCrushingRecipeBuilder implements RecipeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private record ProcessingOutput(ItemStack stack, float chance) {
|
||||
private JsonObject serialize() {
|
||||
JsonObject json = new JsonObject();
|
||||
ResourceLocation resourceLocation = Registry.ITEM.getKey(stack.getItem());
|
||||
json.addProperty("item", resourceLocation.toString());
|
||||
int count = stack.getCount();
|
||||
if (count != 1) {
|
||||
json.addProperty("count", count);
|
||||
}
|
||||
if (stack.hasTag()) {
|
||||
json.add("nbt", JsonParser.parseString(stack.getTag().toString()));
|
||||
}
|
||||
if (chance != 1) {
|
||||
json.addProperty("chance", chance);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
package at.petrak.hexcasting.datagen.recipe.builders;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.advancements.CriterionTriggerInstance;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.data.recipes.FinishedRecipe;
|
||||
import net.minecraft.data.recipes.RecipeBuilder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class FarmersDelightCuttingRecipeBuilder implements RecipeBuilder {
|
||||
private String group = "";
|
||||
private final List<ProcessingOutput> outputs = Lists.newArrayList();
|
||||
private Ingredient input;
|
||||
private ToolIngredient toolAction;
|
||||
private SoundEvent sound;
|
||||
|
||||
@Override
|
||||
public FarmersDelightCuttingRecipeBuilder unlockedBy(String s, CriterionTriggerInstance criterionTriggerInstance) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FarmersDelightCuttingRecipeBuilder group(@Nullable String name) {
|
||||
group = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getResult() {
|
||||
return Items.AIR; // Irrelevant, we implement serialization ourselves
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withInput(ItemLike item) {
|
||||
return withInput(Ingredient.of(item));
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withInput(ItemStack stack) {
|
||||
return withInput(Ingredient.of(stack));
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withInput(Ingredient ingredient) {
|
||||
this.input = ingredient;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(ItemLike output) {
|
||||
return withOutput(1f, output, 1);
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(float chance, ItemLike output) {
|
||||
return withOutput(chance, output, 1);
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(ItemLike output, int count) {
|
||||
return withOutput(1f, output, count);
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(float chance, ItemLike output, int count) {
|
||||
return withOutput(new ItemStack(output, count), chance);
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(ItemStack output, float chance) {
|
||||
this.outputs.add(new ItemProcessingOutput(output, chance));
|
||||
return this;
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(String name) {
|
||||
return withOutput(1f, name, 1);
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(String name, int count) {
|
||||
return withOutput(1f, name, count);
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(float chance, String name) {
|
||||
return withOutput(chance, name, 1);
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withOutput(float chance, String name, int count) {
|
||||
this.outputs.add(new CompatProcessingOutput(name, count, chance));
|
||||
return this;
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withTool(ToolIngredient ingredient) {
|
||||
this.toolAction = ingredient;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FarmersDelightCuttingRecipeBuilder withSound(SoundEvent sound) {
|
||||
this.sound = sound;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Consumer<FinishedRecipe> consumer, ResourceLocation resourceLocation) {
|
||||
consumer.accept(new CuttingRecipe(resourceLocation));
|
||||
}
|
||||
|
||||
public class CuttingRecipe implements FinishedRecipe {
|
||||
|
||||
private final ResourceLocation id;
|
||||
|
||||
public CuttingRecipe(ResourceLocation id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeRecipeData(@NotNull JsonObject json) {
|
||||
json.addProperty("type", "farmersdelight:cutting");
|
||||
|
||||
if (!group.isEmpty()) {
|
||||
json.addProperty("group", group);
|
||||
}
|
||||
|
||||
JsonArray jsonIngredients = new JsonArray();
|
||||
JsonArray jsonOutputs = new JsonArray();
|
||||
|
||||
jsonIngredients.add(input.toJson());
|
||||
|
||||
outputs.forEach(o -> jsonOutputs.add(o.serialize()));
|
||||
|
||||
json.add("ingredients", jsonIngredients);
|
||||
json.add("tool", toolAction.serialize());
|
||||
json.add("result", jsonOutputs);
|
||||
|
||||
if (sound != null) {
|
||||
json.addProperty("sound", Registry.SOUND_EVENT.getKey(sound).toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ResourceLocation getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull RecipeSerializer<?> getType() {
|
||||
return RecipeSerializer.SHAPELESS_RECIPE; // Irrelevant, we implement serialization ourselves
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject serializeAdvancement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAdvancementId() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package at.petrak.hexcasting.datagen.recipe.builders;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public record ItemProcessingOutput(ItemStack stack, float chance) implements ProcessingOutput {
|
||||
@Override
|
||||
public JsonObject serialize() {
|
||||
JsonObject json = new JsonObject();
|
||||
ResourceLocation resourceLocation = Registry.ITEM.getKey(stack.getItem());
|
||||
json.addProperty("item", resourceLocation.toString());
|
||||
int count = stack.getCount();
|
||||
if (count != 1) {
|
||||
json.addProperty("count", count);
|
||||
}
|
||||
if (stack.hasTag()) {
|
||||
json.add("nbt", JsonParser.parseString(stack.getTag().toString()));
|
||||
}
|
||||
if (chance != 1) {
|
||||
json.addProperty("chance", chance);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package at.petrak.hexcasting.datagen.recipe.builders;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public interface ProcessingOutput {
|
||||
JsonObject serialize();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package at.petrak.hexcasting.datagen.recipe.builders;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public interface ToolIngredient {
|
||||
JsonObject serialize();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package at.petrak.hexcasting.interop.patchouli;
|
||||
|
||||
import net.minecraft.client.resources.language.I18n;
|
||||
import vazkii.patchouli.api.IComponentProcessor;
|
||||
import vazkii.patchouli.api.IVariable;
|
||||
import vazkii.patchouli.api.IVariableProvider;
|
||||
|
||||
public class PatternProcessor implements IComponentProcessor {
|
||||
private String translationKey;
|
||||
|
||||
@Override
|
||||
public void setup(IVariableProvider vars) {
|
||||
if (vars.has("header"))
|
||||
translationKey = vars.get("header").asString();
|
||||
else {
|
||||
IVariable key = vars.get("op_id");
|
||||
String opName = key.asString();
|
||||
|
||||
String prefix = "hexcasting.spell.";
|
||||
boolean hasOverride = I18n.exists(prefix + "book." + opName);
|
||||
translationKey = prefix + (hasOverride ? "book." : "") + opName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IVariable process(String key) {
|
||||
if (key.equals("translation_key")) {
|
||||
return IVariable.wrap(translationKey);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package at.petrak.hexcasting.interop.utils;
|
||||
|
||||
import at.petrak.hexcasting.api.mod.HexConfig;
|
||||
import at.petrak.hexcasting.common.items.magic.ItemManaBattery;
|
||||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PhialRecipeStackBuilder {
|
||||
private static ItemStack makeBattery(int unit, int size) {
|
||||
return ItemManaBattery.withMana(new ItemStack(HexItems.BATTERY), unit * size, unit * size);
|
||||
}
|
||||
|
||||
public static Pair<List<ItemStack>, List<ItemStack>> createStacks() {
|
||||
List<ItemStack> inputItems = Lists.newArrayList();
|
||||
List<ItemStack> outputItems = Lists.newArrayList();
|
||||
|
||||
int dust = HexConfig.common().dustManaAmount();
|
||||
int shard = HexConfig.common().shardManaAmount();
|
||||
int charged = HexConfig.common().chargedCrystalManaAmount();
|
||||
|
||||
if (dust > 0) {
|
||||
inputItems.add(new ItemStack(HexItems.AMETHYST_DUST, 1));
|
||||
outputItems.add(makeBattery(dust, 1));
|
||||
inputItems.add(new ItemStack(HexItems.AMETHYST_DUST, 64));
|
||||
outputItems.add(makeBattery(dust, 64));
|
||||
}
|
||||
|
||||
if (shard > 0) {
|
||||
inputItems.add(new ItemStack(Items.AMETHYST_SHARD, 1));
|
||||
outputItems.add(makeBattery(shard, 1));
|
||||
inputItems.add(new ItemStack(Items.AMETHYST_SHARD, 64));
|
||||
outputItems.add(makeBattery(shard, 64));
|
||||
}
|
||||
|
||||
if (charged > 0) {
|
||||
inputItems.add(new ItemStack(HexItems.CHARGED_AMETHYST, 1));
|
||||
outputItems.add(makeBattery(charged, 1));
|
||||
inputItems.add(new ItemStack(HexItems.CHARGED_AMETHYST, 64));
|
||||
outputItems.add(makeBattery(charged, 64));
|
||||
}
|
||||
|
||||
return new Pair<>(inputItems, outputItems);
|
||||
}
|
||||
|
||||
public static boolean shouldAddRecipe() {
|
||||
return HexConfig.common().dustManaAmount() > 0 ||
|
||||
HexConfig.common().shardManaAmount() > 0 ||
|
||||
HexConfig.common().chargedCrystalManaAmount() > 0;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
@file:JvmName("AccessorWrappers")
|
||||
package at.petrak.hexcasting.ktxt
|
||||
|
||||
import at.petrak.hexcasting.mixin.accessor.AccessorEntity
|
||||
import at.petrak.hexcasting.mixin.accessor.AccessorLivingEntity
|
||||
import at.petrak.hexcasting.mixin.accessor.AccessorUseOnContext
|
||||
import at.petrak.hexcasting.mixin.accessor.AccessorVillager
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.npc.Villager
|
||||
|
@ -18,6 +21,18 @@ var LivingEntity.lastHurt: Float
|
|||
get() = (this as AccessorLivingEntity).`hex$getLastHurt`()
|
||||
set(value) = (this as AccessorLivingEntity).`hex$setLastHurt`(value)
|
||||
|
||||
fun LivingEntity.playHurtSound(source: DamageSource) = (this as AccessorLivingEntity).`hex$playHurtSound`(source)
|
||||
fun LivingEntity.checkTotemDeathProtection(source: DamageSource) = (this as AccessorLivingEntity).`hex$checkTotemDeathProtection`(source)
|
||||
val LivingEntity.deathSoundAccessor: SoundEvent? get() = (this as AccessorLivingEntity).`hex$getDeathSound`()
|
||||
val LivingEntity.soundVolumeAccessor get() = (this as AccessorLivingEntity).`hex$getSoundVolume`()
|
||||
|
||||
fun LivingEntity.setHurtWithStamp(source: DamageSource, stamp: Long) = (this as AccessorLivingEntity).apply {
|
||||
`hex$setLastDamageSource`(source)
|
||||
`hex$setLastDamageStamp`(stamp)
|
||||
}
|
||||
|
||||
fun Entity.markHurt() = (this as AccessorEntity).`hex$markHurt`()
|
||||
|
||||
fun Villager.tellWitnessesThatIWasMurdered(murderer: Entity) = (this as AccessorVillager).`hex$tellWitnessesThatIWasMurdered`(murderer)
|
||||
|
||||
@Suppress("FunctionName")
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package at.petrak.hexcasting.mixin.accessor;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public interface AccessorEntity {
|
||||
@Invoker("markHurt")
|
||||
void hex$markHurt();
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
package at.petrak.hexcasting.mixin.accessor;
|
||||
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public interface AccessorLivingEntity {
|
||||
|
@ -11,4 +14,22 @@ public interface AccessorLivingEntity {
|
|||
|
||||
@Accessor("lastHurt")
|
||||
void hex$setLastHurt(float lastHurt);
|
||||
|
||||
@Invoker("playHurtSound")
|
||||
void hex$playHurtSound(DamageSource source);
|
||||
|
||||
@Invoker("checkTotemDeathProtection")
|
||||
boolean hex$checkTotemDeathProtection(DamageSource source);
|
||||
|
||||
@Invoker("getDeathSound")
|
||||
SoundEvent hex$getDeathSound();
|
||||
|
||||
@Invoker("getSoundVolume")
|
||||
float hex$getSoundVolume();
|
||||
|
||||
@Accessor("lastDamageSource")
|
||||
void hex$setLastDamageSource(DamageSource source);
|
||||
|
||||
@Accessor("lastDamageStamp")
|
||||
void hex$setLastDamageStamp(long stamp);
|
||||
}
|
||||
|
|
|
@ -120,8 +120,9 @@ public interface IXplatAbstractions {
|
|||
<T extends BlockEntity> BlockEntityType<T> createBlockEntityType(BiFunction<BlockPos, BlockState, T> func,
|
||||
Block... blocks);
|
||||
|
||||
boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, ItemStack stack, Fluid fluid);
|
||||
boolean tryPlaceFluid(Level level, InteractionHand hand, BlockPos pos, Fluid fluid);
|
||||
|
||||
boolean drainAllFluid(Level level, BlockPos pos);
|
||||
|
||||
// misc
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
"item.hexcasting.trinket": "Trinket",
|
||||
"item.hexcasting.artifact": "Artifact",
|
||||
"item.hexcasting.battery": "Phial of Media",
|
||||
"item.hexcasting.manaholder.amount": "N*merical Mana: %s/%s (%.0f%%)",
|
||||
"item.hexcasting.amethyst_dust": "Amethyst Dust",
|
||||
"item.hexcasting.charged_amethyst": "Charged Amethyst",
|
||||
"item.hexcasting.lens": "Scrying Lens",
|
||||
|
@ -66,9 +65,8 @@
|
|||
"item.hexcasting.pride_colorizer_transgender": "Transgender Pigment",
|
||||
"item.hexcasting.uuid_colorizer": "Soulglimmer Pigment",
|
||||
"item.hexcasting.creative_unlocker": "The Media Cube",
|
||||
"item.hexcasting.creative_unlocker.tooltip.0": "Contains %s.",
|
||||
"item.hexcasting.creative_unlocker.for_emphasis": "INFINITE MEDIA",
|
||||
"item.hexcasting.creative_unlocker.tooltip.1": "Consume to unlock all %s knowledge.",
|
||||
"item.hexcasting.creative_unlocker.tooltip": "Consume to unlock all %s knowledge.",
|
||||
"item.hexcasting.creative_unlocker.mod_name": "Hexcasting",
|
||||
|
||||
|
||||
|
@ -123,13 +121,14 @@
|
|||
"hexcasting.tooltip.abacus": "%d",
|
||||
"hexcasting.tooltip.abacus.reset": "Reset to 0",
|
||||
"hexcasting.tooltip.abacus.reset.nice": "nice",
|
||||
"hexcasting.tooltip.lens.impetus.mana": "%s dust",
|
||||
"hexcasting.tooltip.lens.impetus.storedplayer": "Bound to %s",
|
||||
"hexcasting.tooltip.lens.impetus.storedplayer.none": "Unbound",
|
||||
"hexcasting.tooltip.lens.pattern.invalid": "Invalid Pattern",
|
||||
"hexcasting.tooltip.lens.akashic.bookshelf.location": "Record at %s",
|
||||
"hexcasting.tooltip.lens.akashic.record.count": "%s iotas stored",
|
||||
"hexcasting.tooltip.lens.akashic.record.count.single": "%s iota stored",
|
||||
"hexcasting.tooltip.lens.bee": "%s bees",
|
||||
"hexcasting.tooltip.lens.bee.single": "%s bee",
|
||||
"hexcasting.tooltip.brainsweep.min_level": "Level %s or higher",
|
||||
"hexcasting.tooltip.brainsweep.level": "Level %s",
|
||||
"hexcasting.tooltip.brainsweep.product": "Mindless Body",
|
||||
|
@ -139,19 +138,25 @@
|
|||
"hexcasting.spelldata.entity.whoknows": "An Entity (this should only show up if this was stored before the 0.5.0 update, use Scribe's Reflection, Scribe's Gambit to fix)",
|
||||
"hexcasting.spelldata.akashic.nopos": "The owning record does not know of any iota here (this is a bug)",
|
||||
|
||||
"hexcasting.tooltip.mana": "%s dust",
|
||||
"hexcasting.tooltip.mana_amount": "Contains: %s (%s)",
|
||||
"hexcasting.tooltip.mana_amount.advanced": "Contains: %s/%s (%s)",
|
||||
|
||||
"gui.hexcasting.spellcasting": "Hex Grid",
|
||||
"tag.hexcasting.wands": "Hex Staves",
|
||||
"tag.hexcasting.akashic_logs": "Edified Logs",
|
||||
"tag.hexcasting.akashic_planks": "Edified Planks",
|
||||
"tag.hexcasting.phial_base": "Empty Phials",
|
||||
"emi.category.hexcasting.brainsweep": "Flay Mind",
|
||||
"emi.category.hexcasting.craft.battery": "Craft Phial",
|
||||
"emi.category.hexcasting.edify": "Edify Sapling",
|
||||
"emi.category.hexcasting.villager_leveling": "Trade Leveling",
|
||||
"emi.category.hexcasting.villager_profession": "Villager Profession",
|
||||
|
||||
"advancement.hexcasting:root": "Hexcasting Research",
|
||||
"advancement.hexcasting:root.desc": "Find a concentrated form of media growing deep beneath the earth.",
|
||||
"advancement.hexcasting:root.desc": "Find and mine a concentrated form of media growing deep beneath the earth.",
|
||||
"advancement.hexcasting:enlightenment": "Achieve Enlightenment",
|
||||
"advancement.hexcasting:enlightenment.desc": "Go nearly insane from casting a hex using almost all of your health.",
|
||||
"advancement.hexcasting:enlightenment.desc": "Shatter a barrier by casting a hex using almost all of your health.",
|
||||
"advancement.hexcasting:wasteful_cast": "Waste Not...",
|
||||
"advancement.hexcasting:wasteful_cast.desc": "Waste a large amount of media when casting a hex.",
|
||||
"advancement.hexcasting:big_cast": "... Want Not",
|
||||
|
@ -159,7 +164,7 @@
|
|||
"advancement.hexcasting:y_u_no_cast_angy": "Blind Diversion",
|
||||
"advancement.hexcasting:y_u_no_cast_angy.desc": "Try to cast a spell from a scroll, but fail.",
|
||||
"advancement.hexcasting:opened_eyes": "Opened Eyes",
|
||||
"advancement.hexcasting:opened_eyes.desc": "Have nature take a piece of your mind in payment for a hex.",
|
||||
"advancement.hexcasting:opened_eyes.desc": "Have nature take a piece of your mind in payment for a hex. What might happen if you let it have more?",
|
||||
|
||||
"stat.hexcasting.mana_used": "Media Consumed (in dust)",
|
||||
"stat.hexcasting.mana_overcasted": "Media Overcast (in dust)",
|
||||
|
@ -178,7 +183,10 @@
|
|||
"hexcasting.pattern.unknown": "Unknown pattern resource location %s",
|
||||
"hexcasting.debug.mana_withdrawn": "%s - Mana withdrawn: %s",
|
||||
"hexcasting.debug.mana_withdrawn.with_dust": "%s - Mana withdrawn: %s (%s in dust)",
|
||||
"hexcasting.debug.mana_inserted": "%s - Mana inserted: %s",
|
||||
"hexcasting.debug.mana_inserted.with_dust": "%s - Mana inserted: %s (%s in dust)",
|
||||
"hexcasting.debug.all_mana": "Entire contents",
|
||||
"hexcasting.debug.infinite_mana": "Infinite",
|
||||
|
||||
"hexcasting.message.cant_overcast": "That Hex needed more media than I had... I should double-check my math.",
|
||||
"hexcasting.message.cant_great_spell": "The spell failed, somehow... am I not skilled enough?",
|
||||
|
@ -199,10 +207,40 @@
|
|||
"hexcasting.subtitles.impetus.fletcher.tick": "Fletcher Impetus ticks",
|
||||
"hexcasting.subtitles.impetus.cleric.register": "Cleric Impetus dings",
|
||||
|
||||
"_comment": "hexcasting.spell.book keys override the name of a pattern in the patchouli book if present",
|
||||
|
||||
"hexcasting.spell.book.hexcasting:get_entity_height": "Stadiometer's Prfn.",
|
||||
"hexcasting.spell.book.hexcasting:get_entity/animal": "Entity Prfn.: Animal",
|
||||
"hexcasting.spell.book.hexcasting:get_entity/monster": "Entity Prfn.: Monster",
|
||||
"hexcasting.spell.book.hexcasting:get_entity/item": "Entity Prfn.: Item",
|
||||
"hexcasting.spell.book.hexcasting:get_entity/player": "Entity Prfn.: Player",
|
||||
"hexcasting.spell.book.hexcasting:get_entity/living": "Entity Prfn.: Living",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity": "Zone Dstl.: Any",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/animal": "Zone Dstl.: Animal",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/monster": "Zone Dstl.: Monster",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/item": "Zone Dstl.: Item",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/player": "Zone Dstl.: Player",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/living": "Zone Dstl.: Living",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/not_animal": "Zone Dstl.: Non-Animal",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/not_monster": "Zone Dstl.: Non-Monster",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/not_item": "Zone Dstl.: Non-Item",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/not_player": "Zone Dstl.: Non-Player",
|
||||
"hexcasting.spell.book.hexcasting:zone_entity/not_living": "Zone Dstl.: Non-Living",
|
||||
"hexcasting.spell.book.hexcasting:mul_dot": "Multiplicative Dstl.",
|
||||
"hexcasting.spell.book.hexcasting:div_cross": "Division Dstl.",
|
||||
"hexcasting.spell.book.hexcasting:arcsin": "Inverse Sine Prfn.",
|
||||
"hexcasting.spell.book.hexcasting:arccos": "Inverse Cosine Prfn.",
|
||||
"hexcasting.spell.book.hexcasting:arctan": "Inverse Tangent Prfn.",
|
||||
"hexcasting.spell.book.hexcasting:const/vec/x": "Vector Rfln. +X/-X",
|
||||
"hexcasting.spell.book.hexcasting:const/vec/y": "Vector Rfln. +Y/-Y",
|
||||
"hexcasting.spell.book.hexcasting:const/vec/z": "Vector Rfln. +Z/-Z",
|
||||
"hexcasting.spell.book.hexcasting:number": "Numerical Reflection",
|
||||
"hexcasting.spell.book.hexcasting:mask": "Bookkeeper's Gambit",
|
||||
|
||||
"hexcasting.spell.hexcasting:get_caster": "Mind's Reflection",
|
||||
"hexcasting.spell.hexcasting:get_entity_pos": "Compass' Purification",
|
||||
"hexcasting.spell.hexcasting:get_entity_look": "Alidade's Purification",
|
||||
"hexcasting.spell.hexcasting:get_entity_height": "Stadiometer's Prfn.",
|
||||
"hexcasting.spell.hexcasting:get_entity_height": "Stadiometer's Purification",
|
||||
"hexcasting.spell.hexcasting:get_entity_velocity": "Pace Purification",
|
||||
"hexcasting.spell.hexcasting:raycast": "Archer's Distillation",
|
||||
"hexcasting.spell.hexcasting:raycast/axis": "Architect's Distillation",
|
||||
|
@ -228,22 +266,22 @@
|
|||
"hexcasting.spell.hexcasting:construct": "Speaker's Distillation",
|
||||
"hexcasting.spell.hexcasting:deconstruct": "Speaker's Decomposition",
|
||||
"hexcasting.spell.hexcasting:get_entity": "Entity Purification",
|
||||
"hexcasting.spell.hexcasting:get_entity/animal": "Entity Prfn.: Animal",
|
||||
"hexcasting.spell.hexcasting:get_entity/monster": "Entity Prfn.: Monster",
|
||||
"hexcasting.spell.hexcasting:get_entity/item": "Entity Prfn.: Item",
|
||||
"hexcasting.spell.hexcasting:get_entity/player": "Entity Prfn.: Player",
|
||||
"hexcasting.spell.hexcasting:get_entity/living": "Entity Prfn.: Living",
|
||||
"hexcasting.spell.hexcasting:zone_entity": "Zone Dstl.: Any",
|
||||
"hexcasting.spell.hexcasting:zone_entity/animal": "Zone Dstl.: Animal",
|
||||
"hexcasting.spell.hexcasting:zone_entity/monster": "Zone Dstl.: Monster",
|
||||
"hexcasting.spell.hexcasting:zone_entity/item": "Zone Dstl.: Item",
|
||||
"hexcasting.spell.hexcasting:zone_entity/player": "Zone Dstl.: Player",
|
||||
"hexcasting.spell.hexcasting:zone_entity/living": "Zone Dstl.: Living",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_animal": "Zone Dstl.: Non-Animal",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_monster": "Zone Dstl.: Non-Monster",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_item": "Zone Dstl.: Non-Item",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_player": "Zone Dstl.: Non-Player",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_living": "Zone Dstl.: Non-Living",
|
||||
"hexcasting.spell.hexcasting:get_entity/animal": "Entity Purification: Animal",
|
||||
"hexcasting.spell.hexcasting:get_entity/monster": "Entity Purification: Monster",
|
||||
"hexcasting.spell.hexcasting:get_entity/item": "Entity Purification: Item",
|
||||
"hexcasting.spell.hexcasting:get_entity/player": "Entity Purification: Player",
|
||||
"hexcasting.spell.hexcasting:get_entity/living": "Entity Purification: Living",
|
||||
"hexcasting.spell.hexcasting:zone_entity": "Zone Distillation: Any",
|
||||
"hexcasting.spell.hexcasting:zone_entity/animal": "Zone Distillation: Animal",
|
||||
"hexcasting.spell.hexcasting:zone_entity/monster": "Zone Distillation: Monster",
|
||||
"hexcasting.spell.hexcasting:zone_entity/item": "Zone Distillation: Item",
|
||||
"hexcasting.spell.hexcasting:zone_entity/player": "Zone Distillation: Player",
|
||||
"hexcasting.spell.hexcasting:zone_entity/living": "Zone Distillation: Living",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_animal": "Zone Distillation: Non-Animal",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_monster": "Zone Distillation: Non-Monster",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_item": "Zone Distillation: Non-Item",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_player": "Zone Distillation: Non-Player",
|
||||
"hexcasting.spell.hexcasting:zone_entity/not_living": "Zone Distillation: Non-Living",
|
||||
"hexcasting.spell.hexcasting:const/null": "Nullary Reflection",
|
||||
"hexcasting.spell.hexcasting:duplicate": "Gemini Decomposition",
|
||||
"hexcasting.spell.hexcasting:duplicate_n": "Gemini's Gambit",
|
||||
|
@ -253,8 +291,8 @@
|
|||
"hexcasting.spell.hexcasting:swizzle": "Swindler's Gambit",
|
||||
"hexcasting.spell.hexcasting:add": "Additive Distillation",
|
||||
"hexcasting.spell.hexcasting:sub": "Subtractive Distillation",
|
||||
"hexcasting.spell.hexcasting:mul_dot": "Multiplicative Dstl.",
|
||||
"hexcasting.spell.hexcasting:div_cross": "Division Dstl.",
|
||||
"hexcasting.spell.hexcasting:mul_dot": "Multiplicative Distillation",
|
||||
"hexcasting.spell.hexcasting:div_cross": "Division Distillation",
|
||||
"hexcasting.spell.hexcasting:abs_len": "Length Purification",
|
||||
"hexcasting.spell.hexcasting:pow_proj": "Power Distillation",
|
||||
"hexcasting.spell.hexcasting:construct_vec": "Vector Exaltation",
|
||||
|
@ -281,9 +319,9 @@
|
|||
"hexcasting.spell.hexcasting:sin": "Sine Purification",
|
||||
"hexcasting.spell.hexcasting:cos": "Cosine Purification",
|
||||
"hexcasting.spell.hexcasting:tan": "Tangent Purification",
|
||||
"hexcasting.spell.hexcasting:arcsin": "Inverse Sine Prfn.",
|
||||
"hexcasting.spell.hexcasting:arccos": "Inverse Cosine Prfn.",
|
||||
"hexcasting.spell.hexcasting:arctan": "Inverse Tangent Prfn.",
|
||||
"hexcasting.spell.hexcasting:arcsin": "Inverse Sine Purification",
|
||||
"hexcasting.spell.hexcasting:arccos": "Inverse Cosine Purification",
|
||||
"hexcasting.spell.hexcasting:arctan": "Inverse Tangent Purification",
|
||||
"hexcasting.spell.hexcasting:random": "Entropy Reflection",
|
||||
"hexcasting.spell.hexcasting:logarithm": "Logarithmic Distillation",
|
||||
"hexcasting.spell.hexcasting:coerce_axial": "Axial Purification",
|
||||
|
@ -302,7 +340,7 @@
|
|||
"hexcasting.spell.hexcasting:recharge": "Recharge Item",
|
||||
"hexcasting.spell.hexcasting:erase": "Erase Item",
|
||||
"hexcasting.spell.hexcasting:create_water": "Create Water",
|
||||
"hexcasting.spell.hexcasting:destroy_water": "Destroy Water",
|
||||
"hexcasting.spell.hexcasting:destroy_water": "Destroy Liquid",
|
||||
"hexcasting.spell.hexcasting:ignite": "Ignite Block",
|
||||
"hexcasting.spell.hexcasting:extinguish": "Extinguish Area",
|
||||
"hexcasting.spell.hexcasting:conjure_block": "Conjure Block",
|
||||
|
@ -353,16 +391,13 @@
|
|||
"hexcasting.spell.hexcasting:const/vec/nx": "Vector Reflection -X",
|
||||
"hexcasting.spell.hexcasting:const/vec/ny": "Vector Reflection -Y",
|
||||
"hexcasting.spell.hexcasting:const/vec/nz": "Vector Reflection -Z",
|
||||
"hexcasting.spell.hexcasting:const/vec/x": "Vector Rfln. +X/-X",
|
||||
"hexcasting.spell.hexcasting:const/vec/y": "Vector Rfln. +Y/-Y",
|
||||
"hexcasting.spell.hexcasting:const/vec/z": "Vector Rfln. +Z/-Z",
|
||||
"hexcasting.spell.hexcasting:const/vec/0": "Vector Reflection Zero",
|
||||
"hexcasting.spell.hexcasting:const/double/pi": "Arc's Reflection",
|
||||
"hexcasting.spell.hexcasting:const/double/tau": "Circle's Reflection",
|
||||
"hexcasting.spell.hexcasting:const/double/e": "Euler's Reflection",
|
||||
"hexcasting.spell.hexcasting:number": "Numerical Reflection",
|
||||
"hexcasting.spell.hexcasting:mask": "Bookkeeper's Gambit",
|
||||
"hexcasting.spell.unknown": "Special Handler",
|
||||
"hexcasting.spell.hexcasting:number": "Numerical Reflection: %s",
|
||||
"hexcasting.spell.hexcasting:mask": "Bookkeeper's Gambit: %s",
|
||||
"hexcasting.spell.null": "Unknown Pattern",
|
||||
|
||||
"hexcasting.spell.hexcasting:interop/gravity/get": "Gravitational Purification",
|
||||
"hexcasting.spell.hexcasting:interop/gravity/set": "Alter Gravity",
|
||||
|
@ -624,7 +659,7 @@
|
|||
"hexcasting.page.hexcasting.2": "To do this, I can craft one of three types of magic items: $(l:items/hexcasting)$(item)Cyphers/$, $(l:items/hexcasting)$(item)Trinkets/$, or $(l:items/hexcasting)$(item)Artifacts/$. All of them hold the patterns of a given _Hex inside, along with a small battery containing _media.$(br2)Simply holding one and pressing $(thing)$(k:use)/$ will cast the patterns inside, as if the holder had cast them out of a staff, using its internal battery.",
|
||||
"hexcasting.page.hexcasting.3": "Each item has its own quirks:$(br2)$(l:items/hexcasting)$(item)Cyphers/$ are fragile, destroyed after their internal _media reserves are gone, and $(italic)cannot/$ be recharged;$(br2)$(l:items/hexcasting)$(item)Trinkets/$ can be cast as much as the holder likes, as long as there's enough _media left, but become useless afterwards until recharged;",
|
||||
"hexcasting.page.hexcasting.4": "$(l:items/hexcasting)$(item)Artifacts/$ are the most powerful of all-- after their _media is depleted, they can use $(l:items/amethyst)$(item)Amethyst/$ from the holder's inventory to pay for the _Hex, just as I do when casting with a $(l:items/staff)$(item)Staff/$. Of course, this also means the spell might consume their mind if there's not enough $(l:items/amethyst)$(item)Amethyst/$.$(br2)Once I've made an empty magic item in a mundane crafting bench, I infuse the _Hex into it using (what else but) a spell appropriate to the item. $(l:patterns/spells/hexcasting)I've catalogued the patterns here./$",
|
||||
"hexcasting.page.hexcasting.5": "Each infusion spell requires an entity and a list of patterns on the stack. The entity must be a _media-holding item entity (i.e. $(l:items/amethyst)$(item)amethyst/$ crystals, dropped on the ground); the entity is consumed and forms the battery.$(br2)Usefully, it seems that the _media in the battery is not consumed in chunks as it is when casting with a $(l:items/staff)$(item)Staff/$-- rather, the _media \"melts down\" into one continuous pool. Thus, if I store a _Hex that only costs one $(l:items/amethyst)$(item)Amethyst Dust/$'s worth of mana, a $(l:items/amethyst)$(item)Charged Crystal/$ used as the battery will allow me to cast it 10 times.",
|
||||
"hexcasting.page.hexcasting.5": "Each infusion spell requires an entity and a list of patterns on the stack. The entity must be a _media-holding item entity (i.e. $(l:items/amethyst)$(item)amethyst/$ crystals, dropped on the ground); the entity is consumed and forms the battery.$(br2)Usefully, it seems that the _media in the battery is not consumed in chunks as it is when casting with a $(l:items/staff)$(item)Staff/$-- rather, the _media \"melts down\" into one continuous pool. Thus, if I store a _Hex that only costs one $(l:items/amethyst)$(item)Amethyst Dust/$'s worth of media, a $(l:items/amethyst)$(item)Charged Crystal/$ used as the battery will allow me to cast it 10 times.",
|
||||
"hexcasting.page.hexcasting.crafting.desc": "$(italic)We have a saying in our field: \"Magic isn't\". It doesn't \"just work,\" it doesn't respond to your thoughts, you can't throw fireballs or create a roast dinner from thin air or turn a bunch of muggers into frogs and snails./$",
|
||||
|
||||
"hexcasting.entry.phials": "Phials of Media",
|
||||
|
@ -697,7 +732,7 @@
|
|||
|
||||
"hexcasting.entry.akashiclib": "Akashic Libraries",
|
||||
"hexcasting.page.akashiclib.1": "I KNOW SO MUCH it is ONLY RIGHT to have a place to store it all. Information can be stored in books but it is oh so so so so $(italic)slow/$ to write by hand and read by eye. I demand BETTER. And so I shall MAKE better.$(br2)... I am getting worse ... do not know if I have time to write everything bursting through my head before expiring.",
|
||||
"hexcasting.page.akashiclib.2": "The library. Here. My plans.$(br2)Like how patterns are associated with actions, I can associate my own patterns with iotas in any way I choose. An $(l:greatwork/akashiclib)$(item)Akashic Record/$ controls the library, and each $(l:greatwork/akashiclib)$(item)Akashic Bookshelf/$ stores one pattern mapped to one iota. These must all be directly connected together, touching. An $(l:greatwork/akashiclib)$(item)Akashic Ligature/$ doesn't do anything but count as a connecting block, to extend the size of my library.",
|
||||
"hexcasting.page.akashiclib.2": "The library. Here. My plans.$(br2)Like how patterns are associated with actions, I can associate my own patterns with iotas in any way I choose. An $(l:greatwork/akashiclib)$(item)Akashic Record/$ controls the library, and each $(l:greatwork/akashiclib)$(item)Akashic Bookshelf/$ stores one pattern mapped to one iota. These must all be directly connected together, touching, within 32 blocks. An $(l:greatwork/akashiclib)$(item)Akashic Ligature/$ doesn't do anything but count as a connecting block, to extend the size of my library.",
|
||||
"hexcasting.page.akashiclib.akashic_record": "Allocating and assigning patterns is simple but oh so boring. I have better things to do. I will need a mind well-used to its work for the extraction to stay sound.",
|
||||
"hexcasting.page.akashiclib.3": "Then to operate the library is simple, the patterns are routed through the librarian and it looks them up and returns the iota to you. Two actions do the work. $(l:patterns/akashic_patterns)Notes here/$.$(br2)Using an empty $(l:items/scroll)$(item)scroll/$ on a bookshelf copies the pattern there onto the $(l:items/scroll)$(item)scroll/$. Sneaking and using an empty hand clears the datum in the shelf.",
|
||||
|
||||
|
@ -723,7 +758,6 @@
|
|||
"hexcasting.page.basics_pattern.raycast/entity": "Like $(l:patterns/basics#hexcasting:raycast)$(action)Archer's Distillation/$, but instead returns the $(italic)entity/$ I am looking at. Costs a negligible amount of _media.",
|
||||
|
||||
"hexcasting.entry.numbers": "Number Literals",
|
||||
"hexcasting.page.numbers.1.header": "Numerical Reflection",
|
||||
"hexcasting.page.numbers.1": "Irritatingly, there is no easy way to draw numbers. Here is the method Nature deigned to give us.",
|
||||
"hexcasting.page.numbers.2": "First, I draw one of the two shapes shown on the other page. Next, the $(italic)angles/$ following will modify a running count starting at 0.$(li)Forward: Add 1$(li)Left: Add 5$(li)Right: Add 10$(li)Sharp Left: Multiply by 2$(li)Sharp Right: Divide by 2.$(br)The clockwise version of the pattern, on the right of the other page, will negate the value at the very end. (The left-hand counter-clockwise version keeps the number positive).$(p)Once I finish drawing, the number's pushed to the top of the stack.",
|
||||
"hexcasting.page.numbers.example.10.header": "Example 1",
|
||||
|
@ -797,7 +831,6 @@
|
|||
"hexcasting.page.stackmanip.splat": "Remove the list at the top of the stack, then push its contents to the stack.",
|
||||
"hexcasting.page.stackmanip.duplicate": "Duplicates the top iota of the stack.",
|
||||
"hexcasting.page.stackmanip.duplicate_n": "Removes the number at the top of the stack, then copies the top iota of the stack that number of times. (A count of 2 results in two of the iota on the stack, not three.)",
|
||||
"hexcasting.page.stackmanip.mask.header": "Bookkeeper's Gambits",
|
||||
"hexcasting.page.stackmanip.mask.1": "An infinite family of actions that keep or remove elements at the top of the stack based on the sequence of dips and lines.",
|
||||
"hexcasting.page.stackmanip.mask.2": "Assuming that I draw a Bookkeeper's Gambit pattern left-to-right, the number of iotas the action will require is determined by the horizontal distance covered by the pattern. From deepest in the stack to shallowest, a flat line will keep the iota, whereas a triangle dipping down will remove it.$(br2)If my stack contains $(italic)0, 1, 2/$ from deepest to shallowest, drawing the first pattern opposite will give me $(italic)1/$, the second will give me $(italic)0/$, and the third will give me $(italic)0, 2/$ (the 0 at the bottom is left untouched).",
|
||||
"hexcasting.page.stackmanip.swizzle.1": "Rearranges the top elements of the stack based on the given numerical code, which is the index of the permutation wanted. Costs an amount of media that starts negligible and scales up as the numerical code does.",
|
||||
|
@ -901,7 +934,7 @@
|
|||
|
||||
"hexcasting.entry.basic_spell": "Basic Spells",
|
||||
"hexcasting.page.basic_spell.explode.1": "Remove a number and vector from the stack, then create an explosion at the given location with the given power.",
|
||||
"hexcasting.page.basic_spell.explode.2": "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)Strangely, this explosion doesn't seem to harm me. Perhaps it's because $(italic)I/$ am the one exploding?$(br2)Costs a negligible amount at power 0, plus 3 extra $(l:items/amethyst)$(item)Amethyst Dust/$s per point of explosion power.",
|
||||
"hexcasting.page.basic_spell.explode.2": "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)Strangely, this explosion doesn't seem to harm me. Perhaps it's because $(italic)I/$ am the one exploding?$(br2)Costs a negligible amount at power 0, plus 3 extra $(l:items/amethyst)$(item)Amethyst Dust/$ per point of explosion power.",
|
||||
"hexcasting.page.basic_spell.explode.fire.1": "Remove a number and vector from the stack, then create a fiery explosion at the given location with the given power.",
|
||||
"hexcasting.page.basic_spell.explode.fire.2": "Costs one $(l:items/amethyst)$(item)Amethyst Dust/$, plus about 3 extra $(l:items/amethyst)$(item)Amethyst Dust/$s per point of explosion power. Otherwise, the same as $(l:patterns/spells/basic#hexcasting:explode)$(action)Explosion/$, except with fire.",
|
||||
"hexcasting.page.basic_spell.add_motion": "Remove an entity and direction from the stack, then give a shove 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 $(l:items/amethyst)$(item)Amethyst Dust/$ equal to the square of the length of the vector, plus one for every Impulse except the first targeting an entity.",
|
||||
|
@ -912,14 +945,14 @@
|
|||
"hexcasting.entry.blockworks": "Blockworks",
|
||||
"hexcasting.page.blockworks.place_block": "Remove a location from the stack, then pick a block item and place it at the given location.$(br)Costs a negligible amount of _media.",
|
||||
"hexcasting.page.blockworks.break_block": "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 a bit more than one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.create_water": "Summon a block of water (or insert a bucket's worth) into a block at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.destroy_water": "Destroy a great deal of liquid (not just water) around the given position. Costs about two $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.blockworks.create_water": "Summon a block of water (or insert up to a bucket's worth) into a block at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.destroy_water": "Drains either a liquid container at, or a body of liquid around, the given position. Costs about two $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.blockworks.conjure_block": "Conjure an ethereal, but solid, block that sparkles with my pigment at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.conjure_light": "Conjure a magical light that softly glows with my pigment at the given position. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.bonemeal": "Encourage a plant or sapling at the target position to grow, as if $(item)Bonemeal/$ was applied. Costs a bit more than one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.edify": "Forcibly infuse _media into the sapling at the target position, causing it to grow into an $(l:items/edified)$(thing)Edified Tree/$. Costs about one $(l:items/amethyst)$(item)Charged Crystal/$.",
|
||||
"hexcasting.page.blockworks.edify": "Forcibly infuse _media into the sapling at the target position, causing it to grow into an $(l:items/edified)$(thing)Edified Tree/$. Costs about one $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.blockworks.ignite": "Start a fire on top of the given location, as if a $(item)Fire Charge/$ was applied. Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
"hexcasting.page.blockworks.extinguish": "Extinguish blocks in a large area. Costs about six $(l:items/amethyst)$(item)Amethyst Dust/$s.",
|
||||
"hexcasting.page.blockworks.extinguish": "Extinguish blocks in a large area. Costs about six $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
|
||||
"hexcasting.entry.nadirs": "Nadirs",
|
||||
"hexcasting.page.nadirs.1": "This family of spells all impart a negative potion effect upon an entity. They all take an entity, the recipient, and one or two numbers, the first being the duration and the second, if present, being the potency (starting at 1).$(br2)Each one has a \"base cost;\" the actual cost is equal to that base cost, multiplied by the potency squared.",
|
||||
|
@ -950,7 +983,7 @@
|
|||
|
||||
"hexcasting.page.colorize": "I must be holding a $(l:items/pigments)$(item)Pigment/$ in my other hand to cast this spell. When I do, it will consume the dye and permanently change my mind's coloration (at least, until I cast the spell again). Costs about one $(l:items/amethyst)$(item)Amethyst Dust/$.",
|
||||
|
||||
"hexcasting.page.create_lava.1": "Summon a block of lava or insert a bucket's worth into a block at the given position. Costs about one $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.create_lava.1": "Summon a block of lava (or insert up to a bucket's worth) into a block at the given position. Costs about one $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
"hexcasting.page.create_lava.2": "It may be advisable to keep my knowledge of this spell secret. A certain faction of botanists get... touchy about it, or so I've heard.$(br2)Well, no one said tracing the deep secrets of the universe was going to be an easy time.",
|
||||
|
||||
"hexcasting.entry.weather_manip": "Weather Manipulation",
|
||||
|
@ -962,7 +995,7 @@
|
|||
"hexcasting.page.flight.2": "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 one quarter of an $(l:items/amethyst)$(item)Amethyst Dust/$, per meter of radius, per second in flight.",
|
||||
|
||||
"hexcasting.page.teleport.1": "Far more powerful than $(l:patterns/spells/basic#hexcasting:blink)$(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.",
|
||||
"hexcasting.page.teleport.2": "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 $(l:items/amethyst)$(item)Charged Amethyst/$.$(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, and tends to splatter everywhere at the destination.",
|
||||
"hexcasting.page.teleport.2": "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 $(l:items/amethyst)$(item)Charged Amethyst/$.$(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, and tends to splatter everywhere at the destination. In addition, the target will be forcibly removed from anything inanimate they are riding or sitting on ... but I've read scraps that suggest animals can come along for the ride, so to speak.",
|
||||
|
||||
"hexcasting.entry.zeniths": "Zeniths",
|
||||
"hexcasting.page.zeniths.1": "This family of spells all impart a positive potion effect upon an entity, similar to the $(l:patterns/spells/nadirs)$(action)Nadirs/$. However, these have their _media costs increase with the $(italic)cube/$ of the potency.",
|
||||
|
@ -988,13 +1021,13 @@
|
|||
|
||||
"hexcasting.entry.interop.gravity": "Gravity Changer",
|
||||
"hexcasting.page.interop.gravity.1": "I have discovered actions to get and set an entity's gravity. I find them interesting, if slightly nauseating.$(br2)Interestingly, although $(l:patterns/great_spells/flight)$(action)Flight/$ is a great spell, and manipulates gravity similarly, these are not. It baffles me why... Perhaps the mod developer wanted players to have fun, for once.",
|
||||
"hexcasting.page.interop.gravity.get": "Get the main direction gravity pulls the given entity in, as a unit vector. For most entities, this will be down: [0, -1, 0].",
|
||||
"hexcasting.page.interop.gravity.set": "Set the main direction gravity pulls the given entity in. The given vector will be coerced into the nearest axis, as per $(l:patterns/math#hexcasting:coerce_axial)$(action)Axial Purification/$. Costs about 1 $(item)Charged Amethyst Crystal/$.",
|
||||
"hexcasting.page.interop.gravity.get": "Get the main direction gravity pulls the given entity in, as a unit vector. For most entities, this will be down, <0, -1, 0>.",
|
||||
"hexcasting.page.interop.gravity.set": "Set the main direction gravity pulls the given entity in. The given vector will be coerced into the nearest axis, as per $(l:patterns/math#hexcasting:coerce_axial)$(action)Axial Purification/$. Costs about one $(l:items/amethyst)$(item)Charged Amethyst/$.",
|
||||
|
||||
"hexcasting.entry.interop.pehkui": "Pehkui",
|
||||
"hexcasting.page.interop.pehkui.1": "I have discovered methods of changing the size of entities, and querying how much larger or smaller they are than normal.",
|
||||
"hexcasting.page.interop.pehkui.get": "Get the scale of the entity, as a proportion of their normal size. For most entities, this will be 1.",
|
||||
"hexcasting.page.interop.pehkui.set": "Set the scale of the entity, passing in a proportion of their normal size. Costs about 1 $(item)Amethyst Shard/$.",
|
||||
"hexcasting.page.interop.pehkui.set": "Set the scale of the entity, passing in a proportion of their normal size. Costs about one $(l:items/amethyst)$(item)Amethyst Shard/$.",
|
||||
|
||||
"": ""
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 203 B |
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 147 B |
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
|
@ -8,7 +8,7 @@
|
|||
"pages": [
|
||||
{
|
||||
"type": "hexcasting:manual_pattern",
|
||||
"header": "hexcasting.spell.hexcasting:const/vec/x",
|
||||
"op_id": "hexcasting:const/vec/x",
|
||||
"anchor": "hexcasting:const/vec/x",
|
||||
"input": "",
|
||||
"output": "vector",
|
||||
|
@ -28,7 +28,7 @@
|
|||
},
|
||||
{
|
||||
"type": "hexcasting:manual_pattern",
|
||||
"header": "hexcasting.spell.hexcasting:const/vec/y",
|
||||
"op_id": "hexcasting:const/vec/y",
|
||||
"anchor": "hexcasting:const/vec/y",
|
||||
"input": "",
|
||||
"output": "vector",
|
||||
|
@ -48,7 +48,7 @@
|
|||
},
|
||||
{
|
||||
"type": "hexcasting:manual_pattern",
|
||||
"header": "hexcasting.spell.hexcasting:const/vec/z",
|
||||
"op_id": "hexcasting:const/vec/z",
|
||||
"anchor": "hexcasting:const/vec/z",
|
||||
"input": "",
|
||||
"output": "vector",
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
{
|
||||
"type": "hexcasting:pattern",
|
||||
"op_id": "hexcasting:sentinel/create/great",
|
||||
"text": "hexcasting.page.greater_sentinel.1"
|
||||
"text": "hexcasting.page.greater_sentinel.1",
|
||||
"input": "vector",
|
||||
"output": ""
|
||||
},
|
||||
{
|
||||
"type": "patchouli:text",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"pages": [
|
||||
{
|
||||
"type": "hexcasting:manual_pattern",
|
||||
"header": "hexcasting.page.numbers.1.header",
|
||||
"op_id": "hexcasting:number",
|
||||
"anchor": "Numbers",
|
||||
"input": "",
|
||||
"output": "number",
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
},
|
||||
{
|
||||
"type": "hexcasting:manual_pattern",
|
||||
"header": "hexcasting.page.stackmanip.mask.header",
|
||||
"anchor": "Numbers",
|
||||
"op_id": "hexcasting:mask",
|
||||
"anchor": "hexcasting:mask",
|
||||
"input": "many",
|
||||
"output": "many",
|
||||
"text": "hexcasting.page.stackmanip.mask.1",
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"processor": "at.petrak.hexcasting.interop.patchouli.PatternProcessor",
|
||||
"components": [
|
||||
{
|
||||
"type": "patchouli:header",
|
||||
"text": "#header",
|
||||
"text": "#translation_key",
|
||||
"x": -1,
|
||||
"y": -1
|
||||
},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"processor": "at.petrak.hexcasting.interop.patchouli.PatternProcessor",
|
||||
"components": [
|
||||
{
|
||||
"type": "patchouli:header",
|
||||
"text": "#header",
|
||||
"text": "#translation_key",
|
||||
"x": -1,
|
||||
"y": -1
|
||||
},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"processor": "at.petrak.hexcasting.interop.patchouli.PatternProcessor",
|
||||
"components": [
|
||||
{
|
||||
"type": "patchouli:header",
|
||||
"text": "hexcasting.spell.#op_id#",
|
||||
"text": "#translation_key",
|
||||
"x": -1,
|
||||
"y": -1
|
||||
},
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
{
|
||||
"id": "create:contraption",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "create:stationary_contraption",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "create:gantry_contraption",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "create:carriage_contraption",
|
||||
"required": false
|
||||
},
|
||||
"minecraft:pig",
|
||||
"minecraft:strider",
|
||||
"minecraft:horse",
|
||||
"minecraft:skeleton_horse",
|
||||
"minecraft:zombie_horse",
|
||||
"minecraft:mule",
|
||||
"minecraft:donkey",
|
||||
"minecraft:llama",
|
||||
"minecraft:trader_llama"
|
||||
]
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue