diff --git a/src/main/scala/li/cil/oc/CreativeTab.scala b/src/main/scala/li/cil/oc/CreativeTab.scala index d76309da8..75a2af441 100644 --- a/src/main/scala/li/cil/oc/CreativeTab.scala +++ b/src/main/scala/li/cil/oc/CreativeTab.scala @@ -2,18 +2,11 @@ package li.cil.oc import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly -import li.cil.oc.common.Loot import net.minecraft.creativetab.CreativeTabs object CreativeTab extends CreativeTabs(CreativeTabs.getNextID, "OpenComputers") { @SideOnly(Side.CLIENT) override def getTabIconItemIndex = Settings.get.blockId2 - override def displayAllReleventItems(list: java.util.List[_]) = { - def add[T](list: java.util.List[T], value: Any) = list.add(value.asInstanceOf[T]) - super.displayAllReleventItems(list) - Loot.disks.foreach(add(list, _)) - } - override def getTranslatedTabLabel = getTabLabel } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/Items.scala b/src/main/scala/li/cil/oc/Items.scala index 4fff8f2f9..ef5cc6025 100644 --- a/src/main/scala/li/cil/oc/Items.scala +++ b/src/main/scala/li/cil/oc/Items.scala @@ -1,13 +1,15 @@ package li.cil.oc import cpw.mods.fml.common.registry.GameRegistry -import li.cil.oc.common.item +import li.cil.oc.common.{Loot, item} import li.cil.oc.util.mods.Mods import net.minecraft.item.{Item, ItemBlock, ItemStack} import scala.collection.mutable import li.cil.oc.api.detail.{ItemAPI, ItemInfo} import net.minecraft.block.Block import li.cil.oc.common.recipe.Recipes +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.creativetab.CreativeTabs object Items extends ItemAPI { private val descriptors = mutable.Map.empty[String, ItemInfo] @@ -69,7 +71,8 @@ object Items extends ItemAPI { instance } - private def getBlockOrItem(stack: ItemStack): Any = if (stack == null) null else { + private def getBlockOrItem(stack: ItemStack): Any = if (stack == null) null + else { multi.subItem(stack).getOrElse( Blocks.blockSimple.subBlock(stack).getOrElse( Blocks.blockSimpleWithRedstone.subBlock(stack).getOrElse( @@ -93,7 +96,14 @@ object Items extends ItemAPI { var ironNugget: item.IronNugget = _ def init() { - multi = new item.Delegator(Settings.get.itemId) + multi = new item.Delegator(Settings.get.itemId) { + override def getSubItems(itemId: Int, tab: CreativeTabs, list: java.util.List[_]) { + // Workaround for MC's untyped lists... + def add[T](list: java.util.List[T], value: Any) = list.add(value.asInstanceOf[T]) + super.getSubItems(itemId, tab, list) + Loot.worldDisks.values.foreach(entry => add(list, entry._1)) + } + } GameRegistry.registerItem(multi, Settings.namespace + "item") @@ -184,5 +194,23 @@ object Items extends ItemAPI { Recipes.addItem(new item.UpgradeContainerCard(multi, 0), "cardContainer1", "oc:cardContainer1") Recipes.addItem(new item.UpgradeContainerCard(multi, 1), "cardContainer2", "oc:cardContainer2") Recipes.addItem(new item.UpgradeContainerCard(multi, 2), "cardContainer3", "oc:cardContainer3") + + // Special case loot disk because this one's craftable and having it have + // the same item damage would confuse NEI and the item costs computation. + Recipes.addItem(new item.FloppyDisk(multi) { + override def createItemStack(amount: Int) = { + val data = new NBTTagCompound() + data.setString(Settings.namespace + "fs.label", "openos") + + val nbt = new NBTTagCompound("tag") + nbt.setTag(Settings.namespace + "data", data) + nbt.setString(Settings.namespace + "lootPath", "OpenOS") + + val stack = super.createItemStack(amount) + stack.setTagCompound(nbt) + + stack + } + }, "openOS") } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/Loot.scala b/src/main/scala/li/cil/oc/common/Loot.scala index 39ba2e6a9..04b6f5529 100644 --- a/src/main/scala/li/cil/oc/common/Loot.scala +++ b/src/main/scala/li/cil/oc/common/Loot.scala @@ -1,6 +1,6 @@ package li.cil.oc.common -import net.minecraftforge.common.ChestGenHooks +import net.minecraftforge.common.{DimensionManager, ChestGenHooks} import net.minecraft.util.WeightedRandomChestContent import net.minecraft.nbt.NBTTagCompound import scala.collection.convert.WrapAsScala._ @@ -8,8 +8,11 @@ import java.util.Random import net.minecraft.inventory.IInventory import net.minecraft.item.ItemStack import scala.collection.mutable -import li.cil.oc.{Settings, api} +import li.cil.oc.{OpenComputers, Settings, api} import li.cil.oc.common.recipe.Recipes +import java.io +import net.minecraftforge.event.ForgeSubscribe +import net.minecraftforge.event.world.WorldEvent object Loot extends WeightedRandomChestContent(api.Items.get("lootDisk").createItemStack(1), 1, 1, Settings.get.lootProbability) { val containers = Array( @@ -18,6 +21,10 @@ object Loot extends WeightedRandomChestContent(api.Items.get("lootDisk").createI ChestGenHooks.PYRAMID_JUNGLE_CHEST, ChestGenHooks.STRONGHOLD_LIBRARY) + val builtInDisks = mutable.Map.empty[String, (ItemStack, Int)] + + val worldDisks = mutable.Map.empty[String, (ItemStack, Int)] + val disks = mutable.ArrayBuffer.empty[ItemStack] def init() { @@ -26,16 +33,64 @@ object Loot extends WeightedRandomChestContent(api.Items.get("lootDisk").createI } val list = new java.util.Properties() - val listFile = getClass.getResourceAsStream("/assets/" + Settings.resourceDomain + "/loot/loot.properties") - list.load(listFile) - listFile.close() + val listStream = getClass.getResourceAsStream("/assets/" + Settings.resourceDomain + "/loot/loot.properties") + list.load(listStream) + listStream.close() + parseLootDisks(list, builtInDisks) - for (key <- list.stringPropertyNames) { - disks += createLootDisk(key, list.getProperty(key)) + for ((name, (stack, _)) <- builtInDisks if name == "OpenOS") { + Recipes.list += stack -> "openOS" } } - def createLootDisk(name: String, path: String) = { + @ForgeSubscribe + def initForWorld(e: WorldEvent.Load) { + worldDisks.clear() + disks.clear() + val path = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + "loot/") + if (path.exists && path.isDirectory) { + val listFile = new io.File(path, "loot.properties") + if (listFile.exists && listFile.isFile) { + try { + val listStream = new io.FileInputStream(listFile) + val list = new java.util.Properties() + list.load(listStream) + listStream.close() + parseLootDisks(list, worldDisks) + } + catch { + case t: Throwable => OpenComputers.log.warning("Failed opening loot descriptor file in saves folder.") + } + } + } + for ((name, entry) <- builtInDisks if !worldDisks.contains(name)) { + worldDisks += name -> entry + } + for ((_, (stack, count)) <- worldDisks) { + for (i <- 0 until count) { + disks += stack + } + } + } + + private def parseLootDisks(list: java.util.Properties, acc: mutable.Map[String, (ItemStack, Int)]) { + for (key <- list.stringPropertyNames if key != "OpenOS") { + val value = list.getProperty(key) + val splitAt = value.lastIndexOf(':') + if (splitAt >= 0) { + val (name, count) = value.splitAt(splitAt) + try { + acc += key -> (createLootDisk(name, key), count.toInt) + } + catch { + case _: Throwable => OpenComputers.log.warning("Bad loot descriptor: " + value) + } + } + else acc += key -> (createLootDisk(value, key), 1) + } + } + + private def createLootDisk(name: String, path: String) = { val data = new NBTTagCompound() data.setString(Settings.namespace + "fs.label", name) @@ -47,10 +102,6 @@ object Loot extends WeightedRandomChestContent(api.Items.get("lootDisk").createI val disk = api.Items.get("lootDisk").createItemStack(1) disk.setTagCompound(tag) - if (name == "OpenOS") { - Recipes.list += disk -> "openOS" - } - disk } diff --git a/src/main/scala/li/cil/oc/common/Proxy.scala b/src/main/scala/li/cil/oc/common/Proxy.scala index 8520e705f..78e5f4555 100644 --- a/src/main/scala/li/cil/oc/common/Proxy.scala +++ b/src/main/scala/li/cil/oc/common/Proxy.scala @@ -92,15 +92,16 @@ class Proxy { api.Driver.add(driver.converter.FluidTankInfo) api.Driver.add(driver.converter.ItemStack) + Loot.init() + Recipes.init() + GameRegistry.registerCraftingHandler(CraftingHandler) + MinecraftForge.EVENT_BUS.register(RobotCommonHandler) MinecraftForge.EVENT_BUS.register(ExperienceUpgradeHandler) if (Mods.UniversalElectricity.isAvailable) { MinecraftForge.EVENT_BUS.register(UniversalElectricityToolHandler) } - - Loot.init() - Recipes.init() - GameRegistry.registerCraftingHandler(CraftingHandler) + MinecraftForge.EVENT_BUS.register(Loot) FMLInterModComms.sendMessage("Waila", "register", "li.cil.oc.util.mods.Waila.init") } diff --git a/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala b/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala index 03522cd11..5a3e9ce65 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala @@ -47,7 +47,10 @@ class RobotAssembler extends traits.Environment with traits.Inventory with trait def start() { if (!isAssembling && robot.isEmpty && complexity <= maxComplexity) { - // TODO validate all slots, just in case. never trust a client. never trust minecraft. + for (slot <- 0 until getSizeInventory) { + val stack = getStackInSlot(slot) + if (stack != null && !isItemValidForSlot(slot, stack)) return + } val data = new ItemUtils.RobotData() data.name = ItemUtils.RobotData.randomName data.energy = 50000