Delegate workbench apply button and slot behaviour to item classes
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.event.SpellBindEvent;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Items that implement this interface may be placed in the central slot of the arcane workbench as long as
|
||||
* {@link IWorkbenchItem#canPlace(ItemStack)} returns true.The number of spell book slots displayed is also specified
|
||||
* using {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}.
|
||||
* <p>
|
||||
* Items that implement this interface define what happens if they are in the central slot of the arcane workbench and
|
||||
* the apply button is pressed, in {@link IWorkbenchItem#onApplyButtonPressed(EntityPlayer, Slot, Slot, Slot, Slot[])}.
|
||||
* This is a core part of the arcane workbench refactoring in version 4.2 and allows for custom spell casting items and
|
||||
* chargeable armour without requiring that they extend {@link ItemWand} or {@link ItemWizardArmour}.
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2
|
||||
*/
|
||||
public interface IWorkbenchItem {
|
||||
|
||||
/**
|
||||
* Returns true if the item can be placed in the central slot of an arcane workbench, false otherwise. Allows
|
||||
* for itemstack-sensitive behaviour. Returns true by default.
|
||||
* @param stack The stack that is being placed into the workbench.
|
||||
* @return True to allow the item to be placed into the workbench, false to prevent that from happening.
|
||||
*/
|
||||
default boolean canPlace(ItemStack stack){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of spell book slots that should appear in the workbench when this item is placed into it,
|
||||
* based on the given itemstack.
|
||||
* @param stack The stack that is being placed into the workbench.
|
||||
* @return The number of spell book slots that should appear around this item when it is placed into the workbench.
|
||||
* Can be 0, but must not be negative.
|
||||
*/
|
||||
int getSpellSlotCount(ItemStack stack);
|
||||
|
||||
/**
|
||||
* Called when this item is in the central slot of an arcane workbench and the apply button is pressed. Items must
|
||||
* implement this method to define what happens when the apply button is pressed. Note that {@link SpellBindEvent}
|
||||
* is fired <i>before</i> this method is called.
|
||||
* @param player The player that pressed the apply button.
|
||||
* @param centre The central slot in the arcane workbench. This slot will always contain a stack of the implementing
|
||||
* item, or in other words, <i>it is guaranteed that</i> {@code this == centre.getStack().getItem()}.
|
||||
* @param crystals The magic crystal slot of the arcane workbench.
|
||||
* @param upgrade The upgrade slot of the arcane workbench.
|
||||
* @param spellBooks An array of the <i>active</i> (visible) spell book slots in the arcane workbench. The length of
|
||||
* the array will be equal to the value returned by {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}.
|
||||
* @return True if anything changed, false if not.
|
||||
*/
|
||||
boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.WizardData;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
||||
|
||||
public ItemBlankScroll(){
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpellSlotCount(ItemStack stack){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
|
||||
|
||||
if(!spellBooks[0].getStack().isEmpty() && !crystals.getStack().isEmpty()){
|
||||
|
||||
Spell spell = Spell.get(spellBooks[0].getStack().getItemDamage());
|
||||
WizardData data = WizardData.get(player);
|
||||
|
||||
// Spells can only be bound to scrolls if the player has already cast them (prevents casting of master
|
||||
// spells without getting a master wand)
|
||||
// This restriction does not apply in creative mode
|
||||
if(spell != Spells.none && player.capabilities.isCreativeMode || (data != null
|
||||
&& data.hasSpellBeenDiscovered(spell))){
|
||||
|
||||
int cost = spell.cost;
|
||||
// Continuous spell scrolls require enough mana to cast them for the duration defined in ItemScroll.
|
||||
if(spell.isContinuous) cost *= ItemScroll.CASTING_TIME / 20;
|
||||
|
||||
if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL > cost){
|
||||
// Rounds up to the nearest whole crystal
|
||||
crystals.decrStackSize(cost / Constants.MANA_PER_CRYSTAL + 1);
|
||||
centre.putStack(new ItemStack(WizardryItems.scroll, 1, spell.id()));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||
import electroblob.wizardry.packet.PacketCastSpell;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryAdvancementTriggers;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
@@ -30,6 +31,7 @@ import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.EnumAction;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -59,7 +61,10 @@ import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
*
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
public class ItemWand extends Item {
|
||||
public class ItemWand extends Item implements IWorkbenchItem {
|
||||
|
||||
/** The number of spell slots a wand has with no attunement upgrades applied. */
|
||||
public static final int BASE_SPELL_SLOTS = 5;
|
||||
|
||||
public Tier tier;
|
||||
public Element element;
|
||||
@@ -424,4 +429,142 @@ public class ItemWand extends Item {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpellSlotCount(ItemStack stack){
|
||||
return BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(stack, WizardryItems.attunement_upgrade);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
// Upgrades wand if necessary. Damage is copied, preserving remaining durability,
|
||||
// and also the entire NBT tag compound.
|
||||
if(upgrade.getStack().getItem() == WizardryItems.arcane_tome){
|
||||
|
||||
// Checks the wand upgrade is for the tier above the wand's tier.
|
||||
// It is guaranteed that: this == centre.getStack().getItem()
|
||||
if(upgrade.getStack().getItemDamage() - 1 == this.tier.ordinal()){
|
||||
|
||||
Tier tier = Tier.values()[upgrade.getStack().getItemDamage()];
|
||||
|
||||
ItemStack newWand = new ItemStack(WizardryUtilities.getWand(tier, this.element));
|
||||
newWand.setTagCompound(centre.getStack().getTagCompound());
|
||||
// This needs to be done after copying the tag compound so the max damage for the new wand
|
||||
// takes storage upgrades into account.
|
||||
newWand.setItemDamage(newWand.getMaxDamage() - (centre.getStack().getMaxDamage() - centre.getStack().getItemDamage()));
|
||||
|
||||
centre.putStack(newWand);
|
||||
upgrade.decrStackSize(1);
|
||||
|
||||
if(tier == Tier.APPRENTICE) WizardryAdvancementTriggers.apprentice.triggerFor(player);
|
||||
if(tier == Tier.MASTER) WizardryAdvancementTriggers.master.triggerFor(player);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
}else if(WandHelper.isWandUpgrade(upgrade.getStack().getItem())){
|
||||
|
||||
// Special upgrades
|
||||
Item specialUpgrade = upgrade.getStack().getItem();
|
||||
|
||||
if(WandHelper.getTotalUpgrades(centre.getStack()) < this.tier.upgradeLimit
|
||||
&& WandHelper.getUpgradeLevel(centre.getStack(), specialUpgrade) < Constants.UPGRADE_STACK_LIMIT){
|
||||
|
||||
// Used to preserve existing mana when upgrading storage rather than creating free mana.
|
||||
int prevMana = centre.getStack().getMaxDamage() - centre.getStack().getItemDamage();
|
||||
|
||||
WandHelper.applyUpgrade(centre.getStack(), specialUpgrade);
|
||||
|
||||
// Special behaviours for specific upgrades
|
||||
if(specialUpgrade == WizardryItems.storage_upgrade){
|
||||
|
||||
centre.getStack().setItemDamage(centre.getStack().getMaxDamage() - prevMana);
|
||||
|
||||
}else if(specialUpgrade == WizardryItems.attunement_upgrade){
|
||||
|
||||
int newSlotCount = BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(centre.getStack(),
|
||||
WizardryItems.attunement_upgrade);
|
||||
|
||||
Spell[] spells = WandHelper.getSpells(centre.getStack());
|
||||
Spell[] newSpells = new Spell[newSlotCount];
|
||||
|
||||
for(int i = 0; i < newSpells.length; i++){
|
||||
newSpells[i] = i < spells.length && spells[i] != null ? spells[i] : Spells.none;
|
||||
}
|
||||
|
||||
WandHelper.setSpells(centre.getStack(), newSpells);
|
||||
|
||||
int[] cooldowns = WandHelper.getCooldowns(centre.getStack());
|
||||
int[] newCooldowns = new int[newSlotCount];
|
||||
|
||||
if(cooldowns.length > 0){
|
||||
for(int i = 0; i < cooldowns.length; i++){
|
||||
newCooldowns[i] = cooldowns[i];
|
||||
}
|
||||
}
|
||||
|
||||
WandHelper.setCooldowns(centre.getStack(), newCooldowns);
|
||||
}
|
||||
|
||||
upgrade.decrStackSize(1);
|
||||
WizardryAdvancementTriggers.special_upgrade.triggerFor(player);
|
||||
|
||||
if(WandHelper.getTotalUpgrades(centre.getStack()) == Tier.MASTER.upgradeLimit){
|
||||
WizardryAdvancementTriggers.max_out_wand.triggerFor(player);
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Reads NBT spell id array to variable, edits this, then writes it back to NBT.
|
||||
// Original spells are preserved; if a slot is left empty the existing spell binding will remain.
|
||||
// Accounts for spells which cannot be applied because they are above the wand's tier; these spells
|
||||
// will not bind but the existing spell in that slot will remain and other applicable spells will
|
||||
// be bound as normal, along with any upgrades and crystals.
|
||||
Spell[] spells = WandHelper.getSpells(centre.getStack());
|
||||
|
||||
if(spells.length <= 0){
|
||||
// Base value here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades
|
||||
spells = new Spell[BASE_SPELL_SLOTS];
|
||||
}
|
||||
|
||||
for(int i = 0; i < spells.length; i++){
|
||||
if(spellBooks[i].getStack() != ItemStack.EMPTY){
|
||||
|
||||
Spell spell = Spell.get(spellBooks[i].getStack().getItemDamage());
|
||||
// If the wand is powerful enough for the spell and it's not already bound to that slot
|
||||
if(!(spell.tier.level > this.tier.level) && spells[i] != spell){
|
||||
spells[i] = spell;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WandHelper.setSpells(centre.getStack(), spells);
|
||||
|
||||
// Charges wand by appropriate amount
|
||||
if(crystals.getStack() != ItemStack.EMPTY){
|
||||
|
||||
int chargeDepleted = centre.getStack().getItemDamage();
|
||||
|
||||
if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){
|
||||
|
||||
centre.getStack().setItemDamage(chargeDepleted - crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL);
|
||||
crystals.decrStackSize(crystals.getStack().getCount());
|
||||
changed = true;
|
||||
|
||||
}else if(chargeDepleted != 0){
|
||||
|
||||
centre.getStack().setItemDamage(0);
|
||||
crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import electroblob.wizardry.block.BlockStatue;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.registry.WizardryAdvancementTriggers;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.util.ITooltipFlag;
|
||||
@@ -20,9 +21,11 @@ import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.EnumAction;
|
||||
import net.minecraft.item.ItemArmor;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumHandSide;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||
@@ -32,7 +35,7 @@ import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class ItemWizardArmour extends ItemArmor {
|
||||
public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem {
|
||||
|
||||
//VanillaCopy, ItemArmor has this set to private for some reason.
|
||||
public static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")};
|
||||
@@ -211,4 +214,52 @@ public class ItemWizardArmour extends ItemArmor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpellSlotCount(ItemStack stack){
|
||||
return 0; // Doesn't have any spell slots!
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
// Applies legendary upgrade
|
||||
if(upgrade.getStack().getItem() == WizardryItems.armour_upgrade){
|
||||
|
||||
if(!centre.getStack().hasTagCompound()){
|
||||
centre.getStack().setTagCompound(new NBTTagCompound());
|
||||
}
|
||||
|
||||
if(!centre.getStack().getTagCompound().hasKey("legendary")){
|
||||
|
||||
centre.getStack().getTagCompound().setBoolean("legendary", true);
|
||||
upgrade.decrStackSize(1);
|
||||
WizardryAdvancementTriggers.legendary.triggerFor(player);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Charges armour by appropriate amount
|
||||
if(crystals.getStack() != ItemStack.EMPTY){
|
||||
|
||||
int chargeDepleted = centre.getStack().getItemDamage();
|
||||
|
||||
if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL < chargeDepleted){
|
||||
|
||||
centre.getStack().setItemDamage(chargeDepleted - crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL);
|
||||
crystals.decrStackSize(crystals.getStack().getCount());
|
||||
changed = true;
|
||||
|
||||
}else if(chargeDepleted != 0){
|
||||
|
||||
centre.getStack().setItemDamage(0);
|
||||
crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / Constants.MANA_PER_CRYSTAL));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user