blob: 0342d8c5853cbef5b4abba49ba92d2d8723f8d2e [file] [log] [blame] [raw]
package li.cil.oc.common
import java.io
import java.util.Random
import java.util.concurrent.Callable
import cpw.mods.fml.common.Loader
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import li.cil.oc.Constants
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.fs.FileSystem
import li.cil.oc.common.init.Items
import li.cil.oc.util.Color
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.WeightedRandomChestContent
import net.minecraftforge.common.ChestGenHooks
import net.minecraftforge.common.DimensionManager
import net.minecraftforge.common.util.Constants.NBT
import net.minecraftforge.event.world.WorldEvent
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
class Loot extends WeightedRandomChestContent(api.Items.get(Constants.ItemName.Floppy).createItemStack(1), 1, 1, Settings.get.lootProbability) {
override def generateChestContent(random: Random, newInventory: IInventory) =
if (Loot.disksForSampling.nonEmpty)
ChestGenHooks.generateStacks(random, Loot.disksForSampling(random.nextInt(Loot.disksForSampling.length)),
theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem)
else Array.empty[ItemStack]
}
object Loot {
val containers = Array(
ChestGenHooks.DUNGEON_CHEST,
ChestGenHooks.PYRAMID_DESERT_CHEST,
ChestGenHooks.PYRAMID_JUNGLE_CHEST,
ChestGenHooks.STRONGHOLD_LIBRARY)
val factories = mutable.Map.empty[String, Callable[FileSystem]]
val globalDisks = mutable.ArrayBuffer.empty[(ItemStack, Int)]
val worldDisks = mutable.ArrayBuffer.empty[(ItemStack, Int)]
def disksForCycling = if(disksForCyclingClient.nonEmpty) disksForCyclingClient else disksForCyclingServer
val disksForCyclingServer = mutable.ArrayBuffer.empty[ItemStack]
val disksForCyclingClient = mutable.ArrayBuffer.empty[ItemStack]
val disksForSampling = mutable.ArrayBuffer.empty[ItemStack]
val disksForClient = mutable.ArrayBuffer.empty[ItemStack]
def isLootDisk(stack: ItemStack): Boolean = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy) && stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "lootFactory", NBT.TAG_STRING)
def registerLootDisk(name: String, color: Int, factory: Callable[FileSystem], doRecipeCycling: Boolean): ItemStack = {
val mod = Loader.instance.activeModContainer.getModId
OpenComputers.log.info(s"Registering loot disk '$name' from mod $mod.")
val modSpecificName = mod + ":" + name
val data = new NBTTagCompound()
data.setString(Settings.namespace + "fs.label", name)
val nbt = new NBTTagCompound()
nbt.setTag(Settings.namespace + "data", data)
// Store this top level, so it won't get wiped on save.
nbt.setString(Settings.namespace + "lootFactory", modSpecificName)
nbt.setInteger(Settings.namespace + "color", color max 0 min 15)
val stack = Items.get(Constants.ItemName.Floppy).createItemStack(1)
stack.setTagCompound(nbt)
Loot.factories += modSpecificName -> factory
if(doRecipeCycling) {
Loot.disksForCyclingServer += stack
}
stack.copy()
}
def init() {
for (container <- containers) {
ChestGenHooks.addItem(container, new Loot())
}
val list = new java.util.Properties()
val listStream = getClass.getResourceAsStream("/assets/" + Settings.resourceDomain + "/loot/loot.properties")
list.load(listStream)
listStream.close()
parseLootDisks(list, globalDisks, external = false)
}
@SubscribeEvent
def initForWorld(e: WorldEvent.Load): Unit = if (!e.world.isRemote && e.world.provider.dimensionId == 0) {
worldDisks.clear()
disksForSampling.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, external = true)
}
catch {
case t: Throwable => OpenComputers.log.warn("Failed opening loot descriptor file in saves folder.")
}
}
}
for (entry <- globalDisks if !worldDisks.contains(entry)) {
worldDisks += entry
}
for ((stack, count) <- worldDisks) {
for (i <- 0 until count) {
disksForSampling += stack
}
}
}
private def parseLootDisks(list: java.util.Properties, acc: mutable.ArrayBuffer[(ItemStack, Int)], external: Boolean) {
for (key <- list.stringPropertyNames) {
val value = list.getProperty(key)
try value.split(":") match {
case Array(name, count, color) =>
acc += ((createLootDisk(name, key, external, Some(Color.dyes.indexOf(color))), count.toInt))
case Array(name, count) =>
acc += ((createLootDisk(name, key, external), count.toInt))
case _ =>
acc += ((createLootDisk(value, key, external), 1))
}
catch {
case t: Throwable => OpenComputers.log.warn("Bad loot descriptor: " + value, t)
}
}
}
def createLootDisk(name: String, path: String, external: Boolean, color: Option[Int] = None) = {
val callable = if (external) new Callable[FileSystem] {
override def call(): FileSystem = api.FileSystem.asReadOnly(api.FileSystem.fromSaveDirectory("loot/" + path, 0, false))
} else new Callable[FileSystem] {
override def call(): FileSystem = api.FileSystem.fromClass(OpenComputers.getClass, Settings.resourceDomain, "loot/" + path)
}
val stack = registerLootDisk(path, color.getOrElse(8), callable, doRecipeCycling = true)
stack.setStackDisplayName(name)
if (!external) {
Items.registerStack(stack, path)
}
stack
}
}