diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index da53f756..d4d68860 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -16,6 +16,7 @@ import electroblob.wizardry.client.particle.*; import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory; import electroblob.wizardry.client.renderer.*; import electroblob.wizardry.command.SpellEmitter; +import electroblob.wizardry.constants.Constants; import electroblob.wizardry.data.DispenserCastingData; import electroblob.wizardry.data.SpellEmitterData; import electroblob.wizardry.data.SpellGlyphData; @@ -72,6 +73,7 @@ import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.village.MerchantRecipeList; import net.minecraft.world.World; import net.minecraftforge.client.settings.KeyConflictContext; +import net.minecraftforge.client.settings.KeyModifier; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Property; import net.minecraftforge.fml.client.config.GuiConfigEntries.NumberSliderEntry; @@ -103,6 +105,14 @@ public class ClientProxy extends CommonProxy { // Key Bindings public static final KeyBinding NEXT_SPELL = new KeyBinding("key." + Wizardry.MODID + ".next_spell", KeyConflictContext.IN_GAME, Keyboard.KEY_N, "key.categories." + Wizardry.MODID); public static final KeyBinding PREVIOUS_SPELL = new KeyBinding("key." + Wizardry.MODID + ".previous_spell", KeyConflictContext.IN_GAME, Keyboard.KEY_B, "key.categories." + Wizardry.MODID); + public static final KeyBinding[] SPELL_QUICK_ACCESS = new KeyBinding[ItemWand.BASE_SPELL_SLOTS + Constants.UPGRADE_STACK_LIMIT]; + + static { + for(int i = 0; i < SPELL_QUICK_ACCESS.length; i++){ + SPELL_QUICK_ACCESS[i] = new KeyBinding("key." + Wizardry.MODID + ".spell_" + (i+1), + KeyConflictContext.IN_GAME, KeyModifier.ALT, Keyboard.KEY_1 + i, "key.categories." + Wizardry.MODID); + } + } // Armour Model public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f); @@ -122,6 +132,7 @@ public class ClientProxy extends CommonProxy { public void registerKeyBindings(){ ClientRegistry.registerKeyBinding(NEXT_SPELL); ClientRegistry.registerKeyBinding(PREVIOUS_SPELL); + for(KeyBinding key : SPELL_QUICK_ACCESS) ClientRegistry.registerKeyBinding(key); } @Override diff --git a/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java index 7b98aca0..377880a1 100644 --- a/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java +++ b/src/main/java/electroblob/wizardry/client/WizardryControlHandler.java @@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.gui.GuiSpellDisplay; import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.packet.PacketControlInput; +import electroblob.wizardry.packet.PacketSpellQuickAccess; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.registry.WizardrySounds; import net.minecraft.client.Minecraft; @@ -24,6 +25,7 @@ public class WizardryControlHandler { static boolean NkeyPressed = false; static boolean BkeyPressed = false; + static boolean[] quickAccessKeyPressed = new boolean[ClientProxy.SPELL_QUICK_ACCESS.length]; // Changed to a tick event to allow mouse button keybinds // The 'lag' that happened previously was actually because the code only fired when a keyboard key was pressed! @@ -59,6 +61,19 @@ public class WizardryControlHandler { }else{ BkeyPressed = false; } + + for(int i = 0; i < ClientProxy.SPELL_QUICK_ACCESS.length; i++){ + if(ClientProxy.SPELL_QUICK_ACCESS[i].isKeyDown() && Minecraft.getMinecraft().inGameHasFocus){ + if(!quickAccessKeyPressed[i]){ + quickAccessKeyPressed[i] = true; + // Packet building + selectSpell(wand, i); + } + }else{ + quickAccessKeyPressed[i] = false; + } + } + } } } @@ -118,4 +133,17 @@ public class WizardryControlHandler { GuiSpellDisplay.playSpellSwitchAnimation(false); Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1)); } + + private static void selectSpell(ItemStack wand, int index){ + // GUI switch animation + if(((ISpellCastingItem)wand.getItem()).selectSpell(wand, index)){ // Makes sure the spell is set immediately for the client + // Packet building (no point sending it unless the client-side spell selection succeeded + IMessage msg = new PacketSpellQuickAccess.Message(index); + WizardryPacketHandler.net.sendToServer(msg); + + GuiSpellDisplay.playSpellSwitchAnimation(true); // This will do, it's only an animation + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1)); + } + } + } diff --git a/src/main/java/electroblob/wizardry/item/ISpellCastingItem.java b/src/main/java/electroblob/wizardry/item/ISpellCastingItem.java index 0d532200..2666a5bb 100644 --- a/src/main/java/electroblob/wizardry/item/ISpellCastingItem.java +++ b/src/main/java/electroblob/wizardry/item/ISpellCastingItem.java @@ -65,6 +65,16 @@ public interface ISpellCastingItem { // Nothing here either } + /** + * Selects the spell at the given index bound to the given itemstack. The given itemstack will be of this item. + * @param stack The itemstack to query. + * @param index The index to set. + * @return True if the operation succeeded, false if not. + */ + default boolean selectSpell(ItemStack stack, int index){ + return false; + } + /** * Returns whether the spell HUD should be shown when a player is holding this item. Only called client-side. * @param player The player holding the item. diff --git a/src/main/java/electroblob/wizardry/item/ItemWand.java b/src/main/java/electroblob/wizardry/item/ItemWand.java index 8272098a..8c80cb75 100644 --- a/src/main/java/electroblob/wizardry/item/ItemWand.java +++ b/src/main/java/electroblob/wizardry/item/ItemWand.java @@ -113,6 +113,11 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, WandHelper.selectPreviousSpell(stack); } + @Override + public boolean selectSpell(ItemStack stack, int index){ + return WandHelper.selectSpell(stack, index); + } + @Override public boolean showSpellHUD(EntityPlayer player, ItemStack stack){ return true; diff --git a/src/main/java/electroblob/wizardry/packet/PacketSpellQuickAccess.java b/src/main/java/electroblob/wizardry/packet/PacketSpellQuickAccess.java new file mode 100644 index 00000000..4828216b --- /dev/null +++ b/src/main/java/electroblob/wizardry/packet/PacketSpellQuickAccess.java @@ -0,0 +1,66 @@ +package electroblob.wizardry.packet; + +import electroblob.wizardry.item.ISpellCastingItem; +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +/** [Client -> Server] This packet is for the spell quick access keys. */ +public class PacketSpellQuickAccess implements IMessageHandler { + + @Override + public IMessage onMessage(Message message, MessageContext ctx){ + + // Just to make sure that the side is correct + if(ctx.side.isServer()){ + + final EntityPlayerMP player = ctx.getServerHandler().player; + + player.getServerWorld().addScheduledTask(() -> { + + ItemStack wand = player.getHeldItemMainhand(); + + if(!(wand.getItem() instanceof ISpellCastingItem)){ + wand = player.getHeldItemOffhand(); + } + + if(wand.getItem() instanceof ISpellCastingItem){ + + ((ISpellCastingItem)wand.getItem()).selectSpell(wand, message.index); + // This line fixes the bug with continuous spells casting when they shouldn't be + player.stopActiveHand(); + } + + }); + } + + return null; + } + + public static class Message implements IMessage { + + private int index; + + // This constructor is required otherwise you'll get errors (used somewhere in fml through reflection) + public Message(){ + } + + public Message(int index){ + this.index = index; + } + + @Override + public void fromBytes(ByteBuf buf){ + // The order is important + this.index = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf){ + buf.writeInt(index); + } + } +} diff --git a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java index 8feabd56..7d7133c2 100644 --- a/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java +++ b/src/main/java/electroblob/wizardry/packet/WizardryPacketHandler.java @@ -13,25 +13,26 @@ public class WizardryPacketHandler { public static void initPackets(){ net = NetworkRegistry.INSTANCE.newSimpleChannel(Wizardry.MODID.toUpperCase()); - registerMessage(PacketControlInput.class, PacketControlInput.Message.class); - registerMessage(PacketCastSpell.class, PacketCastSpell.Message.class); - registerMessage(PacketTransportation.class, PacketTransportation.Message.class); - registerMessage(PacketPlayerSync.class, PacketPlayerSync.Message.class); - registerMessage(PacketGlyphData.class, PacketGlyphData.Message.class); - registerMessage(PacketCastContinuousSpell.class, PacketCastContinuousSpell.Message.class); - registerMessage(PacketClairvoyance.class, PacketClairvoyance.Message.class); - registerMessage(PacketSyncSettings.class, PacketSyncSettings.Message.class); - registerMessage(PacketNPCCastSpell.class, PacketNPCCastSpell.Message.class); - registerMessage(PacketDispenserCastSpell.class, PacketDispenserCastSpell.Message.class); - registerMessage(PacketSpellProperties.class, PacketSpellProperties.Message.class); - registerMessage(PacketSyncAdvancements.class, PacketSyncAdvancements.Message.class); + registerMessage(PacketControlInput.class, PacketControlInput.Message.class); + registerMessage(PacketCastSpell.class, PacketCastSpell.Message.class); + registerMessage(PacketTransportation.class, PacketTransportation.Message.class); + registerMessage(PacketPlayerSync.class, PacketPlayerSync.Message.class); + registerMessage(PacketGlyphData.class, PacketGlyphData.Message.class); + registerMessage(PacketCastContinuousSpell.class, PacketCastContinuousSpell.Message.class); + registerMessage(PacketClairvoyance.class, PacketClairvoyance.Message.class); + registerMessage(PacketSyncSettings.class, PacketSyncSettings.Message.class); + registerMessage(PacketNPCCastSpell.class, PacketNPCCastSpell.Message.class); + registerMessage(PacketDispenserCastSpell.class, PacketDispenserCastSpell.Message.class); + registerMessage(PacketSpellProperties.class, PacketSpellProperties.Message.class); + registerMessage(PacketSyncAdvancements.class, PacketSyncAdvancements.Message.class); registerMessage(PacketRequestAdvancementSync.class, PacketRequestAdvancementSync.Message.class); - registerMessage(PacketResurrection.class, PacketResurrection.Message.class); - registerMessage(PacketCastSpellAtPos.class, PacketCastSpellAtPos.Message.class); - registerMessage(PacketEmitterData.class, PacketEmitterData.Message.class); - registerMessage(PacketPossession.class, PacketPossession.Message.class); - registerMessage(PacketConquerShrine.class, PacketConquerShrine.Message.class); - registerMessage(PacketLectern.class, PacketLectern.Message.class); + registerMessage(PacketResurrection.class, PacketResurrection.Message.class); + registerMessage(PacketCastSpellAtPos.class, PacketCastSpellAtPos.Message.class); + registerMessage(PacketEmitterData.class, PacketEmitterData.Message.class); + registerMessage(PacketPossession.class, PacketPossession.Message.class); + registerMessage(PacketConquerShrine.class, PacketConquerShrine.Message.class); + registerMessage(PacketLectern.class, PacketLectern.Message.class); + registerMessage(PacketSpellQuickAccess.class, PacketSpellQuickAccess.Message.class); } private static int nextPacketId = 0; diff --git a/src/main/java/electroblob/wizardry/util/WandHelper.java b/src/main/java/electroblob/wizardry/util/WandHelper.java index 677761a3..ca8fde07 100644 --- a/src/main/java/electroblob/wizardry/util/WandHelper.java +++ b/src/main/java/electroblob/wizardry/util/WandHelper.java @@ -170,6 +170,26 @@ public final class WandHelper { wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, getPreviousSpellIndex(wand)); } } + + /** + * Selects the spell at the given index in this wand's list of spells. + * @param wand The stack to set the spell of + * @param index The spell index to set the wand to + * @return False if the index was out-of-bounds, true otherwise + */ + public static boolean selectSpell(ItemStack wand, int index){ + + if(index < 0 || index > getSpells(wand).length) return false; // Out-of-bounds + + // 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades + if(getSpells(wand).length < 0) setSpells(wand, new Spell[ItemWand.BASE_SPELL_SLOTS]); + + if(wand.getTagCompound() != null){ + wand.getTagCompound().setInteger(SELECTED_SPELL_KEY, index); + } + + return true; + } private static int getNextSpellIndex(ItemStack wand){ diff --git a/src/main/resources/assets/ebwizardry/lang/en_gb.lang b/src/main/resources/assets/ebwizardry/lang/en_gb.lang index 70f25949..ffc3116e 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_gb.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_gb.lang @@ -1076,6 +1076,14 @@ key.categories.ebwizardry=Wizardry key.ebwizardry.next_spell=Next Spell key.ebwizardry.previous_spell=Previous Spell +key.ebwizardry.spell_1=Spell Slot 1 +key.ebwizardry.spell_2=Spell Slot 2 +key.ebwizardry.spell_3=Spell Slot 3 +key.ebwizardry.spell_4=Spell Slot 4 +key.ebwizardry.spell_5=Spell Slot 5 +key.ebwizardry.spell_6=Spell Slot 6 +key.ebwizardry.spell_7=Spell Slot 7 +key.ebwizardry.spell_8=Spell Slot 8 death.attack.wizardry_magic=%1$s was killed by %2$s using magic death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic diff --git a/src/main/resources/assets/ebwizardry/lang/en_us.lang b/src/main/resources/assets/ebwizardry/lang/en_us.lang index d7b710a0..7b5d46f9 100644 --- a/src/main/resources/assets/ebwizardry/lang/en_us.lang +++ b/src/main/resources/assets/ebwizardry/lang/en_us.lang @@ -1076,6 +1076,14 @@ key.categories.ebwizardry=Wizardry key.ebwizardry.next_spell=Next Spell key.ebwizardry.previous_spell=Previous Spell +key.ebwizardry.spell_1=Spell Slot 1 +key.ebwizardry.spell_2=Spell Slot 2 +key.ebwizardry.spell_3=Spell Slot 3 +key.ebwizardry.spell_4=Spell Slot 4 +key.ebwizardry.spell_5=Spell Slot 5 +key.ebwizardry.spell_6=Spell Slot 6 +key.ebwizardry.spell_7=Spell Slot 7 +key.ebwizardry.spell_8=Spell Slot 8 death.attack.wizardry_magic=%1$s was killed by %2$s using magic death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic