diff --git a/src/client/java/dev/enjarai/trickster/ModKeyBindings.java b/src/client/java/dev/enjarai/trickster/ModKeyBindings.java new file mode 100644 index 00000000..8c6c78e6 --- /dev/null +++ b/src/client/java/dev/enjarai/trickster/ModKeyBindings.java @@ -0,0 +1,33 @@ +package dev.enjarai.trickster; + +import dev.enjarai.trickster.item.ModItems; +import dev.enjarai.trickster.net.MladyPacket; +import dev.enjarai.trickster.net.ModNetworking; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.entity.EquipmentSlot; +import org.lwjgl.glfw.GLFW; + +public class ModKeyBindings { + public static final KeyBinding TAKE_HAT = new KeyBinding("key.trickster.take_hat", GLFW.GLFW_KEY_G, "trickster"); + + public static void register() { + KeyBindingHelper.registerKeyBinding(TAKE_HAT); + + ClientTickEvents.END_CLIENT_TICK.register(client -> { + var player = client.player; + if (player != null && client.currentScreen == null) { + if (TAKE_HAT.isPressed()) { + if (player.getEquippedStack(EquipmentSlot.HEAD).isIn(ModItems.HOLDABLE_HAT) && player.getEquippedStack(EquipmentSlot.OFFHAND).isEmpty()) { + ModNetworking.MLADY.clientHandle().send(new MladyPacket(true)); + } + } else { + if (player.getEquippedStack(EquipmentSlot.HEAD).isEmpty() && player.getOffHandStack().isIn(ModItems.HOLDABLE_HAT)) { + ModNetworking.MLADY.clientHandle().send(new MladyPacket(false)); + } + } + } + }); + } +} diff --git a/src/client/java/dev/enjarai/trickster/TricksterClient.java b/src/client/java/dev/enjarai/trickster/TricksterClient.java index cc8d83e5..e4768759 100644 --- a/src/client/java/dev/enjarai/trickster/TricksterClient.java +++ b/src/client/java/dev/enjarai/trickster/TricksterClient.java @@ -9,6 +9,7 @@ public class TricksterClient implements ClientModInitializer { @Override public void onInitializeClient() { ModHandledScreens.register(); + ModKeyBindings.register(); UIParsing.registerFactory(Trickster.id("glyph"), GlyphComponent::parse); } diff --git a/src/client/java/dev/enjarai/trickster/screen/ModHandledScreens.java b/src/client/java/dev/enjarai/trickster/screen/ModHandledScreens.java index 131127a3..a20cc753 100644 --- a/src/client/java/dev/enjarai/trickster/screen/ModHandledScreens.java +++ b/src/client/java/dev/enjarai/trickster/screen/ModHandledScreens.java @@ -5,5 +5,6 @@ public class ModHandledScreens { public static void register() { HandledScreens.register(ModScreenHandlers.SCROLL_AND_QUILL, ScrollAndQuillScreen::new); + HandledScreens.register(ModScreenHandlers.SCROLL_CONTAINER, ScrollContainerScreen::new); } } diff --git a/src/client/java/dev/enjarai/trickster/screen/ScrollContainerScreen.java b/src/client/java/dev/enjarai/trickster/screen/ScrollContainerScreen.java new file mode 100644 index 00000000..8f330b19 --- /dev/null +++ b/src/client/java/dev/enjarai/trickster/screen/ScrollContainerScreen.java @@ -0,0 +1,36 @@ +package dev.enjarai.trickster.screen; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +@Environment(EnvType.CLIENT) +public class ScrollContainerScreen extends HandledScreen implements ScreenHandlerProvider { + private static final Identifier TEXTURE = Identifier.ofVanilla("textures/gui/container/generic_54.png"); + private final int rows; + + public ScrollContainerScreen(ScrollContainerScreenHandler handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + this.rows = handler.getRows(); + this.backgroundHeight = 114 + this.rows * 18; + this.playerInventoryTitleY = this.backgroundHeight - 94; + } + + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + this.drawMouseoverTooltip(context, mouseX, mouseY); + } + + protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { + int i = (this.width - this.backgroundWidth) / 2; + int j = (this.height - this.backgroundHeight) / 2; + context.drawTexture(TEXTURE, i, j, 0, 0, this.backgroundWidth, this.rows * 18 + 17); + context.drawTexture(TEXTURE, i, j + this.rows * 18 + 17, 0, 126, this.backgroundWidth, 96); + } +} + diff --git a/src/client/java/dev/enjarai/trickster/screen/SpellPartWidget.java b/src/client/java/dev/enjarai/trickster/screen/SpellPartWidget.java index 8e809136..b28980b7 100644 --- a/src/client/java/dev/enjarai/trickster/screen/SpellPartWidget.java +++ b/src/client/java/dev/enjarai/trickster/screen/SpellPartWidget.java @@ -32,6 +32,7 @@ public class SpellPartWidget extends AbstractParentElement implements Drawable, public static final Pattern DELETE_CIRCLE_GLYPH = Pattern.of(0, 4, 8); public static final Pattern CLEAR_DISABLED_GLYPH = Pattern.of(0, 4, 8, 5, 2, 1, 0, 3, 6, 7, 8); public static final Pattern COPY_OFFHAND_LITERAL = Pattern.of(4, 0, 1, 4, 2, 1); + public static final Pattern COPY_OFFHAND_LITERAL_INNER = Pattern.of(1, 2, 4, 1, 0, 4, 7); public static final Pattern COPY_OFFHAND_EXECUTE = Pattern.of(4, 3, 0, 4, 5, 2, 4, 1); private SpellPart spellPart; @@ -426,6 +427,8 @@ protected void stopDrawing() { } else { setSubPartInTree(drawingPart, Optional.of(otherHandSpellSupplier.get().deepClone()), spellPart); } + } else if (compiled.equals(COPY_OFFHAND_LITERAL_INNER)) { + drawingPart.glyph = otherHandSpellSupplier.get().deepClone(); } else if (compiled.equals(COPY_OFFHAND_EXECUTE)) { toBeReplaced = drawingPart; initializeReplace.run(); diff --git a/src/main/java/dev/enjarai/trickster/Trickster.java b/src/main/java/dev/enjarai/trickster/Trickster.java index af1961bc..45225fa8 100644 --- a/src/main/java/dev/enjarai/trickster/Trickster.java +++ b/src/main/java/dev/enjarai/trickster/Trickster.java @@ -3,6 +3,7 @@ import dev.enjarai.trickster.block.ModBlocks; import dev.enjarai.trickster.item.ModItems; import dev.enjarai.trickster.item.component.ModComponents; +import dev.enjarai.trickster.net.ModNetworking; import dev.enjarai.trickster.screen.ModScreenHandlers; import dev.enjarai.trickster.spell.tricks.Tricks; import net.fabricmc.api.ModInitializer; @@ -28,6 +29,7 @@ public void onInitialize() { ModComponents.register(); ModItems.register(); ModScreenHandlers.register(); + ModNetworking.register(); Tricks.register(); } diff --git a/src/main/java/dev/enjarai/trickster/item/EvaluationMirrorItem.java b/src/main/java/dev/enjarai/trickster/item/EvaluationMirrorItem.java new file mode 100644 index 00000000..d039eae5 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/item/EvaluationMirrorItem.java @@ -0,0 +1,50 @@ +package dev.enjarai.trickster.item; + +import dev.enjarai.trickster.item.component.ModComponents; +import dev.enjarai.trickster.item.component.SpellComponent; +import dev.enjarai.trickster.screen.ScrollAndQuillScreenHandler; +import dev.enjarai.trickster.spell.SpellPart; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.text.Text; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; + +public class EvaluationMirrorItem extends Item { + public EvaluationMirrorItem(Settings settings) { + super(settings); + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + var stack = user.getStackInHand(hand); + var otherStack = user.getStackInHand(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND); + + if (!user.isSneaking()) { + user.openHandledScreen(new NamedScreenHandlerFactory() { + @Override + public Text getDisplayName() { + return Text.translatable("trickster.screen.mirror_of_evaluation"); + } + + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) { + return new ScrollAndQuillScreenHandler( + syncId, playerInventory, stack, otherStack, + hand == Hand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND, true + ); + } + }); + } else { + stack.set(ModComponents.SPELL, new SpellComponent(new SpellPart())); + } + + return TypedActionResult.success(stack); + } +} diff --git a/src/main/java/dev/enjarai/trickster/item/ModItems.java b/src/main/java/dev/enjarai/trickster/item/ModItems.java index 00077afc..7bd18f9d 100644 --- a/src/main/java/dev/enjarai/trickster/item/ModItems.java +++ b/src/main/java/dev/enjarai/trickster/item/ModItems.java @@ -8,6 +8,8 @@ import net.minecraft.item.Item; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.tag.TagKey; public class ModItems { public static final LavenderBookItem TOME_OF_TOMFOOLERY = LavenderBookItem.registerForBook( @@ -15,6 +17,15 @@ public class ModItems { public static final ScrollAndQuillItem SCROLL_AND_QUILL = register("scroll_and_quill", new ScrollAndQuillItem(new Item.Settings().maxCount(16) .component(ModComponents.SPELL, new SpellComponent(new SpellPart())))); + public static final EvaluationMirrorItem MIRROR_OF_EVALUATION = register("mirror_of_evaluation", + new EvaluationMirrorItem(new Item.Settings().maxCount(1) + .component(ModComponents.SPELL, new SpellComponent(new SpellPart())))); + public static final TrickHatItem TOP_HAT = register("top_hat", + new TrickHatItem(new Item.Settings().maxCount(1))); + + public static final TagKey CAN_EVALUATE_DYNAMICALLY = TagKey.of(RegistryKeys.ITEM, Trickster.id("can_evaluate_dynamically")); + public static final TagKey HOLDABLE_HAT = TagKey.of(RegistryKeys.ITEM, Trickster.id("holdable_hat")); + public static final TagKey SCROLLS = TagKey.of(RegistryKeys.ITEM, Trickster.id("scrolls")); private static T register(String name, T item) { return Registry.register(Registries.ITEM, Trickster.id(name), item); diff --git a/src/main/java/dev/enjarai/trickster/item/ScrollAndQuillItem.java b/src/main/java/dev/enjarai/trickster/item/ScrollAndQuillItem.java index 12c49011..29d22744 100644 --- a/src/main/java/dev/enjarai/trickster/item/ScrollAndQuillItem.java +++ b/src/main/java/dev/enjarai/trickster/item/ScrollAndQuillItem.java @@ -2,7 +2,9 @@ import dev.enjarai.trickster.item.component.ModComponents; import dev.enjarai.trickster.screen.ScrollAndQuillScreenHandler; +import dev.enjarai.trickster.spell.PlayerSpellContext; import dev.enjarai.trickster.spell.SpellContext; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.Item; @@ -24,6 +26,7 @@ public ScrollAndQuillItem(Settings settings) { public TypedActionResult use(World world, PlayerEntity user, Hand hand) { var stack = user.getStackInHand(hand); var otherStack = user.getStackInHand(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND); + var slot = hand == Hand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND; if (user.isSneaking()) { user.openHandledScreen(new NamedScreenHandlerFactory() { @@ -34,13 +37,13 @@ public Text getDisplayName() { @Override public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) { - return new ScrollAndQuillScreenHandler(syncId, playerInventory, stack, otherStack); + return new ScrollAndQuillScreenHandler(syncId, playerInventory, stack, otherStack, slot, false); } }); - } else if (!world.isClient()) { + } else if (!world.isClient()) { // TODO remove var spell = stack.get(ModComponents.SPELL); if (spell != null) { - spell.spell().runSafely(new SpellContext((ServerPlayerEntity) user)); + spell.spell().runSafely(new PlayerSpellContext((ServerPlayerEntity) user, slot)); } } diff --git a/src/main/java/dev/enjarai/trickster/item/TrickHatItem.java b/src/main/java/dev/enjarai/trickster/item/TrickHatItem.java new file mode 100644 index 00000000..e21ae477 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/item/TrickHatItem.java @@ -0,0 +1,30 @@ +package dev.enjarai.trickster.item; + +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Equipment; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; + +public class TrickHatItem extends Item implements Equipment { + public TrickHatItem(Settings settings) { + super(settings); + } + + @Override + public EquipmentSlot getSlotType() { + return EquipmentSlot.HEAD; + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + var stack = user.getStackInHand(hand); + + // TODO + + return TypedActionResult.success(stack); + } +} diff --git a/src/main/java/dev/enjarai/trickster/net/MladyPacket.java b/src/main/java/dev/enjarai/trickster/net/MladyPacket.java new file mode 100644 index 00000000..53cf17c0 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/net/MladyPacket.java @@ -0,0 +1,4 @@ +package dev.enjarai.trickster.net; + +public record MladyPacket(boolean hold) { +} diff --git a/src/main/java/dev/enjarai/trickster/net/ModNetworking.java b/src/main/java/dev/enjarai/trickster/net/ModNetworking.java new file mode 100644 index 00000000..330873db --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/net/ModNetworking.java @@ -0,0 +1,32 @@ +package dev.enjarai.trickster.net; + +import dev.enjarai.trickster.Trickster; +import dev.enjarai.trickster.item.ModItems; +import io.wispforest.owo.network.OwoNetChannel; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.item.ItemStack; + +public class ModNetworking { + public static final OwoNetChannel MLADY = OwoNetChannel.create(Trickster.id("mlady")); + + public static void register() { + MLADY.registerServerbound(MladyPacket.class, (packet, access) -> { + var player = access.player(); + var inventory = player.getInventory(); + + if (packet.hold()) { + if (player.getEquippedStack(EquipmentSlot.HEAD).isIn(ModItems.HOLDABLE_HAT) && player.getOffHandStack().isEmpty()) { + var headStack = inventory.getArmorStack(EquipmentSlot.HEAD.getEntitySlotId()); + inventory.armor.set(EquipmentSlot.HEAD.getEntitySlotId(), ItemStack.EMPTY); + inventory.offHand.set(0, headStack); + } + } else { + if (player.getEquippedStack(EquipmentSlot.HEAD).isEmpty() && player.getOffHandStack().isIn(ModItems.HOLDABLE_HAT)) { + var offHandStack = inventory.offHand.getFirst(); + inventory.offHand.set(0, ItemStack.EMPTY); + inventory.armor.set(EquipmentSlot.HEAD.getEntitySlotId(), offHandStack); + } + } + }); + } +} diff --git a/src/main/java/dev/enjarai/trickster/screen/ModScreenHandlers.java b/src/main/java/dev/enjarai/trickster/screen/ModScreenHandlers.java index 654ffddd..b69fda1c 100644 --- a/src/main/java/dev/enjarai/trickster/screen/ModScreenHandlers.java +++ b/src/main/java/dev/enjarai/trickster/screen/ModScreenHandlers.java @@ -9,8 +9,11 @@ public class ModScreenHandlers { public static final ScreenHandlerType SCROLL_AND_QUILL = new ScreenHandlerType<>(ScrollAndQuillScreenHandler::new, FeatureSet.empty()); + public static final ScreenHandlerType SCROLL_CONTAINER = + new ScreenHandlerType<>(ScrollContainerScreenHandler::new, FeatureSet.empty()); public static void register() { Registry.register(Registries.SCREEN_HANDLER, Trickster.id("scroll_and_quill"), SCROLL_AND_QUILL); + Registry.register(Registries.SCREEN_HANDLER, Trickster.id("scroll_container"), SCROLL_CONTAINER); } } diff --git a/src/main/java/dev/enjarai/trickster/screen/ScrollAndQuillScreenHandler.java b/src/main/java/dev/enjarai/trickster/screen/ScrollAndQuillScreenHandler.java index 738e9496..7815cd19 100644 --- a/src/main/java/dev/enjarai/trickster/screen/ScrollAndQuillScreenHandler.java +++ b/src/main/java/dev/enjarai/trickster/screen/ScrollAndQuillScreenHandler.java @@ -1,18 +1,22 @@ package dev.enjarai.trickster.screen; +import dev.enjarai.trickster.item.ModItems; import dev.enjarai.trickster.item.component.ModComponents; import dev.enjarai.trickster.item.component.SpellComponent; import dev.enjarai.trickster.spell.Fragment; +import dev.enjarai.trickster.spell.PlayerSpellContext; import dev.enjarai.trickster.spell.SpellContext; import dev.enjarai.trickster.spell.SpellPart; import dev.enjarai.trickster.spell.fragment.VoidFragment; import io.wispforest.endec.Endec; import io.wispforest.owo.client.screens.SyncedProperty; +import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.screen.ScreenHandler; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Hand; import java.util.function.Consumer; @@ -24,14 +28,19 @@ public class ScrollAndQuillScreenHandler extends ScreenHandler { public Consumer replacerCallback; + public final EquipmentSlot slot; + public final boolean greedyEvaluation; + public ScrollAndQuillScreenHandler(int syncId, PlayerInventory playerInventory) { - this(syncId, playerInventory, null, null); + this(syncId, playerInventory, null, null, null, false); } - public ScrollAndQuillScreenHandler(int syncId, PlayerInventory playerInventory, ItemStack scrollStack, ItemStack otherHandStack) { + public ScrollAndQuillScreenHandler(int syncId, PlayerInventory playerInventory, ItemStack scrollStack, ItemStack otherHandStack, EquipmentSlot slot, boolean greedyEvaluation) { super(ModScreenHandlers.SCROLL_AND_QUILL, syncId); this.scrollStack = scrollStack; + this.slot = slot; + this.greedyEvaluation = greedyEvaluation; if (scrollStack != null) { var spell = scrollStack.get(ModComponents.SPELL); @@ -58,7 +67,17 @@ public ScrollAndQuillScreenHandler(int syncId, PlayerInventory playerInventory, public void updateSpell(SpellPart spell) { if (scrollStack != null) { - scrollStack.set(ModComponents.SPELL, new SpellComponent(spell)); + var server = player().getServer(); + if (server != null) { + server.execute(() -> { + if (greedyEvaluation) { + spell.runSafely(new PlayerSpellContext((ServerPlayerEntity) player(), slot).setDestructive(), err -> {}); + this.spell.set(spell); + } + + scrollStack.set(ModComponents.SPELL, new SpellComponent(spell)); + }); + } } else { // var result = SpellPart.CODEC.encodeStart(JsonOps.INSTANCE, spell).result().get(); // Trickster.LOGGER.warn(result.toString()); @@ -70,10 +89,12 @@ public void executeOffhand() { var server = player().getServer(); if (server != null) { server.execute(() -> { - var fragment = otherHandSpell.get() - .runSafely(new SpellContext((ServerPlayerEntity) player())) - .orElse(VoidFragment.INSTANCE); - sendMessage(new Replace(fragment)); + if (player().getInventory().contains(ModItems.CAN_EVALUATE_DYNAMICALLY)) { + var fragment = otherHandSpell.get() + .runSafely(new PlayerSpellContext((ServerPlayerEntity) player(), slot)) + .orElse(VoidFragment.INSTANCE); + sendMessage(new Replace(fragment)); + } }); } else { sendMessage(new ExecuteOffhand()); diff --git a/src/main/java/dev/enjarai/trickster/screen/ScrollContainerScreenHandler.java b/src/main/java/dev/enjarai/trickster/screen/ScrollContainerScreenHandler.java new file mode 100644 index 00000000..199c4887 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/screen/ScrollContainerScreenHandler.java @@ -0,0 +1,105 @@ +package dev.enjarai.trickster.screen; + +import com.mojang.datafixers.util.Pair; +import dev.enjarai.trickster.Trickster; +import dev.enjarai.trickster.item.ModItems; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.PlayerScreenHandler; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; + +public class ScrollContainerScreenHandler extends ScreenHandler { + private final Inventory inventory; + private final int rows; + + public ScrollContainerScreenHandler(int syncId, PlayerInventory playerInventory) { + super(ModScreenHandlers.SCROLL_CONTAINER, syncId); + this.rows = 3; + this.inventory = new SimpleInventory(9 * rows); + inventory.onOpen(playerInventory.player); + int i = (this.rows - 4) * 18; + + for(int j = 0; j < this.rows; ++j) { + for(int k = 0; k < 9; ++k) { + this.addSlot(new ScrollSlot(inventory, k + j * 9, 8 + k * 18, 18 + j * 18)); + } + } + + for(int j = 0; j < 3; ++j) { + for(int k = 0; k < 9; ++k) { + this.addSlot(new ScrollSlot(playerInventory, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i)); + } + } + + for(int j = 0; j < 9; ++j) { + this.addSlot(new ScrollSlot(playerInventory, j, 8 + j * 18, 161 + i)); + } + } + + @Override + public boolean canUse(PlayerEntity player) { + return this.inventory.canPlayerUse(player); + } + + @Override + public ItemStack quickMove(PlayerEntity player, int slot) { + ItemStack itemStack = ItemStack.EMPTY; + Slot slot2 = this.slots.get(slot); + if (slot2.hasStack()) { + ItemStack itemStack2 = slot2.getStack(); + itemStack = itemStack2.copy(); + if (slot < this.rows * 9) { + if (!this.insertItem(itemStack2, this.rows * 9, this.slots.size(), true)) { + return ItemStack.EMPTY; + } + } else if (!this.insertItem(itemStack2, 0, this.rows * 9, false)) { + return ItemStack.EMPTY; + } + + if (itemStack2.isEmpty()) { + slot2.setStack(ItemStack.EMPTY); + } else { + slot2.markDirty(); + } + } + + return itemStack; + } + + @Override + public void onClosed(PlayerEntity player) { + super.onClosed(player); + this.inventory.onClose(player); + } + + public Inventory getInventory() { + return this.inventory; + } + + public int getRows() { + return this.rows; + } + + static class ScrollSlot extends Slot { + public ScrollSlot(Inventory inventory, int index, int x, int y) { + super(inventory, index, x, y); + } + + @Override + public boolean canInsert(ItemStack stack) { + return stack.isIn(ModItems.SCROLLS); + } + + @Nullable + @Override + public Pair getBackgroundSprite() { + return Pair.of(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, Trickster.id("item/empty_scroll_slot")); + } + } +} diff --git a/src/main/java/dev/enjarai/trickster/spell/PlayerSpellContext.java b/src/main/java/dev/enjarai/trickster/spell/PlayerSpellContext.java new file mode 100644 index 00000000..f85cc6cc --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/spell/PlayerSpellContext.java @@ -0,0 +1,40 @@ +package dev.enjarai.trickster.spell; + +import dev.enjarai.trickster.item.component.ModComponents; +import dev.enjarai.trickster.item.component.SpellComponent; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.Optional; + +public class PlayerSpellContext extends SpellContext { + private final ServerPlayerEntity player; + private final EquipmentSlot slot; + + public PlayerSpellContext(ServerPlayerEntity player, EquipmentSlot slot) { + super(); + this.player = player; + this.slot = slot; + } + + @Override + public Optional getPlayer() { + return Optional.of(player); + } + + @Override + public Optional getOtherHandSpellStack() { + if (slot == EquipmentSlot.MAINHAND) { + return Optional.ofNullable(player.getOffHandStack()).filter(s -> s.contains(ModComponents.SPELL)); + } else if (slot == EquipmentSlot.OFFHAND) { + return Optional.ofNullable(player.getMainHandStack()).filter(s -> s.contains(ModComponents.SPELL)); + } + + return Optional + .ofNullable(player.getMainHandStack()) + .filter(s -> s.contains(ModComponents.SPELL)) + .or(() -> Optional.ofNullable(player.getOffHandStack()) + .filter(s -> s.contains(ModComponents.SPELL))); + } +} diff --git a/src/main/java/dev/enjarai/trickster/spell/SpellContext.java b/src/main/java/dev/enjarai/trickster/spell/SpellContext.java index bc49cd7d..dd210017 100644 --- a/src/main/java/dev/enjarai/trickster/spell/SpellContext.java +++ b/src/main/java/dev/enjarai/trickster/spell/SpellContext.java @@ -2,22 +2,17 @@ import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; import dev.enjarai.trickster.spell.tricks.blunder.RecursionLimitReachedBlunder; +import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; -import org.jetbrains.annotations.Nullable; import java.util.*; -public class SpellContext { +public abstract class SpellContext { public static final int MAX_RECURSION_DEPTH = 1000; - @Nullable - private final ServerPlayerEntity player; private final Deque> partGlyphStack = new ArrayDeque<>(); private int recursions = 0; - - public SpellContext(@Nullable ServerPlayerEntity player) { - this.player = player; - } + private boolean destructive = false; public void pushPartGlyph(List fragments) throws BlunderException { partGlyphStack.push(fragments); @@ -41,6 +36,19 @@ public List peekPartGlyph() { } public Optional getPlayer() { - return Optional.ofNullable(player); + return Optional.empty(); + } + + public Optional getOtherHandSpellStack() { + return Optional.empty(); + } + + public boolean isDestructive() { + return destructive; + } + + public SpellContext setDestructive() { + destructive = true; + return this; } } diff --git a/src/main/java/dev/enjarai/trickster/spell/SpellPart.java b/src/main/java/dev/enjarai/trickster/spell/SpellPart.java index 91c45c98..9f1da97e 100644 --- a/src/main/java/dev/enjarai/trickster/spell/SpellPart.java +++ b/src/main/java/dev/enjarai/trickster/spell/SpellPart.java @@ -6,6 +6,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import dev.enjarai.trickster.spell.fragment.BooleanFragment; import dev.enjarai.trickster.spell.fragment.FragmentType; +import dev.enjarai.trickster.spell.fragment.VoidFragment; import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; import io.wispforest.endec.Endec; import io.wispforest.owo.serialization.CodecUtils; @@ -15,6 +16,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Collectors; public final class SpellPart implements Fragment { @@ -62,21 +64,33 @@ public Fragment run(SpellContext ctx) throws BlunderException { fragments.add(part.map(p -> p.run(ctx))); } - return glyph.activateAsGlyph(ctx, fragments); + var value = glyph.activateAsGlyph(ctx, fragments); + + if (ctx.isDestructive() && !value.equals(VoidFragment.INSTANCE)) { + if (glyph != value) { + subParts.clear(); + } + glyph = value; + } + + return value; } - public Optional runSafely(SpellContext ctx) throws BlunderException { + public Optional runSafely(SpellContext ctx, Consumer onError) { try { return Optional.of(run(ctx)); } catch (BlunderException e) { - ctx.getPlayer().ifPresent(player -> player.sendMessage(e.createMessage())); + onError.accept(e.createMessage()); } catch (Exception e) { - ctx.getPlayer().ifPresent(player -> player.sendMessage( - Text.literal("Uncaught exception in spell: " + e.getMessage()))); + onError.accept(Text.literal("Uncaught exception in spell: " + e.getMessage())); } return Optional.empty(); } + public Optional runSafely(SpellContext ctx) { + return runSafely(ctx, err -> ctx.getPlayer().ifPresent(player -> player.sendMessage(err))); + } + public Fragment getGlyph() { return glyph; } diff --git a/src/main/resources/assets/trickster/models/item/mirror_of_evaluation.json b/src/main/resources/assets/trickster/models/item/mirror_of_evaluation.json new file mode 100644 index 00000000..1cd4cb17 --- /dev/null +++ b/src/main/resources/assets/trickster/models/item/mirror_of_evaluation.json @@ -0,0 +1,18 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "trickster:item/mirror_of_evaluation" + }, + "display": { + "thirdperson_righthand": { + "rotation": [0, 0, 45], + "scale": [0.6, 0.6, 0.6], + "translation": [0, 4, 0] + }, + "thirdperson_lefthand": { + "rotation": [0, 0, -45], + "scale": [0.6, 0.6, 0.6], + "translation": [0, 4, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/trickster/models/item/top_hat.json b/src/main/resources/assets/trickster/models/item/top_hat.json new file mode 100644 index 00000000..6969680c --- /dev/null +++ b/src/main/resources/assets/trickster/models/item/top_hat.json @@ -0,0 +1,73 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [32, 32], + "textures": { + "0": "trickster:item/top_hat", + "particle": "trickster:item/top_hat" + }, + "elements": [ + { + "name": "crown", + "from": [4, 1, 4], + "to": [12, 11, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [4, 1, 4]}, + "faces": { + "north": {"uv": [6, 0, 10, 5], "texture": "#0"}, + "east": {"uv": [6, 5, 10, 10], "texture": "#0"}, + "south": {"uv": [10, 0, 14, 5], "texture": "#0"}, + "west": {"uv": [10, 5, 14, 10], "texture": "#0"}, + "up": {"uv": [10, 14, 6, 10], "texture": "#0"}, + "down": {"uv": [14, 10, 10, 14], "texture": "#0"} + } + }, + { + "name": "brim", + "from": [2, 0, 2], + "to": [14, 1, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [2, 0, 2]}, + "faces": { + "north": {"uv": [0, 12, 6, 12.5], "texture": "#0"}, + "east": {"uv": [0, 12.5, 6, 13], "texture": "#0"}, + "south": {"uv": [0, 13, 6, 13.5], "texture": "#0"}, + "west": {"uv": [0, 13.5, 6, 14], "texture": "#0"}, + "up": {"uv": [6, 6, 0, 0], "texture": "#0"}, + "down": {"uv": [6, 6, 0, 12], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [-109.78, -24, 1.09], + "translation": [0, 0, -4.5], + "scale": [0.75, 0.75, 0.75] + }, + "thirdperson_lefthand": { + "rotation": [-109.78, -24, 1.09], + "translation": [0, 0, -4.5], + "scale": [0.75, 0.75, 0.75] + }, + "firstperson_righthand": { + "rotation": [-165.53, -24, 1.09], + "translation": [0, -2.25, -1], + "scale": [0.75, 0.75, 0.75] + }, + "firstperson_lefthand": { + "rotation": [-165.53, -24, 1.09], + "translation": [0, -2.25, -1], + "scale": [0.75, 0.75, 0.75] + }, + "ground": { + "translation": [0, 4.25, 0] + }, + "gui": { + "rotation": [18, 57, 0], + "translation": [0, 2.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "head": { + "rotation": [0.75, 2.25, -0.04], + "translation": [0, 17.75, 0], + "scale": [1.6, 1.6, 1.6] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/trickster/textures/item/empty_scroll_slot.png b/src/main/resources/assets/trickster/textures/item/empty_scroll_slot.png new file mode 100644 index 00000000..f2ac3ade Binary files /dev/null and b/src/main/resources/assets/trickster/textures/item/empty_scroll_slot.png differ diff --git a/src/main/resources/assets/trickster/textures/item/mirror_of_evaluation.png b/src/main/resources/assets/trickster/textures/item/mirror_of_evaluation.png new file mode 100644 index 00000000..1b869279 Binary files /dev/null and b/src/main/resources/assets/trickster/textures/item/mirror_of_evaluation.png differ diff --git a/src/main/resources/assets/trickster/textures/item/top_hat.png b/src/main/resources/assets/trickster/textures/item/top_hat.png new file mode 100644 index 00000000..b292cb5f Binary files /dev/null and b/src/main/resources/assets/trickster/textures/item/top_hat.png differ diff --git a/src/main/resources/assets/trickster/textures/item/wand.png b/src/main/resources/assets/trickster/textures/item/wand.png new file mode 100644 index 00000000..d82e4cfe Binary files /dev/null and b/src/main/resources/assets/trickster/textures/item/wand.png differ diff --git a/src/main/resources/data/trickster/tags/item/can_evaluate_dynamically.json b/src/main/resources/data/trickster/tags/item/can_evaluate_dynamically.json new file mode 100644 index 00000000..23f8acca --- /dev/null +++ b/src/main/resources/data/trickster/tags/item/can_evaluate_dynamically.json @@ -0,0 +1,5 @@ +{ + "values": [ + "trickster:mirror_of_evaluation" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/trickster/tags/item/holdable_hat.json b/src/main/resources/data/trickster/tags/item/holdable_hat.json new file mode 100644 index 00000000..971f81b3 --- /dev/null +++ b/src/main/resources/data/trickster/tags/item/holdable_hat.json @@ -0,0 +1,5 @@ +{ + "values": [ + "trickster:top_hat" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/trickster/tags/item/scrolls.json b/src/main/resources/data/trickster/tags/item/scrolls.json new file mode 100644 index 00000000..094698e8 --- /dev/null +++ b/src/main/resources/data/trickster/tags/item/scrolls.json @@ -0,0 +1,5 @@ +{ + "values": [ + "trickster:scroll_and_quill" + ] +} \ No newline at end of file