diff --git a/src/main/java/com/hbm/hazard/HazardData.java b/src/main/java/com/hbm/hazard/HazardData.java new file mode 100644 index 000000000..236937fcd --- /dev/null +++ b/src/main/java/com/hbm/hazard/HazardData.java @@ -0,0 +1,52 @@ +package com.hbm.hazard; + +import java.util.ArrayList; +import java.util.List; + +import com.hbm.hazard.type.HazardTypeBase; + +public class HazardData { + + /* + * Purges all previously loaded data when read, useful for when specific items should fully override ore dict data. + */ + boolean doesOverride = false; + /* + * MUTEX, even more precise to make only specific entries mutually exclusive, for example oredict aliases such as plutonium238 and pu238. + * Does the opposite of overrides, if a previous entry collides with this one, this one will yield. + * + * RESERVED BITS (please keep this up to date) + * -1: base material aliases ("ingotX") + */ + int mutexBits = 0b0000_0000_0000_0000_0000_0000_0000_0000; + + List entries = new ArrayList(); + + public HazardData addEntry(HazardTypeBase hazard) { + return this.addEntry(hazard, 1F, false); + } + + public HazardData addEntry(HazardTypeBase hazard, float level) { + return this.addEntry(hazard, level, false); + } + + public HazardData addEntry(HazardTypeBase hazard, float level, boolean override) { + this.entries.add(new HazardEntry(hazard, level)); + this.doesOverride = override; + return this; + } + + public HazardData addEntry(HazardEntry entry) { + this.entries.add(entry); + return this; + } + + public HazardData setMutex(int mutex) { + this.mutexBits = mutex; + return this; + } + + public int getMutex() { + return mutexBits; + } +} diff --git a/src/main/java/com/hbm/hazard/HazardEntry.java b/src/main/java/com/hbm/hazard/HazardEntry.java new file mode 100644 index 000000000..1240aae21 --- /dev/null +++ b/src/main/java/com/hbm/hazard/HazardEntry.java @@ -0,0 +1,42 @@ +package com.hbm.hazard; + +import java.util.ArrayList; +import java.util.List; + +import com.hbm.hazard.type.HazardTypeBase; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; + +public class HazardEntry { + + HazardTypeBase type; + float baseLevel; + + /* + * Modifiers are evaluated in the order they're being applied to the entry. + */ + List mods = new ArrayList(); + + public HazardEntry(HazardTypeBase type) { + this(type, 1F); + } + + public HazardEntry(HazardTypeBase type, float level) { + this.type = type; + this.baseLevel = level; + } + + public HazardEntry addMod(HazardModifier mod) { + this.mods.add(mod); + return this; + } + + public void applyHazard(ItemStack stack, EntityLivingBase entity) { + type.onUpdate(entity, HazardModifier.evalAllModifiers(stack, entity, baseLevel, mods)); + } + + public HazardTypeBase getType() { + return this.type; + } +} diff --git a/src/main/java/com/hbm/hazard/HazardModifier.java b/src/main/java/com/hbm/hazard/HazardModifier.java new file mode 100644 index 000000000..4f9eb3f37 --- /dev/null +++ b/src/main/java/com/hbm/hazard/HazardModifier.java @@ -0,0 +1,28 @@ +package com.hbm.hazard; + +import java.util.List; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; + +public abstract class HazardModifier { + + public abstract float modify(ItemStack stack, EntityLivingBase holder, float level); + + /** + * Returns the level after applying all modifiers to it, in order. + * @param stack + * @param entity + * @param level + * @param mods + * @return + */ + public static float evalAllModifiers(ItemStack stack, EntityLivingBase entity, float level, List mods) { + + for(HazardModifier mod : mods) { + level = mod.modify(stack, entity, level); + } + + return level; + } +} diff --git a/src/main/java/com/hbm/hazard/HazardRegistry.java b/src/main/java/com/hbm/hazard/HazardRegistry.java new file mode 100644 index 000000000..13bd1b457 --- /dev/null +++ b/src/main/java/com/hbm/hazard/HazardRegistry.java @@ -0,0 +1,26 @@ +package com.hbm.hazard; + +import com.hbm.hazard.type.HazardTypeBase; +import com.hbm.hazard.type.HazardTypeRadiation; +import com.hbm.items.special.ItemHazard; + +public class HazardRegistry { + + public static final HazardTypeBase RADIATION = new HazardTypeRadiation(); + + public static void registerItems() { + HazardSystem.register("ingotPlutonium", makeData(RADIATION, ItemHazard.pu * ItemHazard.ingot)); + } + + private static HazardData makeData() { return new HazardData(); } + private static HazardData makeData(HazardTypeBase hazard) { return new HazardData().addEntry(hazard); } + private static HazardData makeData(HazardTypeBase hazard, float level) { return new HazardData().addEntry(hazard, level); } + private static HazardData makeData(HazardTypeBase hazard, float level, boolean override) { return new HazardData().addEntry(hazard, level, override); } + + public static void reloadSystem() { + HazardSystem.oreMap.clear(); + HazardSystem.itemMap.clear(); + HazardSystem.stackMap.clear(); + registerItems(); + } +} diff --git a/src/main/java/com/hbm/hazard/HazardSystem.java b/src/main/java/com/hbm/hazard/HazardSystem.java new file mode 100644 index 000000000..37be806d4 --- /dev/null +++ b/src/main/java/com/hbm/hazard/HazardSystem.java @@ -0,0 +1,169 @@ +package com.hbm.hazard; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import com.hbm.interfaces.Untested; +import com.hbm.inventory.RecipesCommon.ComparableStack; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import scala.xml.PrettyPrinter.Item; + +@Untested +public class HazardSystem { + + /* + * Map for OreDict entries, always evaluated first. Avoid registering HazardData with 'doesOverride', as internal order is based on the item's ore dict keys. + */ + public static final HashMap oreMap = new HashMap(); + /* + * Map for items, either with wildcard meta or stuff that's expected to have a variety of damage values, like tools. + */ + public static final HashMap itemMap = new HashMap(); + /* + * Very specific stacks with item and meta matching. ComparableStack does not support NBT matching, to scale hazards with NBT please use HazardModifiers. + */ + public static final HashMap stackMap = new HashMap(); + /* + * For items that should, for whichever reason, be completely exempt from the hazard system. + */ + public static final HashSet blacklist = new HashSet(); + + /** + * Automatically casts the first parameter and registers it to the HazSys + * @param o + * @param data + */ + public static void register(Object o, HazardData data) { + + if(o instanceof String) + oreMap.put((String)o, data); + if(o instanceof Item) + itemMap.put((Item)o, data); + if(o instanceof ItemStack) + stackMap.put(new ComparableStack((ItemStack)o), data); + if(o instanceof ComparableStack) + stackMap.put((ComparableStack)o, data); + } + + /** + * Prevents the stack from returning any HazardData + * @param stack + */ + public static void blacklist(ItemStack stack) { + blacklist.add(new ComparableStack(stack).makeSingular()); + } + + public static boolean isItemBlacklisted(ItemStack stack) { + return blacklist.contains(new ComparableStack(stack).makeSingular()); + } + + /** + * Will return a full list of applicable HazardEntries for this stack. + *

ORDER: + *
    + *
  1. ore dict (if multiple keys, in order of the ore dict keys for this stack) + *
  2. item + *
  3. item stack + *
+ * + * "Applicable" means that entries that are overridden or excluded via mutex are not in this list. + * Entries that are marked as "overriding" will delete all fetched entries that came before it. + * Entries that use mutex will prevent subsequent entries from being considered, shall they collide. The mutex system already assumes that + * two keys are the same in priority, so the flipped order doesn't matter. + * @param stack + * @return + */ + public static List getHazardsFromStack(ItemStack stack) { + + if(isItemBlacklisted(stack)) { + return new ArrayList(); + } + + List chronological = new ArrayList(); + + /// ORE DICT /// + int[] ids = OreDictionary.getOreIDs(stack); + for(int id : ids) { + String name = OreDictionary.getOreName(id); + + if(oreMap.containsKey(name)) + chronological.add(oreMap.get(name)); + } + + /// ITEM /// + if(itemMap.containsKey(stack.getItem())) + chronological.add(itemMap.get(stack.getItem())); + + /// STACK /// + ComparableStack comp = new ComparableStack(stack).makeSingular(); + if(stackMap.containsKey(comp)) + chronological.add(stackMap.get(comp)); + + List entries = new ArrayList(); + + int mutex = 0; + + for(HazardData data : chronological) { + //if the current data is marked as an override, purge all previous data + if(data.doesOverride) + entries.clear(); + + if((data.getMutex() & mutex) == 0) { + entries.addAll(data.entries); + mutex = mutex | data.getMutex(); + } + } + + return entries; + } + + /** + * Will grab and iterate through all assigned hazards of the given stack and apply their effects to the holder. + * @param stack + * @param entity + */ + public static void applyHazards(ItemStack stack, EntityLivingBase entity) { + List hazards = getHazardsFromStack(stack); + + for(HazardEntry hazard : hazards) { + hazard.applyHazard(stack, entity); + } + } + + /** + * Will apply the effects of all carried items, including the armor inventory. + * @param player + */ + public static void updatePlayerInventory(EntityPlayer player) { + + for(ItemStack stack : player.inventory.mainInventory) { + if(stack != null) { + applyHazards(stack, player); + } + } + + for(ItemStack stack : player.inventory.armorInventory) { + if(stack != null) { + applyHazards(stack, player); + } + } + } + + @SideOnly(Side.CLIENT) + public static void addFullTooltip(ItemStack stack, EntityPlayer player, List list) { + + List hazards = getHazardsFromStack(stack); + + for(HazardEntry hazard : hazards) { + hazard.type.addHazardInformation(player, list, hazard.baseLevel, stack, hazard.mods); + } + } +} diff --git a/src/main/java/com/hbm/hazard/type/HazardTypeBase.java b/src/main/java/com/hbm/hazard/type/HazardTypeBase.java new file mode 100644 index 000000000..e196d4bd7 --- /dev/null +++ b/src/main/java/com/hbm/hazard/type/HazardTypeBase.java @@ -0,0 +1,32 @@ +package com.hbm.hazard.type; + +import java.util.List; + +import com.hbm.hazard.HazardModifier; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public abstract class HazardTypeBase { + + /** + * Does the thing. Called by HazardEntry.applyHazard + * @param target the holder + * @param level the final level after calculating all the modifiers + */ + public abstract void onUpdate(EntityLivingBase target, float level); + + /** + * Adds item tooltip info. Called by Item.addInformation + * @param player + * @param list + * @param level the base level, mods are passed separately + * @param stack + * @param modifiers + */ + @SideOnly(Side.CLIENT) + public abstract void addHazardInformation(EntityPlayer player, List list, float level, ItemStack stack, List modifiers); +} diff --git a/src/main/java/com/hbm/hazard/type/HazardTypeRadiation.java b/src/main/java/com/hbm/hazard/type/HazardTypeRadiation.java new file mode 100644 index 000000000..396d962a8 --- /dev/null +++ b/src/main/java/com/hbm/hazard/type/HazardTypeRadiation.java @@ -0,0 +1,55 @@ +package com.hbm.hazard.type; + +import java.util.List; + +import com.hbm.config.GeneralConfig; +import com.hbm.hazard.HazardModifier; +import com.hbm.items.ModItems; +import com.hbm.util.ContaminationUtil; +import com.hbm.util.I18nUtil; +import com.hbm.util.ContaminationUtil.ContaminationType; +import com.hbm.util.ContaminationUtil.HazardType; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; + +public class HazardTypeRadiation extends HazardTypeBase { + + @Override + public void onUpdate(EntityLivingBase target, float level) { + + boolean reacher = false; + + if(target instanceof EntityPlayer && !GeneralConfig.enable528) + reacher = ((EntityPlayer) target).inventory.hasItem(ModItems.reacher); + + if(level > 0) { + float rad = level / 20F; + + if(reacher) + rad = (float) Math.min(Math.sqrt(rad), rad); //to prevent radiation from going up when being <1 + + ContaminationUtil.contaminate(target, HazardType.RADIATION, ContaminationType.CREATIVE, rad); + } + } + + @Override + @SideOnly(Side.CLIENT) + public void addHazardInformation(EntityPlayer player, List list, float level, ItemStack stack, List modifiers) { + + level = HazardModifier.evalAllModifiers(stack, player, level, modifiers); + + list.add(EnumChatFormatting.GREEN + "[" + I18nUtil.resolveKey("trait.radioactive") + "]"); + String rad = "" + (Math.floor(level* 1000) / 1000); + list.add(EnumChatFormatting.YELLOW + (rad + "RAD/s")); + + if(stack.stackSize > 1) { + list.add(EnumChatFormatting.YELLOW + "Stack: " + ((Math.floor(level * 1000 * stack.stackSize) / 1000) + "RAD/s")); + } + } + +} diff --git a/src/main/java/com/hbm/main/MainRegistry.java b/src/main/java/com/hbm/main/MainRegistry.java index b51f26ba6..a077cb375 100644 --- a/src/main/java/com/hbm/main/MainRegistry.java +++ b/src/main/java/com/hbm/main/MainRegistry.java @@ -67,6 +67,7 @@ import com.hbm.handler.imc.IMCCentrifuge; import com.hbm.handler.imc.IMCCrystallizer; import com.hbm.handler.imc.IMCHandler; import com.hbm.handler.radiation.ChunkRadiationManager; +import com.hbm.hazard.HazardRegistry; import com.hbm.inventory.*; import com.hbm.items.ModItems; import com.hbm.lib.HbmWorld; @@ -250,6 +251,7 @@ public class MainRegistry { CraftingManager.mainRegistry(); AssemblerRecipes.preInit(PreEvent.getModConfigurationDirectory()); SiegeTier.registerTiers(); + HazardRegistry.registerItems(); Library.superuser.add("192af5d7-ed0f-48d8-bd89-9d41af8524f8"); Library.superuser.add("5aee1e3d-3767-4987-a222-e7ce1fbdf88e"); diff --git a/src/main/java/com/hbm/main/ModEventHandlerClient.java b/src/main/java/com/hbm/main/ModEventHandlerClient.java index 3242f82bb..544e95f6a 100644 --- a/src/main/java/com/hbm/main/ModEventHandlerClient.java +++ b/src/main/java/com/hbm/main/ModEventHandlerClient.java @@ -14,6 +14,7 @@ import com.hbm.extprop.HbmPlayerProps; import com.hbm.handler.ArmorModHandler; import com.hbm.handler.HTTPHandler; import com.hbm.handler.HazmatRegistry; +import com.hbm.hazard.HazardSystem; import com.hbm.interfaces.IHoldableWeapon; import com.hbm.interfaces.IItemHUD; import com.hbm.interfaces.Spaghetti; @@ -528,6 +529,9 @@ public class ModEventHandlerClient { } } } + + /// HAZARDS /// + HazardSystem.addFullTooltip(stack, event.entityPlayer, list); } private ResourceLocation ashes = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_ash.png");