From d57da2b27810954c3c2e412f798bb6e252051e4d Mon Sep 17 00:00:00 2001 From: enjarai Date: Fri, 14 Jun 2024 21:05:42 +0200 Subject: [PATCH] Progress in work --- build.gradle | 6 +++ .../dev/enjarai/trickster/ModKeyBindings.java | 17 ++++++- .../mixin/client/ExampleClientMixin.java | 26 ---------- .../mixin/client/HeldItemRendererMixin.java | 29 +++++++++++ .../trickster/mixin/client/MouseMixin.java | 27 ++++++++++ .../screen/ScrollContainerScreen.java | 18 ++++++- .../resources/trickster.client.mixins.json | 16 +++--- .../dev/enjarai/trickster/item/ModItems.java | 4 +- .../item/component/ModComponents.java | 2 + .../item/component/SelectedSlotComponent.java | 11 ++++ .../enjarai/trickster/net/ModNetworking.java | 48 +++++++++++++++++- .../trickster/net/ScrollInGamePacket.java | 4 ++ .../screen/ScrollContainerScreenHandler.java | 7 +++ .../spell/fragment/NumberFragment.java | 9 ++++ .../spell/fragment/VectorFragment.java | 8 +++ .../trickster/spell/tricks/Tricks.java | 6 +++ .../trickster/spell/tricks/bool/AllTrick.java | 21 ++++++++ .../trickster/spell/tricks/bool/AnyTrick.java | 21 ++++++++ .../spell/tricks/bool/EqualsTrick.java | 29 +++++++++++ .../spell/tricks/{ => bool}/IfElseTrick.java | 3 +- .../spell/tricks/bool/NoneTrick.java | 21 ++++++++ .../spell/tricks/bool/NotEqualsTrick.java | 29 +++++++++++ .../resources/assets/trickster/lang/en_us.yml | 21 ++++++++ .../trickster/textures/gui/scroll_54.png | Bin 0 -> 13290 bytes .../trickster/textures/gui/selected_slot.png | Bin 0 -> 516 bytes .../trickster/textures/item/top_hat.png | Bin 298 -> 378 bytes 26 files changed, 343 insertions(+), 40 deletions(-) delete mode 100644 src/client/java/dev/enjarai/trickster/mixin/client/ExampleClientMixin.java create mode 100644 src/client/java/dev/enjarai/trickster/mixin/client/HeldItemRendererMixin.java create mode 100644 src/client/java/dev/enjarai/trickster/mixin/client/MouseMixin.java create mode 100644 src/main/java/dev/enjarai/trickster/item/component/SelectedSlotComponent.java create mode 100644 src/main/java/dev/enjarai/trickster/net/ScrollInGamePacket.java create mode 100644 src/main/java/dev/enjarai/trickster/spell/tricks/bool/AllTrick.java create mode 100644 src/main/java/dev/enjarai/trickster/spell/tricks/bool/AnyTrick.java create mode 100644 src/main/java/dev/enjarai/trickster/spell/tricks/bool/EqualsTrick.java rename src/main/java/dev/enjarai/trickster/spell/tricks/{ => bool}/IfElseTrick.java (88%) create mode 100644 src/main/java/dev/enjarai/trickster/spell/tricks/bool/NoneTrick.java create mode 100644 src/main/java/dev/enjarai/trickster/spell/tricks/bool/NotEqualsTrick.java create mode 100644 src/main/resources/assets/trickster/lang/en_us.yml create mode 100644 src/main/resources/assets/trickster/textures/gui/scroll_54.png create mode 100644 src/main/resources/assets/trickster/textures/gui/selected_slot.png diff --git a/build.gradle b/build.gradle index dadd0ca8..c1b547bb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id 'fabric-loom' version '1.6-SNAPSHOT' id 'maven-publish' + id 'me.fallenbreath.yamlang' version '1.3.1' } version = project.mod_version @@ -79,6 +80,11 @@ jar { } } +yamlang { + targetSourceSets = [sourceSets.main] + inputDir = "assets/trickster/lang" +} + // configure the maven publication publishing { publications { diff --git a/src/client/java/dev/enjarai/trickster/ModKeyBindings.java b/src/client/java/dev/enjarai/trickster/ModKeyBindings.java index 8c6c78e6..43ab4046 100644 --- a/src/client/java/dev/enjarai/trickster/ModKeyBindings.java +++ b/src/client/java/dev/enjarai/trickster/ModKeyBindings.java @@ -1,10 +1,13 @@ package dev.enjarai.trickster; import dev.enjarai.trickster.item.ModItems; +import dev.enjarai.trickster.item.component.ModComponents; import dev.enjarai.trickster.net.MladyPacket; import dev.enjarai.trickster.net.ModNetworking; +import dev.enjarai.trickster.net.ScrollInGamePacket; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.option.KeyBinding; import net.minecraft.entity.EquipmentSlot; import org.lwjgl.glfw.GLFW; @@ -20,14 +23,24 @@ public static void register() { 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)); + ModNetworking.CHANNEL.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)); + ModNetworking.CHANNEL.clientHandle().send(new MladyPacket(false)); } } } }); } + + public static boolean interceptScroll(float amount) { + var player = MinecraftClient.getInstance().player; + if (player != null && (player.getOffHandStack().contains(ModComponents.SELECTED_SLOT) + || (player.isSneaking() && player.getMainHandStack().contains(ModComponents.SELECTED_SLOT)))) { + ModNetworking.CHANNEL.clientHandle().send(new ScrollInGamePacket(amount)); + return true; + } + return false; + } } diff --git a/src/client/java/dev/enjarai/trickster/mixin/client/ExampleClientMixin.java b/src/client/java/dev/enjarai/trickster/mixin/client/ExampleClientMixin.java deleted file mode 100644 index cdcd35e5..00000000 --- a/src/client/java/dev/enjarai/trickster/mixin/client/ExampleClientMixin.java +++ /dev/null @@ -1,26 +0,0 @@ -package dev.enjarai.trickster.mixin.client; - -import dev.enjarai.trickster.screen.SpellCircleScreen; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.TitleScreen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.Text; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(TitleScreen.class) -public class ExampleClientMixin extends Screen { - protected ExampleClientMixin(Text title) { - super(title); - } - - @Inject(at = @At("HEAD"), method = "init") - private void init(CallbackInfo info) { - addDrawableChild(ButtonWidget.builder(Text.of("TEST"), btn -> { - MinecraftClient.getInstance().setScreen(new SpellCircleScreen()); - }).position(100, 100).size(100, 20).build()); - } -} \ No newline at end of file diff --git a/src/client/java/dev/enjarai/trickster/mixin/client/HeldItemRendererMixin.java b/src/client/java/dev/enjarai/trickster/mixin/client/HeldItemRendererMixin.java new file mode 100644 index 00000000..7c7aee0c --- /dev/null +++ b/src/client/java/dev/enjarai/trickster/mixin/client/HeldItemRendererMixin.java @@ -0,0 +1,29 @@ +package dev.enjarai.trickster.mixin.client; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import dev.enjarai.trickster.item.ModItems; +import net.minecraft.client.render.item.HeldItemRenderer; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(HeldItemRenderer.class) +public class HeldItemRendererMixin { + @WrapOperation( + method = "updateHeldItems", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/ItemStack;areEqual(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)Z" + ) + ) + private boolean cancelItemSwapAnimation(ItemStack left, ItemStack right, Operation original) { + var originalValue = original.call(left, right); + + if (left.isIn(ModItems.HOLDABLE_HAT) && right.isIn(ModItems.HOLDABLE_HAT)) { + return true; + } + + return originalValue; + } +} diff --git a/src/client/java/dev/enjarai/trickster/mixin/client/MouseMixin.java b/src/client/java/dev/enjarai/trickster/mixin/client/MouseMixin.java new file mode 100644 index 00000000..3e388713 --- /dev/null +++ b/src/client/java/dev/enjarai/trickster/mixin/client/MouseMixin.java @@ -0,0 +1,27 @@ +package dev.enjarai.trickster.mixin.client; + +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import dev.enjarai.trickster.ModKeyBindings; +import dev.enjarai.trickster.screen.SpellCircleScreen; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Mouse; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Mouse.class) +public class MouseMixin { + @WrapWithCondition( + method = "onMouseScroll", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/player/PlayerInventory;scrollInHotbar(D)V" + ) + ) + private boolean interceptMouseScroll(PlayerInventory instance, double scrollAmount) { + return !ModKeyBindings.interceptScroll((float) scrollAmount); + } +} \ No newline at end of file diff --git a/src/client/java/dev/enjarai/trickster/screen/ScrollContainerScreen.java b/src/client/java/dev/enjarai/trickster/screen/ScrollContainerScreen.java index 8f330b19..1c6bdb40 100644 --- a/src/client/java/dev/enjarai/trickster/screen/ScrollContainerScreen.java +++ b/src/client/java/dev/enjarai/trickster/screen/ScrollContainerScreen.java @@ -1,17 +1,21 @@ package dev.enjarai.trickster.screen; +import dev.enjarai.trickster.Trickster; 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.screen.slot.Slot; 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 static final Identifier TEXTURE = Trickster.id("textures/gui/scroll_54.png"); +// private static final Identifier TEXTURE = Identifier.ofVanilla("textures/gui/container/generic_54.png"); + private static final Identifier SELECTED_SLOT_TEXTURE = Trickster.id("textures/gui/selected_slot.png"); private final int rows; public ScrollContainerScreen(ScrollContainerScreenHandler handler, PlayerInventory inventory, Text title) { @@ -32,5 +36,17 @@ protected void drawBackground(DrawContext context, float delta, int mouseX, int 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); } + + @Override + protected void drawSlot(DrawContext context, Slot slot) { + super.drawSlot(context, slot); + + context.getMatrices().push(); + context.getMatrices().translate(0.0F, 0.0F, 110.0F); + if (slot.id == handler.selectedSlot.get()) { + context.drawTexture(SELECTED_SLOT_TEXTURE, slot.x - 4, slot.y - 4, 0, 0, 24, 24, 24, 24); + } + context.getMatrices().pop(); + } } diff --git a/src/client/resources/trickster.client.mixins.json b/src/client/resources/trickster.client.mixins.json index 5cb36eaa..e811a5a6 100644 --- a/src/client/resources/trickster.client.mixins.json +++ b/src/client/resources/trickster.client.mixins.json @@ -1,10 +1,12 @@ { - "required": true, - "package": "dev.enjarai.trickster.mixin.client", - "compatibilityLevel": "JAVA_21", - "client": [ - ], - "injectors": { - "defaultRequire": 1 + "required": true, + "package": "dev.enjarai.trickster.mixin.client", + "compatibilityLevel": "JAVA_21", + "client": [ + "HeldItemRendererMixin", + "MouseMixin" + ], + "injectors": { + "defaultRequire": 1 } } \ No newline at end of file diff --git a/src/main/java/dev/enjarai/trickster/item/ModItems.java b/src/main/java/dev/enjarai/trickster/item/ModItems.java index b0ecdeca..4aeaa3a8 100644 --- a/src/main/java/dev/enjarai/trickster/item/ModItems.java +++ b/src/main/java/dev/enjarai/trickster/item/ModItems.java @@ -2,6 +2,7 @@ import dev.enjarai.trickster.Trickster; import dev.enjarai.trickster.item.component.ModComponents; +import dev.enjarai.trickster.item.component.SelectedSlotComponent; import dev.enjarai.trickster.item.component.SpellComponent; import dev.enjarai.trickster.spell.SpellPart; import io.wispforest.lavender.book.LavenderBookItem; @@ -27,7 +28,8 @@ public class ModItems { public static final TrickHatItem TOP_HAT = register("top_hat", new TrickHatItem(new Item.Settings().maxCount(1) .component(DataComponentTypes.CONTAINER, - ContainerComponent.fromStacks(DefaultedList.ofSize(27, ItemStack.EMPTY))))); + ContainerComponent.fromStacks(DefaultedList.ofSize(27, ItemStack.EMPTY))) + .component(ModComponents.SELECTED_SLOT, new SelectedSlotComponent(0, 27)))); 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")); diff --git a/src/main/java/dev/enjarai/trickster/item/component/ModComponents.java b/src/main/java/dev/enjarai/trickster/item/component/ModComponents.java index 7f9401e5..5033b3a9 100644 --- a/src/main/java/dev/enjarai/trickster/item/component/ModComponents.java +++ b/src/main/java/dev/enjarai/trickster/item/component/ModComponents.java @@ -10,6 +10,8 @@ public class ModComponents { public static final ComponentType SPELL = register("spell", builder -> builder.codec(SpellComponent.CODEC).cache()); + public static final ComponentType SELECTED_SLOT = + register("selected_slot", builder -> builder.codec(SelectedSlotComponent.CODEC).cache()); private static ComponentType register(String id, UnaryOperator> builderOperator) { return Registry.register(Registries.DATA_COMPONENT_TYPE, Trickster.id(id), (builderOperator.apply(ComponentType.builder())).build()); diff --git a/src/main/java/dev/enjarai/trickster/item/component/SelectedSlotComponent.java b/src/main/java/dev/enjarai/trickster/item/component/SelectedSlotComponent.java new file mode 100644 index 00000000..3cdac7e2 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/item/component/SelectedSlotComponent.java @@ -0,0 +1,11 @@ +package dev.enjarai.trickster.item.component; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public record SelectedSlotComponent(int slot, int maxSlot) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("slot").forGetter(SelectedSlotComponent::slot), + Codec.INT.fieldOf("max_slot").forGetter(SelectedSlotComponent::maxSlot) + ).apply(instance, SelectedSlotComponent::new)); +} diff --git a/src/main/java/dev/enjarai/trickster/net/ModNetworking.java b/src/main/java/dev/enjarai/trickster/net/ModNetworking.java index 330873db..4ccf2b72 100644 --- a/src/main/java/dev/enjarai/trickster/net/ModNetworking.java +++ b/src/main/java/dev/enjarai/trickster/net/ModNetworking.java @@ -2,15 +2,19 @@ import dev.enjarai.trickster.Trickster; import dev.enjarai.trickster.item.ModItems; +import dev.enjarai.trickster.item.component.ModComponents; +import dev.enjarai.trickster.item.component.SelectedSlotComponent; import io.wispforest.owo.network.OwoNetChannel; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.EquipmentSlot; import net.minecraft.item.ItemStack; +import net.minecraft.text.Text; public class ModNetworking { - public static final OwoNetChannel MLADY = OwoNetChannel.create(Trickster.id("mlady")); + public static final OwoNetChannel CHANNEL = OwoNetChannel.create(Trickster.id("main")); public static void register() { - MLADY.registerServerbound(MladyPacket.class, (packet, access) -> { + CHANNEL.registerServerbound(MladyPacket.class, (packet, access) -> { var player = access.player(); var inventory = player.getInventory(); @@ -28,5 +32,45 @@ public static void register() { } } }); + + CHANNEL.registerServerbound(ScrollInGamePacket.class, (packet, access) -> { + var player = access.player(); + + if (Math.abs(packet.amount()) >= 1f) { + ItemStack stack = null; + + if (player.isSneaking() && player.getMainHandStack().contains(ModComponents.SELECTED_SLOT)) { + stack = player.getMainHandStack(); + } else if (player.getOffHandStack().contains(ModComponents.SELECTED_SLOT)) { + stack = player.getOffHandStack(); + } + + if (stack != null) { + var current = stack.get(ModComponents.SELECTED_SLOT); + var container = stack.get(DataComponentTypes.CONTAINER); + + if (current != null && container != null) { + var newSlot = Math.round(current.slot() + packet.amount()); + int maxSlot = (int) Math.min(current.maxSlot(), container.stream().count()); + + if (maxSlot > 0) { + while (newSlot < 0) { + newSlot += maxSlot; + } + while (newSlot >= maxSlot) { + newSlot -= maxSlot; + } + } else { + newSlot = 0; + } + + stack.set(ModComponents.SELECTED_SLOT, + new SelectedSlotComponent(newSlot, current.maxSlot())); + + player.sendMessage(Text.of("TODO: " + newSlot), true); + } + } + } + }); } } diff --git a/src/main/java/dev/enjarai/trickster/net/ScrollInGamePacket.java b/src/main/java/dev/enjarai/trickster/net/ScrollInGamePacket.java new file mode 100644 index 00000000..cd09b4a1 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/net/ScrollInGamePacket.java @@ -0,0 +1,4 @@ +package dev.enjarai.trickster.net; + +public record ScrollInGamePacket(float amount) { +} diff --git a/src/main/java/dev/enjarai/trickster/screen/ScrollContainerScreenHandler.java b/src/main/java/dev/enjarai/trickster/screen/ScrollContainerScreenHandler.java index b6e8e9a0..c6ed643c 100644 --- a/src/main/java/dev/enjarai/trickster/screen/ScrollContainerScreenHandler.java +++ b/src/main/java/dev/enjarai/trickster/screen/ScrollContainerScreenHandler.java @@ -3,6 +3,7 @@ import com.mojang.datafixers.util.Pair; import dev.enjarai.trickster.Trickster; import dev.enjarai.trickster.item.ModItems; +import dev.enjarai.trickster.item.component.ModComponents; import io.wispforest.owo.client.screens.SyncedProperty; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.ContainerComponent; @@ -25,6 +26,7 @@ public class ScrollContainerScreenHandler extends ScreenHandler { private final ItemStack containerStack; private final SyncedProperty lockedSlot = createProperty(Integer.class, -1); + public final SyncedProperty selectedSlot = createProperty(Integer.class, 0); public ScrollContainerScreenHandler(int syncId, PlayerInventory playerInventory) { this(syncId, playerInventory, null); @@ -47,6 +49,11 @@ public ScrollContainerScreenHandler(int syncId, PlayerInventory playerInventory, }); } + var selected = containerStack.get(ModComponents.SELECTED_SLOT); + if (selected != null) { + selectedSlot.set(selected.slot()); + } + for (int j = 0; j < 9; ++j) { if (playerInventory.getStack(j) == containerStack) { lockedSlot.set(j); diff --git a/src/main/java/dev/enjarai/trickster/spell/fragment/NumberFragment.java b/src/main/java/dev/enjarai/trickster/spell/fragment/NumberFragment.java index d3cc51c9..8f12e7ba 100644 --- a/src/main/java/dev/enjarai/trickster/spell/fragment/NumberFragment.java +++ b/src/main/java/dev/enjarai/trickster/spell/fragment/NumberFragment.java @@ -78,4 +78,13 @@ public RoundableFragment ceil() throws BlunderException { public RoundableFragment round() throws BlunderException { return new NumberFragment(Math.round(number)); } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NumberFragment n) { + var precision = 1 / 16d; + return n.number > number - precision && n.number < number + precision; + } + return false; + } } diff --git a/src/main/java/dev/enjarai/trickster/spell/fragment/VectorFragment.java b/src/main/java/dev/enjarai/trickster/spell/fragment/VectorFragment.java index e2a8aee9..1fe2b552 100644 --- a/src/main/java/dev/enjarai/trickster/spell/fragment/VectorFragment.java +++ b/src/main/java/dev/enjarai/trickster/spell/fragment/VectorFragment.java @@ -92,4 +92,12 @@ public RoundableFragment ceil() throws BlunderException { public RoundableFragment round() throws BlunderException { return new VectorFragment(vector.round(new Vector3d())); } + + @Override + public boolean equals(Object obj) { + if (obj instanceof VectorFragment v) { + return v.vector.equals(vector, 1 / 16d); + } + return false; + } } diff --git a/src/main/java/dev/enjarai/trickster/spell/tricks/Tricks.java b/src/main/java/dev/enjarai/trickster/spell/tricks/Tricks.java index b035999d..389367d9 100644 --- a/src/main/java/dev/enjarai/trickster/spell/tricks/Tricks.java +++ b/src/main/java/dev/enjarai/trickster/spell/tricks/Tricks.java @@ -3,6 +3,7 @@ import com.mojang.serialization.Lifecycle; import dev.enjarai.trickster.Trickster; import dev.enjarai.trickster.spell.Pattern; +import dev.enjarai.trickster.spell.tricks.bool.*; import dev.enjarai.trickster.spell.tricks.math.*; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; @@ -46,6 +47,11 @@ public class Tricks { // Boolean public static final IfElseTrick IF_ELSE = register("if_else", new IfElseTrick()); + public static final EqualsTrick EQUALS = register("equals", new EqualsTrick()); + public static final NotEqualsTrick NOT_EQUALS = register("not_equals", new NotEqualsTrick()); + public static final AllTrick ALL = register("all", new AllTrick()); + public static final AnyTrick ANY = register("any", new AnyTrick()); + public static final NoneTrick NONE = register("none", new NoneTrick()); private static T register(String path, T trick) { LOOKUP.put(trick.getPattern(), trick); diff --git a/src/main/java/dev/enjarai/trickster/spell/tricks/bool/AllTrick.java b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/AllTrick.java new file mode 100644 index 00000000..f0ed8855 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/AllTrick.java @@ -0,0 +1,21 @@ +package dev.enjarai.trickster.spell.tricks.bool; + +import dev.enjarai.trickster.spell.Fragment; +import dev.enjarai.trickster.spell.Pattern; +import dev.enjarai.trickster.spell.SpellContext; +import dev.enjarai.trickster.spell.fragment.BooleanFragment; +import dev.enjarai.trickster.spell.tricks.Trick; +import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; + +import java.util.List; + +public class AllTrick extends Trick { + public AllTrick() { + super(Pattern.of(1, 4, 7, 5, 4, 3, 1)); + } + + @Override + public Fragment activate(SpellContext ctx, List fragments) throws BlunderException { + return new BooleanFragment(fragments.stream().allMatch(f -> f.asBoolean().bool())); + } +} diff --git a/src/main/java/dev/enjarai/trickster/spell/tricks/bool/AnyTrick.java b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/AnyTrick.java new file mode 100644 index 00000000..c8a0c910 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/AnyTrick.java @@ -0,0 +1,21 @@ +package dev.enjarai.trickster.spell.tricks.bool; + +import dev.enjarai.trickster.spell.Fragment; +import dev.enjarai.trickster.spell.Pattern; +import dev.enjarai.trickster.spell.SpellContext; +import dev.enjarai.trickster.spell.fragment.BooleanFragment; +import dev.enjarai.trickster.spell.tricks.Trick; +import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; + +import java.util.List; + +public class AnyTrick extends Trick { + public AnyTrick() { + super(Pattern.of(5, 7, 4, 1, 3)); + } + + @Override + public Fragment activate(SpellContext ctx, List fragments) throws BlunderException { + return new BooleanFragment(fragments.stream().anyMatch(f -> f.asBoolean().bool())); + } +} diff --git a/src/main/java/dev/enjarai/trickster/spell/tricks/bool/EqualsTrick.java b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/EqualsTrick.java new file mode 100644 index 00000000..ff525fd0 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/EqualsTrick.java @@ -0,0 +1,29 @@ +package dev.enjarai.trickster.spell.tricks.bool; + +import dev.enjarai.trickster.spell.Fragment; +import dev.enjarai.trickster.spell.Pattern; +import dev.enjarai.trickster.spell.SpellContext; +import dev.enjarai.trickster.spell.fragment.BooleanFragment; +import dev.enjarai.trickster.spell.tricks.Trick; +import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; + +import java.util.List; + +public class EqualsTrick extends Trick { + public EqualsTrick() { + super(Pattern.of(0, 2, 5, 8, 6)); + } + + @Override + public Fragment activate(SpellContext ctx, List fragments) throws BlunderException { + Fragment last = null; + for (Fragment fragment : fragments) { + if (last != null && !fragment.equals(last)) { + return BooleanFragment.FALSE; + } + last = fragment; + } + + return BooleanFragment.TRUE; + } +} diff --git a/src/main/java/dev/enjarai/trickster/spell/tricks/IfElseTrick.java b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/IfElseTrick.java similarity index 88% rename from src/main/java/dev/enjarai/trickster/spell/tricks/IfElseTrick.java rename to src/main/java/dev/enjarai/trickster/spell/tricks/bool/IfElseTrick.java index ec693e28..d60bf48d 100644 --- a/src/main/java/dev/enjarai/trickster/spell/tricks/IfElseTrick.java +++ b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/IfElseTrick.java @@ -1,8 +1,9 @@ -package dev.enjarai.trickster.spell.tricks; +package dev.enjarai.trickster.spell.tricks.bool; import dev.enjarai.trickster.spell.Fragment; import dev.enjarai.trickster.spell.Pattern; import dev.enjarai.trickster.spell.SpellContext; +import dev.enjarai.trickster.spell.tricks.Trick; import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; import java.util.List; diff --git a/src/main/java/dev/enjarai/trickster/spell/tricks/bool/NoneTrick.java b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/NoneTrick.java new file mode 100644 index 00000000..edb89d98 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/NoneTrick.java @@ -0,0 +1,21 @@ +package dev.enjarai.trickster.spell.tricks.bool; + +import dev.enjarai.trickster.spell.Fragment; +import dev.enjarai.trickster.spell.Pattern; +import dev.enjarai.trickster.spell.SpellContext; +import dev.enjarai.trickster.spell.fragment.BooleanFragment; +import dev.enjarai.trickster.spell.tricks.Trick; +import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; + +import java.util.List; + +public class NoneTrick extends Trick { + public NoneTrick() { + super(Pattern.of(7, 5, 2, 1, 3)); + } + + @Override + public Fragment activate(SpellContext ctx, List fragments) throws BlunderException { + return new BooleanFragment(fragments.stream().noneMatch(f -> f.asBoolean().bool())); + } +} diff --git a/src/main/java/dev/enjarai/trickster/spell/tricks/bool/NotEqualsTrick.java b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/NotEqualsTrick.java new file mode 100644 index 00000000..2fb3b3f3 --- /dev/null +++ b/src/main/java/dev/enjarai/trickster/spell/tricks/bool/NotEqualsTrick.java @@ -0,0 +1,29 @@ +package dev.enjarai.trickster.spell.tricks.bool; + +import dev.enjarai.trickster.spell.Fragment; +import dev.enjarai.trickster.spell.Pattern; +import dev.enjarai.trickster.spell.SpellContext; +import dev.enjarai.trickster.spell.fragment.BooleanFragment; +import dev.enjarai.trickster.spell.tricks.Trick; +import dev.enjarai.trickster.spell.tricks.blunder.BlunderException; + +import java.util.List; + +public class NotEqualsTrick extends Trick { + public NotEqualsTrick() { + super(Pattern.of(0, 2, 5, 8, 6, 4, 2)); + } + + @Override + public Fragment activate(SpellContext ctx, List fragments) throws BlunderException { + Fragment last = null; + for (Fragment fragment : fragments) { + if (last != null && !fragment.equals(last)) { + return BooleanFragment.TRUE; + } + last = fragment; + } + + return BooleanFragment.FALSE; + } +} diff --git a/src/main/resources/assets/trickster/lang/en_us.yml b/src/main/resources/assets/trickster/lang/en_us.yml new file mode 100644 index 00000000..d13e90da --- /dev/null +++ b/src/main/resources/assets/trickster/lang/en_us.yml @@ -0,0 +1,21 @@ +trickster: + screen: + scroll_container: Scroll Storage + + trick.trickster: + add: Annexation Stratagem + subtract: Desertion Stratagem + multiply: Domination Stratagem + divide: Submission Stratagem + modulo: Distortion of Wholes + max: Noble Stratagem + min: Insignificance Stratagem + ceil: Distortion of Grandeur + floor: Distortion of Humility + round: Distortion of Objectivity + +item.trickster: + tome_of_tomfoolery: Tome of Tomfoolery + mirror_of_evaluation: Mirror of Evaluation + scroll_and_quill: Scroll and Quill + top_hat: Top Hat \ No newline at end of file diff --git a/src/main/resources/assets/trickster/textures/gui/scroll_54.png b/src/main/resources/assets/trickster/textures/gui/scroll_54.png new file mode 100644 index 0000000000000000000000000000000000000000..f6cbe229003edace212712fb8aa4d8e16129ef00 GIT binary patch literal 13290 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�`N(-E!- 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 W&n=C59UqT(0J4&b64heh!2bb3BuxPT literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/trickster/textures/gui/selected_slot.png b/src/main/resources/assets/trickster/textures/gui/selected_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..06614a1766fa2f1f4785958cd22cc652b6edad46 GIT binary patch literal 516 zcmV+f0{i`mP)3VOUxiCDEt5a<0+{4U@erc0ps6$E8%Rg9GnfozxGsMh@GC5@E>G0+yamQ3?G{s zgTg;OEB^n@r5XQ^K*e|Wg#AA=I}y%@(I9+fQ5u+TOR>VVpfkmr4j?}02WAd*4Wwcm z7C;227C2MIg5%R-!Q~l>4^B*v0~dDa8c4-3$ASt&xCO9`Ruf}Pu?4^PRsBCdHwm+- zI50619P{WJNX0ng;MC0c|1C*WNT$G|A7mCNMPfwqpZ!(vDi4N1UIvx%VEzFpjTP6z zt6Z!;011NdwZ&=RDiBm9!o&_wi3W><*r3D!69?gwGa!5z4RSrGibb&iW+MpqWZHo- zsJa9N8B82hfq?P}j1R-0DitILVoxh{0n?yz2qhKK5(5Babs}KxZKquT00000{Q}wB!2;OQb$4nuFf3k0003rNklz_&002ovPDHLkV1h3)oJ;@! delta 271 zcmV+q0r39%0;&R#B!BTqL_t(|UhR~z3c^4TMAJ(?z(%n4A8h{FbLkCoFS{vc#I1T|kCY{8<4p zFp!LW*#J)`dV$3iIG)ba<$9a$kLMS|y`XtI^V=7Y<6Dq0 zG4@#DRV9erLbAlG0!fAO^MtwOq6aTEQU#ID%PDHLkV1jr_eu)48