package com.austinv11.peripheralsplusplus.turtles.peripherals; import com.austinv11.peripheralsplusplus.reference.Config; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import net.minecraft.enchantment.EnchantmentData; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.item.EntityXPOrb; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.Vec3; import java.util.List; import java.util.Random; public class PeripheralXP extends MountedPeripheral {//Beware, a lot of the math was taken from the mind of RichardG (meaning, I don't really understand all of it) private static final int MAX_LEVEL = 30; private static final double COLLECT_RANGE = 2.0D; private final BetterRandom random = new BetterRandom(); private int experience = 0; private int experienceRemainder = 0; private int experienceLevel = 0; private boolean autoCollect = false; private int ticker = random.nextInt(20); public boolean changed = false; private ITurtleAccess turtle; private TurtleSide side; public PeripheralXP(ITurtleAccess turtleAccess, TurtleSide side) { turtle = turtleAccess; this.side = side; NBTTagCompound tag = turtle.getUpgradeNBTData(side); experience = tag.getInteger("experience"); experienceRemainder = tag.getInteger("experienceRemainder"); experienceLevel = tag.getInteger("experienceLevel"); random.setSeed(tag.getLong("rndSeed")); } public void update() { if (autoCollect && ++ticker >= 20) { ticker = 0; addExperience(collect()); changed = true; } if (changed) { NBTTagCompound tag = turtle.getUpgradeNBTData(side); tag.setInteger("experience", experience); tag.setInteger("experienceRemainder", experienceRemainder); tag.setInteger("experienceLevel", experienceLevel); tag.setLong("rndSeed", random.getSeed()); turtle.updateUpgradeNBTData(side); changed = false; } } public void addExperience(int amount) { int var = Integer.MAX_VALUE - this.experience; if (amount > var) amount = var; this.experienceRemainder += amount; for (this.experience += amount; this.experienceRemainder < 0 || this.experienceRemainder >= levelXP(experienceLevel); this.experienceRemainder -= levelXP(experienceLevel) * (this.experienceRemainder < 0 ? -1 : 1)){ this.addLevels(this.experienceRemainder < 0 ? -1 : 1, false); } } public void addLevels(int par1, boolean updateXP) { this.experienceLevel += par1; if (this.experienceLevel < 0) this.experienceLevel = 0; if (updateXP) experience = calculateLevelXP(experienceLevel) + experienceRemainder; } public int levelXP(int level) { return level >= 30 ? 62 + (level - 30) * 7 : (level >= 15 ? 17 + (level - 15) * 3 : 17); } public int calculateLevelXP(int level) { int levelXP = 0; for (int currentLevel = 1;currentLevel <= level;currentLevel++) { levelXP += levelXP(currentLevel); } return levelXP; } private int collect() { int ret = 0; Vec3 pos = Vec3.createVectorHelper(turtle.getPosition().posX,turtle.getPosition().posY,turtle.getPosition().posZ); for (EntityXPOrb orb : (List<EntityXPOrb>)turtle.getWorld().getEntitiesWithinAABB(EntityXPOrb.class, AxisAlignedBB.getBoundingBox(pos.xCoord - COLLECT_RANGE, pos.yCoord - COLLECT_RANGE, pos.zCoord - COLLECT_RANGE, pos.xCoord + 1.0D + COLLECT_RANGE, pos.yCoord + 1.0D + COLLECT_RANGE, pos.zCoord + 1.0D + COLLECT_RANGE))) { ret += orb.getXpValue(); orb.setDead(); } return ret; } @Override public String getType() { return "xp"; } @Override public String[] getMethodNames() { return new String[] {"add", "getXP", "getLevels", "collect", "setAutoCollect", "enchant"}; } @Override public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException { if (!Config.enableXPTurtle) throw new LuaException("XP Turtles have been disabled"); ItemStack slot; switch (method) { case 0: slot = turtle.getInventory().getStackInSlot(turtle.getSelectedSlot()); int amount = Integer.MAX_VALUE; if (arguments.length > 0) { if (!(arguments[0] instanceof Double)) throw new LuaException("Bad argument #1 (expected number)"); amount = (int)Math.floor((Double)arguments[0]); } if (slot == null) return new Object[] {0}; amount = Math.min(amount, slot.stackSize); int recharge = 0; if (slot.isItemEqual(new ItemStack(Items.experience_bottle))) { recharge = 3 + random.nextInt(5) + random.nextInt(5); } recharge *= amount; addExperience(recharge); if (recharge > 0) { slot.stackSize -= amount; if (slot.stackSize <= 0) slot = null; turtle.getInventory().setInventorySlotContents(turtle.getSelectedSlot(), slot); } changed = true; return new Object[] {recharge}; case 1: return new Object[] {experience}; case 2: return new Object[] {experienceLevel}; case 3: int collected = collect(); addExperience(collected); changed = true; return new Object[] {collected}; case 4: boolean ac = !autoCollect; if (arguments.length > 0) { if (!(arguments[0] instanceof Boolean)) throw new LuaException("Bad argument #1 (expected boolean)"); ac = (Boolean)arguments[0]; } autoCollect = ac; return new Object[] {autoCollect}; case 5: if (arguments.length < 1) throw new LuaException("Too few arguments"); if (!(arguments[0] instanceof Double)) throw new LuaException("Bad argument #1 (expected number)"); int levels = (int)Math.floor((Double)arguments[0]); if (levels < 1 || levels > MAX_LEVEL) throw new LuaException("invalid level count "+levels+" (expected 1-"+MAX_LEVEL+")"); slot = turtle.getInventory().getStackInSlot(turtle.getSelectedSlot()); if (!slot.isItemEnchantable()) return new Object[] {false}; if (experienceLevel < levels) return new Object[] {false}; List enchants = EnchantmentHelper.buildEnchantmentList(random, slot, levels); if (enchants == null || enchants.isEmpty()) return new Object[] {false}; ItemStack enchanted = slot.copy(); if (enchanted.isItemEqual(new ItemStack(Items.book))) { enchanted = new ItemStack(Items.enchanted_book); enchanted.stackTagCompound = new NBTTagCompound(); NBTTagList storedEnchantments = new NBTTagList(); NBTTagCompound enchantment = new NBTTagCompound(); EnchantmentData data = (EnchantmentData)enchants.get(0); enchantment.setShort("id", (short)data.enchantmentobj.effectId); enchantment.setShort("lvl", (short)data.enchantmentLevel); storedEnchantments.appendTag(enchantment); enchanted.stackTagCompound.setTag("StoredEnchantments", storedEnchantments); } else { for (EnchantmentData data : (List<EnchantmentData>)enchants) { enchanted.addEnchantment(data.enchantmentobj, data.enchantmentLevel); } } addLevels(-levels, true); turtle.getInventory().setInventorySlotContents(turtle.getSelectedSlot(), enchanted); changed = true; return new Object[] {true}; } return new Object[0]; } @Override public boolean equals(IPeripheral other) { return (other == this); } private class BetterRandom extends Random { private long seed; @Override public void setSeed(long seed) { super.setSeed(seed); this.seed = seed; } public long getSeed() { return seed; } } }