2012-08-06 22:07:53 +00:00
|
|
|
/**
|
|
|
|
* This software is provided under the terms of the Minecraft Forge Public
|
|
|
|
* License v1.0.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package net.minecraftforge.common;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
2012-12-13 05:58:35 +00:00
|
|
|
import net.minecraft.util.DamageSource;
|
2013-06-30 12:50:11 +00:00
|
|
|
import net.minecraft.entity.EntityLivingBase;
|
2012-12-13 05:58:35 +00:00
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
|
|
import net.minecraft.item.ItemArmor;
|
|
|
|
import net.minecraft.item.ItemStack;
|
2012-08-06 22:07:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This interface is to be implemented by ItemArmor classes. It will allow to
|
|
|
|
* modify computation of damage and health loss. Computation will be called
|
|
|
|
* before the actual armor computation, which can then be cancelled.
|
|
|
|
*
|
|
|
|
* @see ItemArmor
|
|
|
|
*/
|
|
|
|
public interface ISpecialArmor
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Retrieves the modifiers to be used when calculating armor damage.
|
|
|
|
*
|
|
|
|
* Armor will higher priority will have damage applied to them before
|
|
|
|
* lower priority ones. If there are multiple pieces of armor with the
|
|
|
|
* same priority, damage will be distributed between them based on there
|
|
|
|
* absorption ratio.
|
|
|
|
*
|
2012-09-11 20:11:17 +00:00
|
|
|
* @param player The entity wearing the armor.
|
2012-08-06 22:07:53 +00:00
|
|
|
* @param armor The ItemStack of the armor item itself.
|
|
|
|
* @param source The source of the damage, which can be used to alter armor
|
|
|
|
* properties based on the type or source of damage.
|
|
|
|
* @param damage The total damage being applied to the entity
|
|
|
|
* @param slot The armor slot the item is in.
|
|
|
|
* @return A ArmorProperties instance holding information about how the armor effects damage.
|
|
|
|
*/
|
2013-06-30 12:50:11 +00:00
|
|
|
public ArmorProperties getProperties(EntityLivingBase player, ItemStack armor, DamageSource source, double damage, int slot);
|
2012-08-06 22:07:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the displayed effective armor.
|
|
|
|
*
|
|
|
|
* @param player The player wearing the armor.
|
|
|
|
* @param armor The ItemStack of the armor item itself.
|
|
|
|
* @param slot The armor slot the item is in.
|
|
|
|
* @return The number of armor points for display, 2 per shield.
|
|
|
|
*/
|
|
|
|
public abstract int getArmorDisplay(EntityPlayer player, ItemStack armor, int slot);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Applies damage to the ItemStack. The mod is responsible for reducing the
|
|
|
|
* item durability and stack size. If the stack is depleted it will be cleaned
|
|
|
|
* up automatically.
|
|
|
|
*
|
|
|
|
* @param entity The entity wearing the armor
|
2012-09-11 20:11:17 +00:00
|
|
|
* @param stack The ItemStack of the armor item itself.
|
2012-08-06 22:07:53 +00:00
|
|
|
* @param source The source of the damage, which can be used to alter armor
|
|
|
|
* properties based on the type or source of damage.
|
|
|
|
* @param damage The amount of damage being applied to the armor
|
|
|
|
* @param slot The armor slot the item is in.
|
|
|
|
*/
|
2013-06-30 12:50:11 +00:00
|
|
|
public abstract void damageArmor(EntityLivingBase entity, ItemStack stack, DamageSource source, int damage, int slot);
|
2012-08-06 22:07:53 +00:00
|
|
|
|
|
|
|
public static class ArmorProperties implements Comparable<ArmorProperties>
|
|
|
|
{
|
|
|
|
public int Priority = 0;
|
|
|
|
public int AbsorbMax = Integer.MAX_VALUE;
|
|
|
|
public double AbsorbRatio = 0;
|
|
|
|
public int Slot = 0;
|
|
|
|
private static final boolean DEBUG = false; //Only enable this if you wish to be spamed with debugging information.
|
|
|
|
//Left it in because I figured it'd be useful for modders developing custom armor.
|
|
|
|
|
|
|
|
public ArmorProperties(int priority, double ratio, int max)
|
|
|
|
{
|
|
|
|
Priority = priority;
|
|
|
|
AbsorbRatio = ratio;
|
|
|
|
AbsorbMax = max;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gathers and applies armor reduction to damage being dealt to a entity.
|
|
|
|
*
|
|
|
|
* @param entity The Entity being damage
|
|
|
|
* @param inventory An array of armor items
|
|
|
|
* @param source The damage source type
|
|
|
|
* @param damage The total damage being done
|
|
|
|
* @return The left over damage that has not been absorbed by the armor
|
|
|
|
*/
|
2013-06-30 12:50:11 +00:00
|
|
|
public static float ApplyArmor(EntityLivingBase entity, ItemStack[] inventory, DamageSource source, double damage)
|
2012-08-06 22:07:53 +00:00
|
|
|
{
|
|
|
|
if (DEBUG)
|
|
|
|
{
|
|
|
|
System.out.println("Start: " + damage + " " + (damage * 25));
|
|
|
|
}
|
|
|
|
damage *= 25;
|
|
|
|
ArrayList<ArmorProperties> dmgVals = new ArrayList<ArmorProperties>();
|
|
|
|
for (int x = 0; x < inventory.length; x++)
|
|
|
|
{
|
|
|
|
ItemStack stack = inventory[x];
|
|
|
|
if (stack == null)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ArmorProperties prop = null;
|
|
|
|
if (stack.getItem() instanceof ISpecialArmor)
|
|
|
|
{
|
|
|
|
ISpecialArmor armor = (ISpecialArmor)stack.getItem();
|
|
|
|
prop = armor.getProperties(entity, stack, source, damage / 25D, x).copy();
|
|
|
|
}
|
|
|
|
else if (stack.getItem() instanceof ItemArmor && !source.isUnblockable())
|
|
|
|
{
|
|
|
|
ItemArmor armor = (ItemArmor)stack.getItem();
|
|
|
|
prop = new ArmorProperties(0, armor.damageReduceAmount / 25D, armor.getMaxDamage() + 1 - stack.getItemDamage());
|
|
|
|
}
|
|
|
|
if (prop != null)
|
|
|
|
{
|
|
|
|
prop.Slot = x;
|
|
|
|
dmgVals.add(prop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dmgVals.size() > 0)
|
|
|
|
{
|
2013-01-02 04:57:45 +00:00
|
|
|
ArmorProperties[] props = dmgVals.toArray(new ArmorProperties[dmgVals.size()]);
|
2012-08-06 22:07:53 +00:00
|
|
|
StandardizeList(props, damage);
|
|
|
|
int level = props[0].Priority;
|
|
|
|
double ratio = 0;
|
|
|
|
for (ArmorProperties prop : props)
|
|
|
|
{
|
|
|
|
if (level != prop.Priority)
|
|
|
|
{
|
|
|
|
damage -= (damage * ratio);
|
|
|
|
ratio = 0;
|
|
|
|
level = prop.Priority;
|
|
|
|
}
|
|
|
|
ratio += prop.AbsorbRatio;
|
|
|
|
|
|
|
|
double absorb = damage * prop.AbsorbRatio;
|
|
|
|
if (absorb > 0)
|
|
|
|
{
|
|
|
|
ItemStack stack = inventory[prop.Slot];
|
|
|
|
int itemDamage = (int)(absorb / 25D < 1 ? 1 : absorb / 25D);
|
|
|
|
if (stack.getItem() instanceof ISpecialArmor)
|
|
|
|
{
|
|
|
|
((ISpecialArmor)stack.getItem()).damageArmor(entity, stack, source, itemDamage, prop.Slot);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (DEBUG)
|
|
|
|
{
|
|
|
|
System.out.println("Item: " + stack.toString() + " Absorbed: " + (absorb / 25D) + " Damaged: " + itemDamage);
|
|
|
|
}
|
|
|
|
stack.damageItem(itemDamage, entity);
|
|
|
|
}
|
|
|
|
if (stack.stackSize <= 0)
|
|
|
|
{
|
2012-08-07 03:45:37 +00:00
|
|
|
/*if (entity instanceof EntityPlayer)
|
2012-08-06 22:07:53 +00:00
|
|
|
{
|
|
|
|
stack.onItemDestroyedByUse((EntityPlayer)entity);
|
2012-08-07 03:45:37 +00:00
|
|
|
}*/
|
2012-08-06 22:07:53 +00:00
|
|
|
inventory[prop.Slot] = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
damage -= (damage * ratio);
|
|
|
|
}
|
|
|
|
if (DEBUG)
|
|
|
|
{
|
2013-06-30 12:50:11 +00:00
|
|
|
System.out.println("Return: " + (int)(damage / 25.0F) + " " + damage);
|
2012-08-06 22:07:53 +00:00
|
|
|
}
|
2013-06-30 12:50:11 +00:00
|
|
|
return (float)(damage / 25.0F);
|
2012-08-06 22:07:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorts and standardizes the distribution of damage over armor.
|
|
|
|
*
|
|
|
|
* @param armor The armor information
|
|
|
|
* @param damage The total damage being received
|
|
|
|
*/
|
|
|
|
private static void StandardizeList(ArmorProperties[] armor, double damage)
|
|
|
|
{
|
|
|
|
Arrays.sort(armor);
|
|
|
|
|
|
|
|
int start = 0;
|
|
|
|
double total = 0;
|
|
|
|
int priority = armor[0].Priority;
|
|
|
|
int pStart = 0;
|
|
|
|
boolean pChange = false;
|
|
|
|
boolean pFinished = false;
|
|
|
|
|
|
|
|
if (DEBUG)
|
|
|
|
{
|
|
|
|
for (ArmorProperties prop : armor)
|
|
|
|
{
|
|
|
|
System.out.println(prop);
|
|
|
|
}
|
|
|
|
System.out.println("========================");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int x = 0; x < armor.length; x++)
|
|
|
|
{
|
|
|
|
total += armor[x].AbsorbRatio;
|
|
|
|
if (x == armor.length - 1 || armor[x].Priority != priority)
|
|
|
|
{
|
|
|
|
if (armor[x].Priority != priority)
|
|
|
|
{
|
|
|
|
total -= armor[x].AbsorbRatio;
|
|
|
|
x--;
|
|
|
|
pChange = true;
|
|
|
|
}
|
|
|
|
if (total > 1)
|
|
|
|
{
|
|
|
|
for (int y = start; y <= x; y++)
|
|
|
|
{
|
|
|
|
double newRatio = armor[y].AbsorbRatio / total;
|
|
|
|
if (newRatio * damage > armor[y].AbsorbMax)
|
|
|
|
{
|
|
|
|
armor[y].AbsorbRatio = (double)armor[y].AbsorbMax / damage;
|
|
|
|
total = 0;
|
|
|
|
for (int z = pStart; z <= y; z++)
|
|
|
|
{
|
|
|
|
total += armor[z].AbsorbRatio;
|
|
|
|
}
|
|
|
|
start = y + 1;
|
|
|
|
x = y;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
armor[y].AbsorbRatio = newRatio;
|
|
|
|
pFinished = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pChange && pFinished)
|
|
|
|
{
|
|
|
|
damage -= (damage * total);
|
|
|
|
total = 0;
|
|
|
|
start = x + 1;
|
|
|
|
priority = armor[start].Priority;
|
|
|
|
pStart = start;
|
|
|
|
pChange = false;
|
|
|
|
pFinished = false;
|
|
|
|
if (damage <= 0)
|
|
|
|
{
|
|
|
|
for (int y = x + 1; y < armor.length; y++)
|
|
|
|
{
|
|
|
|
armor[y].AbsorbRatio = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int y = start; y <= x; y++)
|
|
|
|
{
|
|
|
|
total -= armor[y].AbsorbRatio;
|
|
|
|
if (damage * armor[y].AbsorbRatio > armor[y].AbsorbMax)
|
|
|
|
{
|
2013-01-02 04:57:45 +00:00
|
|
|
armor[y].AbsorbRatio = (double)armor[y].AbsorbMax / damage;
|
2012-08-06 22:07:53 +00:00
|
|
|
}
|
|
|
|
total += armor[y].AbsorbRatio;
|
|
|
|
}
|
|
|
|
damage -= (damage * total);
|
|
|
|
total = 0;
|
|
|
|
if (x != armor.length - 1)
|
|
|
|
{
|
|
|
|
start = x + 1;
|
|
|
|
priority = armor[start].Priority;
|
|
|
|
pStart = start;
|
|
|
|
pChange = false;
|
|
|
|
if (damage <= 0)
|
|
|
|
{
|
|
|
|
for (int y = x + 1; y < armor.length; y++)
|
|
|
|
{
|
|
|
|
armor[y].AbsorbRatio = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (DEBUG)
|
|
|
|
{
|
|
|
|
for (ArmorProperties prop : armor)
|
|
|
|
{
|
|
|
|
System.out.println(prop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int compareTo(ArmorProperties o)
|
|
|
|
{
|
|
|
|
if (o.Priority != Priority)
|
|
|
|
{
|
|
|
|
return o.Priority - Priority;
|
|
|
|
}
|
|
|
|
double left = ( AbsorbRatio == 0 ? 0 : AbsorbMax * 100.0D / AbsorbRatio);
|
|
|
|
double right = (o.AbsorbRatio == 0 ? 0 : o.AbsorbMax * 100.0D / o.AbsorbRatio);
|
|
|
|
return (int)(left - right);
|
|
|
|
}
|
|
|
|
|
|
|
|
public String toString()
|
|
|
|
{
|
|
|
|
return String.format("%d, %d, %f, %d", Priority, AbsorbMax, AbsorbRatio, (AbsorbRatio == 0 ? 0 : (int)(AbsorbMax * 100.0D / AbsorbRatio)));
|
|
|
|
}
|
|
|
|
|
|
|
|
public ArmorProperties copy()
|
|
|
|
{
|
|
|
|
return new ArmorProperties(Priority, AbsorbRatio, AbsorbMax);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|