public static Optional<List<Tuple<DamageModifier, Function<? super Double, Double>>>> createArmorModifiers( EntityLivingBase entityLivingBase, DamageSource damageSource, double damage) { if (!damageSource.isDamageAbsolute()) { damage *= 25; net.minecraft.item.ItemStack[] inventory = entityLivingBase instanceof EntityPlayer ? ((EntityPlayer) entityLivingBase).inventory.armorInventory : entityLivingBase.getInventory(); List<Tuple<DamageModifier, Function<? super Double, Double>>> modifiers = new ArrayList<>(); List<DamageObject> damageObjects = new ArrayList<>(); for (int index = 0; index < inventory.length; index++) { net.minecraft.item.ItemStack itemStack = inventory[index]; if (itemStack == null) { continue; } Item item = itemStack.getItem(); if (item instanceof ItemArmor) { ItemArmor armor = (ItemArmor) item; double reduction = armor.damageReduceAmount / 25D; DamageObject object = new DamageObject(); object.slot = index; object.ratio = reduction; damageObjects.add(object); } } boolean first = true; double ratio = 0; for (DamageObject prop : damageObjects) { EquipmentType type = resolveEquipment(prop.slot); final DamageObject object = new DamageObject(); object.ratio = ratio; if (first) { object.previousDamage = damage; object.augment = true; } Function<? super Double, Double> function = incomingDamage -> { incomingDamage *= 25; if (object.augment) { // This is the damage that needs to be archived for the "first" armor modifier // function since the armor modifiers work based on the initial damage and not as // a chain one after another. damageToHandle = incomingDamage; } double functionDamage = damageToHandle; object.previousDamage = functionDamage; object.ratio = prop.ratio; object.ratio += prop.ratio; return -((functionDamage * prop.ratio) / 25); }; ratio += prop.ratio; DamageModifier modifier = DamageModifier.builder() .cause( Cause.of( NamedCause.of( DamageEntityEvent.GENERAL_ARMOR + ":" + type.getId(), ((org.spongepowered.api.item.inventory.ItemStack) inventory[prop.slot]) .createSnapshot()), NamedCause.of( "ArmorProperty", prop), // We need this property to refer to the slot. NamedCause.of("0xDEADBEEF", object))) // We need this object later on. .type(DamageModifierTypes.ARMOR) .build(); modifiers.add(new Tuple<>(modifier, function)); first = false; } if (modifiers.isEmpty()) { return Optional.empty(); } else { return Optional.of(modifiers); } } return Optional.empty(); }