/*
* KubaTech - Gregtech Addon
* Copyright (C) 2022 kuba6000
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
*
*/
package kubatech.nei;
import static kubatech.nei.Mob_Handler.Translations.*;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW_STACK_DEPTH;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.recipe.*;
import cpw.mods.fml.common.event.FMLInterModComms;
import crazypants.enderio.EnderIO;
import crazypants.enderio.machine.spawner.BlockPoweredSpawner;
import gregtech.api.util.GT_Utility;
import java.awt.*;
import java.lang.reflect.Field;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import kubatech.api.LoaderReference;
import kubatech.api.mobhandler.MobDrop;
import kubatech.api.utils.FastRandom;
import kubatech.api.utils.InfernalHelper;
import kubatech.api.utils.MobUtils;
import kubatech.api.utils.ModUtils;
import kubatech.kubatech;
import kubatech.loaders.MobRecipeLoader;
import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeExterminationChamber;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RendererLivingEntity;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLiving;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.StatCollector;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
public class Mob_Handler extends TemplateRecipeHandler {
enum Translations {
NORMAL_DROPS,
RARE_DROPS,
ADDITIONAL_DROPS,
INFERNAL_DROPS,
INFERNAL_CANNOT,
INFERNAL_CAN,
INFERNAL_ALWAYS,
CHANCE,
AVERAGE_REMINDER,
MOD,
MAX_HEALTH,
LOOTABLE,
PLAYER_ONLY,
;
final String key;
Translations() {
key = "mobhandler." + this.name().toLowerCase();
}
public String get() {
return StatCollector.translateToLocal(key);
}
public String get(Object... args) {
return StatCollector.translateToLocalFormatted(key, args);
}
public String getKey() {
return key;
}
@Override
public String toString() {
return get();
}
}
private static final Mob_Handler instance = new Mob_Handler();
private static final List cachedRecipes = new ArrayList<>();
public static int cycleTicksStatic = Math.abs((int) System.currentTimeMillis());
private static final int itemsPerRow = 8, itemXShift = 18, itemYShift = 18, nextRowYShift = 35;
public static void addRecipe(EntityLiving e, List drop) {
List positionedStacks = new ArrayList<>();
int xorigin = 7,
xoffset = xorigin,
yoffset = 95,
normaldrops = 0,
raredrops = 0,
additionaldrops = 0,
infernaldrops = 0;
MobDrop.DropType i = null;
for (MobDrop d : drop) {
if (i == d.type) {
xoffset += itemXShift;
if (xoffset >= xorigin + (itemXShift * itemsPerRow)) {
xoffset = xorigin;
yoffset += itemYShift;
}
}
if (i != null && i != d.type) {
xoffset = xorigin;
yoffset += nextRowYShift;
}
i = d.type;
if (d.type == MobDrop.DropType.Normal) normaldrops++;
else if (d.type == MobDrop.DropType.Rare) raredrops++;
else if (d.type == MobDrop.DropType.Additional) additionaldrops++;
else if (d.type == MobDrop.DropType.Infernal) break; // dont render infernal drops
positionedStacks.add(new MobPositionedStack(
d.stack.copy(),
xoffset,
yoffset,
d.type,
d.chance,
d.enchantable,
d.damages != null ? new ArrayList<>(d.damages.keySet()) : null,
d.lootable,
d.playerOnly));
}
instance.addRecipeInt(e, positionedStacks, normaldrops, raredrops, additionaldrops, infernaldrops);
}
private void addRecipeInt(
EntityLiving e,
List l,
int normaldrops,
int raredrops,
int additionaldrops,
int infernalDrops) {
cachedRecipes.add(new MobCachedRecipe(e, l, normaldrops, raredrops, additionaldrops, infernalDrops));
}
public static void clearRecipes() {
cachedRecipes.clear();
}
public static void sortCachedRecipes() {
cachedRecipes.sort((o1, o2) -> {
boolean m1 = o1.mod.equals("Minecraft");
boolean m2 = o2.mod.equals("Minecraft");
if (m1 && !m2) return -1;
else if (!m1 && m2) return 1;
if (!o1.mod.equals(o2.mod)) return o1.mod.compareTo(o2.mod);
else return o1.localizedName.compareTo(o2.localizedName);
});
}
public Mob_Handler() {
this.transferRects.add(new RecipeTransferRect(new Rectangle(7, 62, 16, 16), getOverlayIdentifier()));
if (!NEI_Config.isAdded) {
FMLInterModComms.sendRuntimeMessage(
kubatech.instance,
"NEIPlugins",
"register-crafting-handler",
"kubatech@" + getRecipeName() + "@" + getOverlayIdentifier());
GuiCraftingRecipe.craftinghandlers.add(this);
GuiUsageRecipe.usagehandlers.add(this);
}
}
@Override
public TemplateRecipeHandler newInstance() {
return new Mob_Handler();
}
@Override
public String getOverlayIdentifier() {
return "kubatech.mobhandler";
}
@Override
public String getGuiTexture() {
return "kubatech:textures/gui/MobHandler.png";
}
private static final Field mainmodelfield;
static {
try {
mainmodelfield = RendererLivingEntity.class.getDeclaredField(
ModUtils.isDeobfuscatedEnvironment ? "mainModel" : "field_77045_g");
mainmodelfield.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
@Override
public void drawBackground(int recipe) {
GL11.glColor4f(1f, 1f, 1f, 1f);
GuiDraw.changeTexture(getGuiTexture());
GuiDraw.drawTexturedModalRect(0, 0, 0, 0, 168, 192);
MobCachedRecipe currentrecipe = ((MobCachedRecipe) arecipes.get(recipe));
{
int x = 6, y = 94, yshift = nextRowYShift;
if (currentrecipe.normalOutputsCount > 0) {
for (int i = 0; i < ((currentrecipe.normalOutputsCount - 1) / itemsPerRow) + 1; i++) {
GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18);
if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2);
}
y += yshift + ((currentrecipe.normalOutputsCount - 1) / itemsPerRow) * 18;
}
if (currentrecipe.rareOutputsCount > 0) {
for (int i = 0; i < ((currentrecipe.rareOutputsCount - 1) / itemsPerRow) + 1; i++) {
GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18);
if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2);
}
y += yshift + ((currentrecipe.rareOutputsCount - 1) / itemsPerRow) * 18;
}
if (currentrecipe.additionalOutputsCount > 0) {
for (int i = 0; i < ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) + 1; i++) {
GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18);
if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2);
}
y += yshift + ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) * 18;
}
if (currentrecipe.infernalOutputsCount > 0) {
for (int i = 0; i < ((currentrecipe.infernalOutputsCount - 1) / itemsPerRow) + 1; i++) {
GuiDraw.drawTexturedModalRect(x, y + (18 * i), 0, 192, 144, 18);
if (i > 0) GuiDraw.drawTexturedModalRect(x, y + ((18 * i) - 1), 0, 193, 144, 2);
}
}
}
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glColor4f(1f, 1f, 1f, 1f);
Minecraft mc = Minecraft.getMinecraft();
ScaledResolution scale = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
int width = scale.getScaledWidth();
int height = scale.getScaledHeight();
int mouseX = Mouse.getX() * width / mc.displayWidth;
int mouseZ = height - Mouse.getY() * height / mc.displayHeight - 1;
// Get current x,y from matrix
FloatBuffer buf = BufferUtils.createFloatBuffer(16);
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, buf);
float x = buf.get(12);
float y = buf.get(13);
int stackdepth = GL11.glGetInteger(GL_MODELVIEW_STACK_DEPTH);
GL11.glPushMatrix();
try {
EntityLiving e = currentrecipe.mob;
float eheight = MobUtils.getMobHeight(e);
float scaled = MobUtils.getDesiredScale(eheight, 27);
//
// int maxwidth = 15;
// scaled = (int) Math.min(scaled, maxwidth / ewidth);
int mobx = 30, moby = 50;
e.setPosition(mc.thePlayer.posX + 5, mc.thePlayer.posY, mc.thePlayer.posZ);
// ARGS: x, y, scale, rot, rot, entity
GuiInventory.func_147046_a(
mobx, moby, Math.round(scaled), (x + mobx) - mouseX, y + moby - eheight * scaled - mouseZ, e);
} catch (Throwable ex) {
Tessellator tes = Tessellator.instance;
try {
tes.draw();
} catch (Exception ignored) {
}
}
stackdepth -= GL11.glGetInteger(GL_MODELVIEW_STACK_DEPTH);
if (stackdepth < 0) for (; stackdepth < 0; stackdepth++) GL11.glPopMatrix();
GL11.glDisable(GL11.GL_DEPTH_TEST);
}
@Override
public void drawForeground(int recipe) {
MobCachedRecipe currentrecipe = ((MobCachedRecipe) arecipes.get(recipe));
int y = 7, yshift = 10, x = 57;
GuiDraw.drawString(currentrecipe.localizedName, x, y, 0xFF555555, false);
if (Minecraft.getMinecraft().gameSettings.advancedItemTooltips && NEIClientUtils.shiftKey())
GuiDraw.drawString(currentrecipe.mobname, x, y += yshift, 0xFF555555, false);
GuiDraw.drawString(MOD.get() + currentrecipe.mod, x, y += yshift, 0xFF555555, false);
GuiDraw.drawString(MAX_HEALTH.get() + currentrecipe.maxHealth, x, y += yshift, 0xFF555555, false);
switch (currentrecipe.infernaltype) {
case -1:
break;
case 0:
GuiDraw.drawString(INFERNAL_CANNOT.get(), x, y += yshift, 0xFF555555, false);
break;
case 1:
GuiDraw.drawString(INFERNAL_CAN.get(), x, y += yshift, 0xFFFF0000, false);
break;
case 2:
GuiDraw.drawString(INFERNAL_ALWAYS.get(), x, y += yshift, 0xFFFF0000, false);
break;
}
MobRecipeLoader.MobRecipe MBRecipe =
GT_MetaTileEntity_ExtremeExterminationChamber.MobNameToRecipeMap.get(currentrecipe.mobname);
if (MBRecipe != null) {
GuiDraw.drawString(
GT_Utility.trans("153", "Usage: ") + GT_Utility.formatNumbers(MBRecipe.mEUt) + " EU/t",
x,
y += yshift,
0xFF555555,
false);
GuiDraw.drawString(
GT_Utility.trans("158", "Time: ") + GT_Utility.formatNumbers(MBRecipe.mDuration / 20d) + " secs",
x,
y += yshift,
0xFF555555,
false);
}
x = 6;
y = 83;
yshift = nextRowYShift;
if (currentrecipe.normalOutputsCount > 0) {
GuiDraw.drawString(NORMAL_DROPS.get(), x, y, 0xFF555555, false);
y += yshift + ((currentrecipe.normalOutputsCount - 1) / itemsPerRow) * 18;
}
if (currentrecipe.rareOutputsCount > 0) {
GuiDraw.drawString(RARE_DROPS.get(), x, y, 0xFF555555, false);
y += yshift + ((currentrecipe.rareOutputsCount - 1) / itemsPerRow) * 18;
}
if (currentrecipe.additionalOutputsCount > 0) {
GuiDraw.drawString(ADDITIONAL_DROPS.get(), x, y, 0xFF555555, false);
y += yshift + ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) * 18;
}
if (currentrecipe.infernalOutputsCount > 0) {
GuiDraw.drawString(INFERNAL_DROPS.get(), x, y, 0xFF555555, false);
y += yshift + ((currentrecipe.additionalOutputsCount - 1) / itemsPerRow) * 18;
}
yshift = 10;
}
@Override
public String getRecipeName() {
return "Mob Drops";
}
@Override
public IUsageHandler getUsageAndCatalystHandler(String inputId, Object... ingredients) {
if (inputId.equals("item")) {
TemplateRecipeHandler handler = newInstance();
ItemStack candidate = (ItemStack) ingredients[0];
if (RecipeCatalysts.containsCatalyst(handler, candidate)) {
handler.loadCraftingRecipes(getOverlayIdentifier(), (Object) null);
return handler;
}
}
return this.getUsageHandler(inputId, ingredients);
}
@Override
public void loadCraftingRecipes(String outputId, Object... results) {
if (outputId.equals(getOverlayIdentifier())) {
arecipes.addAll(cachedRecipes);
return;
}
super.loadCraftingRecipes(outputId, results);
}
@Override
public void loadCraftingRecipes(ItemStack result) {
for (MobCachedRecipe r : cachedRecipes) if (r.contains(r.mOutputs, result)) arecipes.add(r);
}
@Override
public void loadUsageRecipes(ItemStack ingredient) {
if (LoaderReference.EnderIO && ingredient.getItem() == Item.getItemFromBlock(EnderIO.blockPoweredSpawner)) {
if (!ingredient.hasTagCompound() || !ingredient.getTagCompound().hasKey("mobType")) {
loadCraftingRecipes(getOverlayIdentifier(), (Object) null);
return;
}
for (MobCachedRecipe r : cachedRecipes)
if (r.mInput.stream()
.anyMatch(s -> s.getItem() == ingredient.getItem()
&& Objects.equals(
s.getTagCompound().getString("mobType"),
ingredient.getTagCompound().getString("mobType")))) arecipes.add(r);
} else
for (MobCachedRecipe r : cachedRecipes)
if (r.mInput.stream().anyMatch(ingredient::isItemEqual)) arecipes.add(r);
}
@Override
public void onUpdate() {
cycleTicksStatic++;
}
public static class MobPositionedStack extends PositionedStack {
public final MobDrop.DropType type;
public final int chance;
public final boolean enchantable;
public final boolean randomdamage;
public final List damages;
public final int enchantmentLevel;
private final Random rand;
public MobPositionedStack(
Object object,
int x,
int y,
MobDrop.DropType type,
int chance,
Integer enchantable,
List damages,
boolean lootable,
boolean isPlayerOnly) {
super(object, x, y, false);
rand = new FastRandom();
this.type = type;
this.chance = chance;
this.enchantable = enchantable != null;
if (this.enchantable) enchantmentLevel = enchantable;
else enchantmentLevel = 0;
this.randomdamage = damages != null;
if (this.randomdamage) this.damages = damages;
else this.damages = null;
NBTTagList extratooltip = new NBTTagList();
if (chance != 10000)
extratooltip.appendTag(new NBTTagString(
EnumChatFormatting.RESET + CHANCE.get() + (chance / 100) + "." + (chance % 100) + "%"));
if (lootable) extratooltip.appendTag(new NBTTagString(EnumChatFormatting.RESET + LOOTABLE.get()));
if (isPlayerOnly) extratooltip.appendTag(new NBTTagString(EnumChatFormatting.RESET + PLAYER_ONLY.get()));
extratooltip.appendTag(new NBTTagString(EnumChatFormatting.RESET + AVERAGE_REMINDER.get()));
NBTTagCompound itemtag = this.items[0].getTagCompound();
if (itemtag == null) itemtag = new NBTTagCompound();
NBTTagCompound display = new NBTTagCompound();
if (itemtag.hasKey("display")) {
display = itemtag.getCompoundTag("display");
if (display.hasKey("Lore")) {
NBTTagList lore = display.getTagList("Lore", 8);
for (int i = 0; i < extratooltip.tagCount(); i++)
lore.appendTag(new NBTTagString(extratooltip.getStringTagAt(i)));
display.setTag("Lore", lore);
} else display.setTag("Lore", extratooltip);
} else display.setTag("Lore", extratooltip);
itemtag.setTag("display", display);
this.items[0].setTagCompound(itemtag);
this.item.setTagCompound((NBTTagCompound) itemtag.copy());
setPermutationToRender(0);
}
@Override
public void setPermutationToRender(int index) {
if (this.item == null) this.item = this.items[0].copy();
if (enchantable) {
if (this.item.getItem() == Items.enchanted_book) this.item = this.items[0].copy();
this.item.getTagCompound().removeTag("ench");
EnchantmentHelper.addRandomEnchantment(rand, this.item, enchantmentLevel);
}
if (randomdamage) this.item.setItemDamage(damages.get(rand.nextInt(damages.size())));
}
}
private class MobCachedRecipe extends TemplateRecipeHandler.CachedRecipe {
public final EntityLiving mob;
public final List mOutputs;
public final List mInput;
public final String mobname;
public final int infernaltype;
public final PositionedStack ingredient;
public final String localizedName;
public final String mod;
public final float maxHealth;
public final int normalOutputsCount;
public final int rareOutputsCount;
public final int additionalOutputsCount;
public final int infernalOutputsCount;
public MobCachedRecipe(
EntityLiving mob,
List mOutputs,
int normalOutputsCount,
int rareOutputsCount,
int additionalOutputsCount,
int infernalOutputsCount) {
super();
String classname = mob.getClass().getName();
this.mod = ModUtils.getModNameFromClassName(classname);
this.mob = mob;
this.maxHealth = mob.getMaxHealth();
this.mOutputs = new ArrayList<>(mOutputs.size());
this.mOutputs.addAll(mOutputs);
this.normalOutputsCount = normalOutputsCount;
this.rareOutputsCount = rareOutputsCount;
this.additionalOutputsCount = additionalOutputsCount;
this.infernalOutputsCount = infernalOutputsCount;
this.mInput = new ArrayList<>();
int id = EntityList.getEntityID(mob);
mobname = EntityList.getEntityString(mob);
localizedName = StatCollector.translateToLocal("entity." + mobname + ".name");
if (id != 0) {
this.mInput.add(new ItemStack(Items.spawn_egg, 1, id));
this.mInput.add(new ItemStack(Blocks.mob_spawner, 1, id));
}
if (LoaderReference.EnderIO) {
ItemStack s = new ItemStack(EnderIO.blockPoweredSpawner, 1);
NBTTagCompound nbt = new NBTTagCompound();
BlockPoweredSpawner.writeMobTypeToNBT(nbt, mobname);
s.setTagCompound(nbt);
this.mInput.add(0, s);
} else if (id == 0) this.mInput.add(new ItemStack(Items.spawn_egg, 1, 0)); // ???
ingredient = new PositionedStack(this.mInput.get(0), 38, 44, false);
if (!LoaderReference.InfernalMobs) infernaltype = -1; // not supported
else {
if (!InfernalHelper.isClassAllowed(mob)) infernaltype = 0; // not allowed
else if (InfernalHelper.checkEntityClassForced(mob)) infernaltype = 2; // forced
else infernaltype = 1; // normal
}
}
@Override
public PositionedStack getIngredient() {
return ingredient;
}
@Override
public PositionedStack getResult() {
return null;
}
@Override
public List getOtherStacks() {
if (cycleTicksStatic % 10 == 0) mOutputs.forEach(p -> p.setPermutationToRender(0));
return mOutputs;
}
}
}