Fix spell book for crystals trade not working

This commit is contained in:
Electroblob
2018-04-09 17:28:59 +01:00
parent 4e91b0d19d
commit 766570aeb2
3 changed files with 140 additions and 3 deletions
@@ -1,5 +1,7 @@
package electroblob.wizardry.client;
import java.lang.reflect.Field;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.WizardData;
@@ -9,6 +11,7 @@ import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Flight;
import electroblob.wizardry.spell.ShadowWard;
@@ -17,19 +20,27 @@ import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiMerchant;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityArmorStand;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.village.MerchantRecipe;
import net.minecraftforge.client.event.FOVUpdateEvent;
import net.minecraftforge.client.event.GuiContainerEvent;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
@@ -39,6 +50,7 @@ import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.fml.relauncher.Side;
/**
@@ -59,6 +71,12 @@ public final class WizardryClientEventHandler {
private static final ResourceLocation pointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/pointer.png");
private static final ResourceLocation targetPointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/target_pointer.png");
private static final Field ITEM_RENDERER;
static {
ITEM_RENDERER = ReflectionHelper.findField(GuiScreen.class, "itemRender", "");
}
@SubscribeEvent
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL);
@@ -115,6 +133,66 @@ public final class WizardryClientEventHandler {
event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F);
}
}
// Brute-force fix for crystals not showing up when a wizard is given a spell book in the trade GUI.
@SubscribeEvent
public static void onGuiDrawForegroundEvent(GuiContainerEvent.DrawForeground event){
if(event.getGuiContainer() instanceof GuiMerchant){
GuiMerchant gui = (GuiMerchant)event.getGuiContainer();
// Note that gui.getMerchant() returns an NpcMerchant, not an EntityWizard.
// Using == the specific item rather than instanceof because that's how trades do it.
if(gui.inventorySlots.getSlot(0).getStack().getItem() == WizardryItems.spell_book
|| gui.inventorySlots.getSlot(1).getStack().getItem() == WizardryItems.spell_book){
for(MerchantRecipe trade : gui.getMerchant().getRecipes(Minecraft.getMinecraft().player)){
if(trade.getItemToBuy().getItem() == WizardryItems.spell_book && trade.getSecondItemToBuy().isEmpty()){
Slot slot = gui.inventorySlots.getSlot(2);
// Uses reflection to draw the itemstack
// It still doesn't look quite right because the slot highlight is behind the item, but it'll do
// until/unless I find a better solution.
renderItemAndTooltip(gui, trade.getItemToSell(), slot.xPos, slot.yPos, event.getMouseX(), event.getMouseY(),
gui.getSlotUnderMouse() == slot);
}
}
}
}
}
private static void renderItemAndTooltip(GuiContainer gui, ItemStack stack, int x, int y, int mouseX, int mouseY, boolean tooltip){
try {
RenderItem renderItem = (RenderItem)ITEM_RENDERER.get(gui);
GlStateManager.pushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
GlStateManager.enableLighting();
renderItem.zLevel = 100.0F;
if(!stack.isEmpty()){
renderItem.renderItemAndEffectIntoGUI(stack, x, y);
renderItem.renderItemOverlays(Minecraft.getMinecraft().fontRenderer, stack, x, y);
if(tooltip){
gui.drawHoveringText(gui.getItemToolTip(stack), mouseX + gui.getXSize()/2 - gui.width/2,
mouseY + gui.getYSize()/2 - gui.height/2);
}
}
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
} catch (Exception e){
e.printStackTrace();
}
}
// Third person
@SubscribeEvent
@@ -23,6 +23,7 @@ import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.util.WildcardTradeList;
import electroblob.wizardry.util.WizardryParticleType;
import electroblob.wizardry.util.WizardryUtilities;
import io.netty.buffer.ByteBuf;
@@ -91,6 +92,7 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit
* are overriding something, in which case it should be fine). */
// Extending EntityVillager turned out to be a pretty neat thing to do, since now zombies will attack wizards
// TODO: Perhaps we should be implementing IMerchant now instead?
private EntityAIAttackSpell spellCastingAI = new EntityAIAttackSpell(this, 0.5D, 14.0F, 30, 50);
@@ -369,7 +371,7 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit
if(nbt.hasKey("trades")){
NBTTagCompound nbttagcompound1 = nbt.getCompoundTag("trades");
this.trades = new MerchantRecipeList(nbttagcompound1);
this.trades = new WildcardTradeList(nbttagcompound1);
}
this.setElement(Element.values()[nbt.getInteger("element")]);
@@ -428,7 +430,7 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit
if(this.trades == null){
this.trades = new MerchantRecipeList();
this.trades = new WildcardTradeList();
// All wizards will buy spell books
ItemStack anySpellBook = new ItemStack(WizardryItems.spell_book, 1, OreDictionary.WILDCARD_VALUE);
@@ -509,7 +511,7 @@ public class EntityWizard extends EntityVillager implements ISpellCaster, IEntit
Collections.shuffle(merchantrecipelist);
if(this.trades == null){
this.trades = new MerchantRecipeList();
this.trades = new WildcardTradeList();
}
for(int j1 = 0; j1 < merchantrecipelist.size(); ++j1){
@@ -0,0 +1,57 @@
package electroblob.wizardry.util;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.village.MerchantRecipe;
import net.minecraft.village.MerchantRecipeList;
import net.minecraftforge.oredict.OreDictionary;
/** Custom version of {@link MerchantRecipeList} which allows wildcard recipes (i.e. trades which accept items with any
* damage value). Function is otherwise identical. For some reason this feature was removed in 1.11.
* @author Electroblob
* @since Wizardry 4.1 */
@SuppressWarnings("serial")
public class WildcardTradeList extends MerchantRecipeList {
public WildcardTradeList(){
super();
}
public WildcardTradeList(NBTTagCompound tag){
super(tag);
}
@Override
public MerchantRecipe canRecipeBeUsed(ItemStack offer1, ItemStack offer2, int index){
if(index > 0 && index < this.size()){
MerchantRecipe merchantrecipe1 = (MerchantRecipe)this.get(index);
return !this.areItemStacksExactlyEqual(offer1, merchantrecipe1.getItemToBuy()) || (!offer2.isEmpty() || merchantrecipe1.hasSecondItemToBuy()) && (!merchantrecipe1.hasSecondItemToBuy() || !this.areItemStacksExactlyEqual(offer2, merchantrecipe1.getSecondItemToBuy())) || offer1.getCount() < merchantrecipe1.getItemToBuy().getCount() || merchantrecipe1.hasSecondItemToBuy() && offer2.getCount() < merchantrecipe1.getSecondItemToBuy().getCount() ? null : merchantrecipe1;
}else{
for(int i = 0; i < this.size(); ++i){
MerchantRecipe merchantrecipe = (MerchantRecipe)this.get(i);
if (this.areItemStacksExactlyEqual(offer1, merchantrecipe.getItemToBuy()) && offer1.getCount() >= merchantrecipe.getItemToBuy().getCount() && (!merchantrecipe.hasSecondItemToBuy() && offer2.isEmpty() || merchantrecipe.hasSecondItemToBuy() && this.areItemStacksExactlyEqual(offer2, merchantrecipe.getSecondItemToBuy()) && offer2.getCount() >= merchantrecipe.getSecondItemToBuy().getCount())){
return merchantrecipe;
}
}
return null;
}
}
private boolean areItemStacksExactlyEqual(ItemStack stack1, ItemStack stack2){
// Added to allow wildcards; this line is the only actual change.
if((stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE || stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE)
// Can't use ItemStack.areItemsEqualIgnoreDurability because that only works for items with durability, not subtypes.
&& stack1.getItem() == stack2.getItem()) return true;
return ItemStack.areItemsEqual(stack1, stack2) && (!stack2.hasTagCompound() || stack1.hasTagCompound() && NBTUtil.areNBTEquals(stack2.getTagCompound(), stack1.getTagCompound(), false));
}
}