[SOLVED] ISpecialArmor ArmorProperties either gives invincibility or no protection

Discussion in 'Mod Development' started by Type1Ninja, Jun 19, 2015.

  1. Type1Ninja

    Type1Ninja New Member

    SEE LAST POST FOR SOLUTION

    I ran into this issue a bit ago with a different set of armor. If you implement ISpecialAmor, then when overriding getProperties, which returns an ArmorProperties object which determines damage absorption, you get either full invincibility or no protection at all. I got it working, but looking back at the code, I can't tell what exactly is different from what I have now.
    For the curious, I'm trying to make mid-game powered armor. :p
    Code for WORKING armorset (a rather unrealistic Hazmat Suit):
    Code:
    //Imports 'n' stuff
    
    public class ItemHazmatArmor extends ItemArmorXF implements ISpecialArmor {
        public static ArmorMaterial HAZMATARMOR = EnumHelper.addArmorMaterial("HAZMATARMOR", 12, new int[] {25, 25, 25, 25}, 7);
      
        public ItemHazmatArmor(String unlocalizedName, ArmorMaterial material, int armorSetNumber, int armorPiece) {
            super(unlocalizedName, HAZMATARMOR, armorSetNumber, armorPiece);
        }
    
        @Override
        public void onArmorTick(World world, EntityPlayer player, ItemStack armor) {
            //Helmet gives you water breathing
            if (ModItems.itemHazmatHelmet == armor.getItem()) {
                player.addPotionEffect(new PotionEffect(Potion.waterBreathing.id, 1, 0));
            }
        }
      
        //Different armor pieces give different amounts of protection against different damage types
        //The armor properties is returned as (1 - use this armor first, (1-(percent damage taken)), Integer.MAX_VALUE)
        @Override
        public ArmorProperties getProperties(EntityLivingBase player,
                ItemStack armor, DamageSource source, double damage, int slot) {
            //Take damage first; damageArmor is derpy in how it is called
            if (source == source.inFire || source == source.lava || source == source.onFire || source == source.fall || source == source.cactus || source == source.wither || source == source.magic || !source.isUnblockable()) {
                damageArmor(player, armor, source, 1, slot);
            }
          
            //Chestplate protects against fire/lava
            if (ModItems.itemHazmatChestplate == armor.getItem() && (source == source.inFire || source == source.lava || source == source.onFire)) {
                //Take 1/3 fire/lava damage
                return new ArmorProperties(1, .67, Integer.MAX_VALUE);
            //Boots protect against fall damage
            } else if (ModItems.itemHazmatBoots == armor.getItem() && source == source.fall) {
                //Take 2/3 fall damage
                return new ArmorProperties(1, .34, Integer.MAX_VALUE);
            //Leggings protect against cactus, wither, and "magic"
            } else if (ModItems.itemHazmatLeggings == armor.getItem() && (source == source.cactus || source == source.wither || source == source.magic)){
                //Take 1/3 cactus/wither/magic damage
                return new ArmorProperties(1, .67, Integer.MAX_VALUE);
            } else if (!source.isUnblockable()){
                return new ArmorProperties(1, 0, 0);
            } else {
                return new ArmorProperties(0, 0, 0);
            }
        }
    
        @Override
        public int getArmorDisplay(EntityPlayer player, ItemStack armor, int slot) {
            //Always return zero 'cause it's just a hazmat suit; no protection offered. :P
            return 0;
        }
    
        @Override
        public void damageArmor(EntityLivingBase entity, ItemStack stack,
                DamageSource source, int damage, int slot) {
            stack.damageItem(1, entity);
        }
    }
    
    Code for the NOT WORKING armorset:
    Code:
    //Imports 'n' stuff
    
    public class ItemPoweredArmor extends ItemArmorXF implements ISpecialArmor, IEnergyContainerItem {
        //Armor material
        public static ArmorMaterial POWEREDARMOR = EnumHelper.addArmorMaterial("POWEREDARMOR", 12, new int[] {3, 7, 5, 2}, 10);
        public static double maxProtect = .75;
        public static double minProtect = .1;
      
        public static int capacity = 10000;
        public static int maxTransfer = 100;
        public static int durability = 300;
        public static int energyPerHit = capacity / durability;
      
        public ItemPoweredArmor(String unlocalizedName, ArmorMaterial material, int armorSetNumber, int armorPiece) {
            super(unlocalizedName, POWEREDARMOR, armorSetNumber, armorPiece);
        }
      
        //Set tooltip
        @Override
        public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean par4) {
            String str = "";
            int storedEnergy = getEnergyStored(stack);
            str = String.valueOf(storedEnergy) + "/" + getMaxEnergyStored(stack) + " RF";
            list.add(str);
        }
      
        public double getEnergyStoredPercent(ItemStack stack) {
            double energyStored = getEnergyStored(stack);
            double maxEnergyStored = getMaxEnergyStored(stack);
            double percentStored = energyStored / maxEnergyStored;
            return (percentStored);
        }
      
        //Pasted from KingLemming's ItemEnergyContainer code, with minor adjustments as needed
        @Override
        public int receiveEnergy(ItemStack container, int maxReceive,
                boolean simulate) {
            if (container.stackTagCompound == null) {
                container.stackTagCompound = new NBTTagCompound();
            }
            int energy = container.stackTagCompound.getInteger("Energy");
            int energyReceived = Math.min(capacity - energy, Math.min(this.maxTransfer, maxReceive));
    
            if (!simulate) {
                energy += energyReceived;
                container.stackTagCompound.setInteger("Energy", energy);
            }
            return energyReceived;
        }
    
        //Pasted from KingLemming's ItemEnergyContainer code, with minor adjustments as needed
        @Override
        public int extractEnergy(ItemStack container, int maxExtract,
                boolean simulate) {
            if (container.stackTagCompound == null || !container.stackTagCompound.hasKey("Energy")) {
                return 0;
            }
            int energy = container.stackTagCompound.getInteger("Energy");
            int energyExtracted = Math.min(energy, Math.min(this.maxTransfer, maxExtract));
    
            if (!simulate) {
                energy -= energyExtracted;
                container.stackTagCompound.setInteger("Energy", energy);
            }
            return energyExtracted;
        }
    
        //Pasted from KingLemming's ItemEnergyContainer code, with minor adjustments as needed
        @Override
        public int getEnergyStored(ItemStack container) {
            if (container.stackTagCompound == null || !container.stackTagCompound.hasKey("Energy")) {
                return 0;
            }
            return container.stackTagCompound.getInteger("Energy");
        }
    
        @Override
        public int getMaxEnergyStored(ItemStack container) {
            return capacity;
        }
    
        @Override
        public ArmorProperties getProperties(EntityLivingBase player,
                ItemStack armor, DamageSource source, double damage, int slot) {
            if (!source.isUnblockable()) {
                double absorbRatio = getEnergyStoredPercent(armor);
                LogHelper.info(absorbRatio);
                //Make sure that the absorb ratio is always at least the minimum protect if there is energy left
                //but also that it is never above the max
                if (getEnergyStored(armor) != 0) {
                    absorbRatio += minProtect;
                }
                if (absorbRatio > maxProtect) {
                    absorbRatio = maxProtect;
                }
                LogHelper.info(absorbRatio);
                return new ArmorProperties(1, absorbRatio, Integer.MAX_VALUE);
            } else {
                return new ArmorProperties(0, 0, 0);
            }
        }
    
        @Override
        public int getArmorDisplay(EntityPlayer player, ItemStack armor, int slot) {
            //Armor bars - each "half shirt" above the health bar
            double absorbRatio = getEnergyStoredPercent(armor);
            //Make sure that the absorb ratio is always at least the minimum protect if there is energy left
            //but also that it is never above the max
            if (getEnergyStored(armor) != 0) {
                absorbRatio += minProtect;
            }
            if (absorbRatio > maxProtect) {
                absorbRatio = maxProtect;
            }
            //Multiply by 25 to get amount/25
            //Divide by 4 (multiply by .25) to get amount per armor piece
            double armorBars = absorbRatio * 25 * .25;
            //Make sure that SOME bars are displayed as long as the protection is greater than 0
            if (armorBars > 0 && armorBars < 1) {
                armorBars = 1;
            }
            return MathHelper.floor(armorBars);
        }
    
        @Override
        public void damageArmor(EntityLivingBase entity, ItemStack stack,
                DamageSource source, int damage, int slot) {
            extractEnergy(stack, energyPerHit, false);
        }
      
        //TODO - POWER BAR
    }
    
    To be more exact - when I wear the power armor, one of two things happens. If it has any amount of charge, I take zero damage from all blockable sources (mobs, cacti, lava, etc.). When it has zero charge, I take full damage from all sources, including blockable ones (the second part - full damage at zero charge - is intended). All other bits of code for the armor are working, including the dynamic armor bar change (which I find charming) and the charging.

    [Reply to side questions in spoilers so the moderators don't eat me ^^]
    Side Question - How would I specify "CoFH Core OR CoFH Lib" as a requirement in my main mod code? I understand hard and soft dependencies, but don't know how to do an "either or" sort of thing. :p
    Second Side Question - How would I do the power bar? :p I'll figure it out myself later if I need to.

    Thanks! :D
     
    Last edited: Jun 21, 2015
  2. lenscas

    lenscas Over-Achiever

    not written any mods yet or touched java so what I suggest is probably not the way to do it:

    Put them both as a soft dependency and look by yourself if either of them is loaded if neither of them is loaded then you can probably crash the game in a nice way.

    Again, I have not done anything with java let alone mod minecraft so their may be a better way to do it.
     
    Type1Ninja likes this.
  3. Type1Ninja

    Type1Ninja New Member

    I know there's a lot of mods - like Matter Overdrive - that have that sort of optional dependency (working properly, I think) so I'll probably post over on that thread if nobody responds here. It might be that yours is the ONLY method, although I'm hoping there's something cleaner. :p Thanks for the guess, though. :)
     
  4. lenscas

    lenscas Over-Achiever

    To be honest if there is not a cleaner way to do it then I would be surprised.
     
    Type1Ninja likes this.
  5. gattsuru

    gattsuru Well-Known Member

    I assume the logged absorbratio is showing a sane (0.1-0.75) range during the call? May I ask if you run into similar issues if you switch "return new ArmorProperties(1, absorbRatio, Integer.MAX_VALUE);" with something more like "return new ArmorProperties(1, absorbRatio, 100);" , just in case MaxAbsorb does odd things with high values?

    I don't think the required-after syntax supports conditional requirements, so you're probably better off putting both as after dependencies and checking for the existence of their classes during your own loading stage.
     
    Type1Ninja likes this.
  6. Type1Ninja

    Type1Ninja New Member

    Yeah, it does display sane values (I'm glad you were able to figure out that those were the max and min from my code ;)). I'll try playing with the last parameter next time I work on that. Thanks for the advice! :D
    Also thanks for the dependency stuff. :)
     
  7. Type1Ninja

    Type1Ninja New Member

    Alright, I did my test. Setting the max damage absorption (third parameter) to 10, I take full-ish damage from a zombie pigman. Setting it to 100, I don't take any damage until I've reached about 2,000/10,000 RF (maybe lower). The amount of damage taken goes up slightly, until it finally reaches full damage at 0 charge. I'm tired right now and don't know what to make of that... My code in the working Hazmat Suit appears to work fine, and I can't tell what's different about the Powered Armor. :(
     
  8. Type1Ninja

    Type1Ninja New Member

    So, I fixed the issue. For all those who are curious, I forgot that the absorb ratio is per piece of armor. Simply dividing absorbRatio by four and THEN passing it to the ArmorProperties instance solved the issue. That was a real headache... :(
     
  9. chbachman

    chbachman Guest

    If you don't mind me asking, what are you hoping to do with your mod?

    I currently develop Modular Armour, which seems to be pretty close (at least with the armour section) to what you are doing.

    If you ever need help, I have figured out most of this through trial and error.

    My github repository is here, for some code examples.

    I am available here, with a private message or post in this forum, or on EsperNet IRC, in the channel ModularArmour.
     
  10. Type1Ninja

    Type1Ninja New Member

    Just a quick summary of what I'm trying to do:
    I want a mod that adds everything I haven't seen in other mods done in the way I want it to be done. That includes a lightning creator, various specialized suits of armor, and an Enderman-style RF-powered handheld teleporter, as well as some other stuff. I'll be sure to look at your github for help. :D
    I may also look at your mod for my modpack. :)
     
  11. King Lemming

    King Lemming New Member

    Just specify CoFHLib. It ships with Core, but it still counts as being there.
    Also, https://github.com/CoFH/RedstoneArs...h/redstonearsenal/item/armor/ItemArmorRF.java is how armor is done, in general.
     
    chbachman and Type1Ninja like this.

Share This Page