--- ../src-base/minecraft/org/bukkit/event/entity/EntityDamageEvent.java +++ ../src-work/minecraft/org/bukkit/event/entity/EntityDamageEvent.java @@ -10,6 +10,8 @@ import org.bukkit.event.HandlerList; import org.bukkit.util.NumberConversions; +import com.google.common.base.Function; +import com.google.common.base.Functions; import com.google.common.collect.ImmutableMap; /** @@ -18,7 +20,9 @@ public class EntityDamageEvent extends EntityEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); private static final DamageModifier[] MODIFIERS = DamageModifier.values(); + private static final Function ZERO = Functions.constant(-0.0); private final Map modifiers; + private final Map> modifierFunctions; private final Map originals; private boolean cancelled; private final DamageCause cause; @@ -30,16 +34,20 @@ @Deprecated public EntityDamageEvent(final Entity damagee, final DamageCause cause, final double damage) { - this(damagee, cause, new EnumMap(ImmutableMap.of(DamageModifier.BASE, damage))); + this(damagee, cause, new EnumMap(ImmutableMap.of(DamageModifier.BASE, damage)), new EnumMap>(ImmutableMap.of(DamageModifier.BASE, ZERO))); } - public EntityDamageEvent(final Entity damagee, final DamageCause cause, final Map modifiers) { + public EntityDamageEvent(final Entity damagee, final DamageCause cause, final Map modifiers, final Map> modifierFunctions) { super(damagee); Validate.isTrue(modifiers.containsKey(DamageModifier.BASE), "BASE DamageModifier missing"); Validate.isTrue(!modifiers.containsKey(null), "Cannot have null DamageModifier"); + Validate.noNullElements(modifiers.values(), "Cannot have null modifier values"); + Validate.isTrue(modifiers.keySet().equals(modifierFunctions.keySet()), "Must have a modifier function for each DamageModifier"); + Validate.noNullElements(modifierFunctions.values(), "Cannot have null modifier function"); this.originals = new EnumMap(modifiers); this.cause = cause; this.modifiers = modifiers; + this.modifierFunctions = modifierFunctions; } public boolean isCancelled() { @@ -149,11 +157,39 @@ } /** - * Sets the raw amount of damage caused by the event + * Sets the raw amount of damage caused by the event. + *

+ * For compatibility this also recalculates the modifiers and scales + * them by the difference between the modifier for the previous damage + * value and the new one. * * @param damage The raw amount of damage caused by the event */ public void setDamage(double damage) { + // These have to happen in the same order as the server calculates them, keep the enum sorted + double remaining = damage; + double oldRemaining = getDamage(DamageModifier.BASE); + for (DamageModifier modifier : MODIFIERS) { + if (!isApplicable(modifier)) { + continue; + } + + Function modifierFunction = modifierFunctions.get(modifier); + double newVanilla = modifierFunction.apply(remaining); + double oldVanilla = modifierFunction.apply(oldRemaining); + double difference = oldVanilla - newVanilla; + + // Don't allow value to cross zero, assume zero values should be negative + double old = getDamage(modifier); + if (old > 0) { + setDamage(modifier, Math.max(0, old - difference)); + } else { + setDamage(modifier, Math.min(0, old - difference)); + } + remaining += newVanilla; + oldRemaining += oldVanilla; + } + setDamage(DamageModifier.BASE, damage); }