diff options
author | fullwall <fullwall@optusnet.com> | 2012-01-09 14:39:06 +0800 |
---|---|---|
committer | EvilSeph <evilseph@gmail.com> | 2012-02-10 17:26:38 -0500 |
commit | d99c95f6d1b9a91f5f9c254b8e2fa615ea31e3c6 (patch) | |
tree | f9b8f32218a2a35d3a90e35eda71d2c297106ee4 /src/main/java/org | |
parent | ec01da91bbba8d4a1d928df6273389923491e75e (diff) | |
download | bukkit-d99c95f6d1b9a91f5f9c254b8e2fa615ea31e3c6.tar bukkit-d99c95f6d1b9a91f5f9c254b8e2fa615ea31e3c6.tar.gz bukkit-d99c95f6d1b9a91f5f9c254b8e2fa615ea31e3c6.tar.lz bukkit-d99c95f6d1b9a91f5f9c254b8e2fa615ea31e3c6.tar.xz bukkit-d99c95f6d1b9a91f5f9c254b8e2fa615ea31e3c6.zip |
[Bleeding] Added Potions API. Fixes BUKKIT-389
Diffstat (limited to 'src/main/java/org')
-rw-r--r-- | src/main/java/org/bukkit/entity/LivingEntity.java | 52 | ||||
-rw-r--r-- | src/main/java/org/bukkit/entity/Player.java | 1 | ||||
-rw-r--r-- | src/main/java/org/bukkit/entity/ThrownPotion.java | 9 | ||||
-rw-r--r-- | src/main/java/org/bukkit/potion/Potion.java | 265 | ||||
-rw-r--r-- | src/main/java/org/bukkit/potion/PotionBrewer.java | 31 | ||||
-rw-r--r-- | src/main/java/org/bukkit/potion/PotionEffect.java | 85 | ||||
-rw-r--r-- | src/main/java/org/bukkit/potion/PotionEffectType.java | 239 | ||||
-rw-r--r-- | src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java | 29 | ||||
-rw-r--r-- | src/main/java/org/bukkit/potion/PotionType.java | 45 |
9 files changed, 755 insertions, 1 deletions
diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java index c57b84d1..a6b4e9b2 100644 --- a/src/main/java/org/bukkit/entity/LivingEntity.java +++ b/src/main/java/org/bukkit/entity/LivingEntity.java @@ -1,10 +1,13 @@ package org.bukkit.entity; +import java.util.Collection; import java.util.HashSet; import java.util.List; import org.bukkit.Location; import org.bukkit.block.Block; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; /** * Represents a living entity, such as a monster or player @@ -225,4 +228,53 @@ public interface LivingEntity extends Entity { * @return Killer player, or null if none found. */ public Player getKiller(); + + /** + * Adds the given {@link PotionEffect} to this entity. + * Only one potion effect can be present for a given {@link PotionEffectType}. + * + * @param effect PotionEffect to be added + * @return Whether the effect could be added + */ + public boolean addPotionEffect(PotionEffect effect); + + /** + * Adds the given {@link PotionEffect} to this entity. + * Only one potion effect can be present for a given {@link PotionEffectType}. + * + * @param effect PotionEffect to be added + * @param force Whether conflicting effects should be removed + * @return Whether the effect could be added + */ + public boolean addPotionEffect(PotionEffect effect, boolean force); + + /** + * Attempts to add all of the given {@link PotionEffect} to this entity. + * + * @param effects The effects to add + * @return Whether all of the effects could be added + */ + public boolean addPotionEffects(Collection<PotionEffect> effects); + + /** + * Returns whether the entity already has an existing + * effect of the given {@link PotionEffectType} applied to it. + * + * @param type The potion type to check + */ + public boolean hasPotionEffect(PotionEffectType type); + + /** + * Removes any effects present of the given {@link PotionEffectType}. + * + * @param type The potion type to remove + */ + public void removePotionEffect(PotionEffectType type); + + /** + * Returns all currently active {@link PotionEffect}s on this entity. + * + * @return A collection of {@link PotionEffect}s + */ + public Collection<PotionEffect> getActivePotionEffects(); } diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java index 1ee3722e..c32cd0d9 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -1,6 +1,7 @@ package org.bukkit.entity; import java.net.InetSocketAddress; + import org.bukkit.Achievement; import org.bukkit.ChatColor; import org.bukkit.Effect; diff --git a/src/main/java/org/bukkit/entity/ThrownPotion.java b/src/main/java/org/bukkit/entity/ThrownPotion.java index 789ade54..4a858c6b 100644 --- a/src/main/java/org/bukkit/entity/ThrownPotion.java +++ b/src/main/java/org/bukkit/entity/ThrownPotion.java @@ -1,8 +1,15 @@ package org.bukkit.entity; +import java.util.Collection; + +import org.bukkit.potion.PotionEffect; + /** * Represents a thrown potion bottle */ public interface ThrownPotion extends Projectile { - + /** + * Returns the effects that are applied by this potion. + */ + public Collection<PotionEffect> getEffects(); } diff --git a/src/main/java/org/bukkit/potion/Potion.java b/src/main/java/org/bukkit/potion/Potion.java new file mode 100644 index 00000000..920522ac --- /dev/null +++ b/src/main/java/org/bukkit/potion/Potion.java @@ -0,0 +1,265 @@ +package org.bukkit.potion; + +import java.util.Collection; + +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.entity.LivingEntity; +import org.bukkit.inventory.ItemStack; + +/** + * Represents a minecraft potion + */ +public class Potion { + private boolean extended = false; + private boolean splash = false; + private Tier tier = Tier.ONE; + private final PotionType type; + + public Potion(PotionType type) { + Validate.notNull(type, "type cannot be null"); + this.type = type; + } + + public Potion(PotionType type, Tier tier) { + this(type); + Validate.notNull(tier, "tier cannot be null"); + this.tier = tier; + } + + public Potion(PotionType type, Tier tier, boolean splash) { + this(type, tier); + this.splash = splash; + } + + public Potion(PotionType type, Tier tier, boolean splash, boolean extended) { + this(type, tier, splash); + this.extended = extended; + } + + /** + * Applies the effects of this potion to the given {@link ItemStack}. The + * itemstack must be a potion. + * + * @param to + * The itemstack to apply to + */ + public void apply(ItemStack to) { + Validate.notNull(to, "itemstack cannot be null"); + if (to.getType() != Material.POTION) + throw new IllegalArgumentException("given itemstack is not a potion"); + to.setDurability(toDamageValue()); + } + + /** + * Applies the effects that would be applied by this potion to the given + * {@link LivingEntity}. + * + * @see LivingEntity#addPotionEffects(Collection) + * @param to + * The entity to apply the effects to + */ + public void apply(LivingEntity to) { + Validate.notNull(to, "entity cannot be null"); + to.addPotionEffects(getEffects()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Potion other = (Potion) obj; + return extended == other.extended && splash == other.splash && tier == other.tier && type == other.type; + } + + /** + * Returns a collection of {@link PotionEffect}s that this {@link Potion} + * would confer upon a {@link LivingEntity}. + * + * @see PotionBrewer#getEffectsFromDamage(int) + * @see Potion#toDamageValue() + * @return The effects that this potion applies + */ + public Collection<PotionEffect> getEffects() { + return getBrewer().getEffectsFromDamage(toDamageValue()); + } + + /** + * Returns the {@link Tier} of this potion. + * + * @return The tier of this potion + */ + public Tier getTier() { + return tier; + } + + /** + * Returns the {@link PotionType} of this potion. + * + * @return The type of this potion + */ + public PotionType getType() { + return type; + } + + /** + * Returns whether this potion has an extended duration. + * + * @return Whether this potion has extended duration + */ + public boolean hasExtendedDuration() { + return extended; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = prime + (extended ? 1231 : 1237); + result = prime * result + (splash ? 1231 : 1237); + result = prime * result + ((tier == null) ? 0 : tier.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + /** + * Returns whether this potion is a splash potion. + * + * @return Whether this is a splash potion + */ + public boolean isSplash() { + return splash; + } + + /** + * Set whether this potion has extended duration. This will cause the potion + * to have roughly 8/3 more duration than a regular potion. + * + * @param isExtended + * Whether the potion should have extended duration + */ + public void setHasExtendedDuration(boolean isExtended) { + extended = isExtended; + } + + /** + * Sets whether this potion is a splash potion. Splash potions can be thrown + * for a radius effect. + * + * @param isSplash + * Whether this is a splash potion + */ + public void setSplash(boolean isSplash) { + splash = isSplash; + } + + /** + * Sets the {@link Tier} of this potion. + * + * @param tier + * The new tier of this potion + */ + public void setTier(Tier tier) { + Validate.notNull(tier, "tier cannot be null"); + this.tier = tier; + } + + /** + * Converts this potion to a valid potion damage short, usable for potion + * item stacks. + * + * @return The damage value of this potion + */ + public short toDamageValue() { + short damage = (short) type.getDamageValue(); + damage |= tier.damageBit; + if (splash) { + damage |= SPLASH_BIT; + } + if (extended) { + damage |= EXTENDED_BIT; + } + return damage; + } + + /** + * Converts this potion to an {@link ItemStack} with the specified amount + * and a correct damage value. + * + * @param amount + * The amount of the ItemStack + * @return The created ItemStack + */ + public ItemStack toItemStack(int amount) { + return new ItemStack(Material.POTION, amount, toDamageValue()); + } + + public enum Tier { + ONE(0), + TWO(0x20); + + private int damageBit; + + Tier(int bit) { + damageBit = bit; + } + + public int getDamageBit() { + return damageBit; + } + + public static Tier getByDamageBit(int damageBit) { + for (Tier tier : Tier.values()) { + if (tier.damageBit == damageBit) + return tier; + } + return null; + } + } + + private static PotionBrewer brewer; + + private static final int EXTENDED_BIT = 0x0040; + private static final int POTION_BIT = 0xF; + private static final int SPLASH_BIT = 0x4000; + + public static Potion fromDamage(int damage) { + PotionType type = PotionType.getByDamageValue(damage & POTION_BIT); + Validate.notNull(type, "unable to find potion type"); + Tier tier = Tier.getByDamageBit(damage & Tier.TWO.damageBit); + Validate.notNull(tier, "unable to find tier"); + return new Potion(type, tier, (damage & SPLASH_BIT) > 0, (damage & EXTENDED_BIT) > 0); + } + + public static Potion fromItemStack(ItemStack item) { + Validate.notNull(item, "item cannot be null"); + if (item.getType() != Material.POTION) + throw new IllegalArgumentException("item is not a potion"); + return fromDamage(item.getDurability()); + } + + /** + * Returns an instance of {@link PotionBrewer}. + * + * @return An instance of PotionBrewer + */ + public static PotionBrewer getBrewer() { + return brewer; + } + + /** + * Sets the current instance of {@link PotionBrewer}. Generally not to be + * used from within a plugin. + * + * @param other + * The new PotionBrewer + */ + public static void setPotionBrewer(PotionBrewer other) { + if (brewer != null) + throw new IllegalArgumentException("brewer can only be set internally"); + brewer = other; + } +}
\ No newline at end of file diff --git a/src/main/java/org/bukkit/potion/PotionBrewer.java b/src/main/java/org/bukkit/potion/PotionBrewer.java new file mode 100644 index 00000000..14df6a05 --- /dev/null +++ b/src/main/java/org/bukkit/potion/PotionBrewer.java @@ -0,0 +1,31 @@ +package org.bukkit.potion; + +import java.util.Collection; + +/** + * Represents a brewer that can create {@link PotionEffect}s. + */ +public interface PotionBrewer { + /** + * Creates a {@link PotionEffect} from the given {@link PotionEffectType}, + * applying duration modifiers and checks. + * + * @param potion + * The type of potion + * @param duration + * The duration in ticks + * @param amplifier + * The amplifier of the effect + */ + public PotionEffect createEffect(PotionEffectType potion, int duration, int amplifier); + + /** + * Returns a collection of {@link PotionEffect} that would be applied from a + * potion with the given data value. + * + * @param damage + * The data value of the potion + * @return + */ + public Collection<PotionEffect> getEffectsFromDamage(int damage); +} diff --git a/src/main/java/org/bukkit/potion/PotionEffect.java b/src/main/java/org/bukkit/potion/PotionEffect.java new file mode 100644 index 00000000..e4066323 --- /dev/null +++ b/src/main/java/org/bukkit/potion/PotionEffect.java @@ -0,0 +1,85 @@ +package org.bukkit.potion; + +import org.apache.commons.lang.Validate; +import org.bukkit.entity.LivingEntity; + +/** + * Represents a potion effect, that can be added to a {@link LivingEntity}. A + * potion effect has a duration that it will last for, an amplifier that will + * enhance its effects, and a {@link PotionEffectType}, that represents its + * effect on an entity. + */ +public class PotionEffect { + private final int amplifier; + private final int duration; + private final PotionEffectType type; + + public PotionEffect(PotionEffectType type, int duration, int amplifier) { + Validate.notNull(type, "effect type cannot be null"); + this.type = type; + this.duration = duration; + this.amplifier = amplifier; + } + + /** + * Attempts to add the effect represented by this object to the given + * {@link LivingEntity}. + * + * @see LivingEntity#addPotionEffect(PotionEffect) + * @param entity + * The entity to add this effect to + */ + public boolean apply(LivingEntity entity) { + return entity.addPotionEffect(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + PotionEffect other = (PotionEffect) obj; + if (type == null) { + if (other.type != null) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + return true; + } + + /** + * Returns the amplifier of this effect. A higher amplifier means the potion + * effect happens more often over its duration and in some cases has more + * effect on its target. + */ + public int getAmplifier() { + return amplifier; + } + + /** + * Returns the duration (in ticks) that this effect will run for when + * applied to a {@link LivingEntity}. + */ + public int getDuration() { + return duration; + } + + /** + * Returns the {@link PotionEffectType} of this effect. + * + * @return The potion type of this effect + */ + public PotionEffectType getType() { + return type; + } + + @Override + public int hashCode() { + return 31 + ((type == null) ? 0 : type.hashCode()); + }; +} diff --git a/src/main/java/org/bukkit/potion/PotionEffectType.java b/src/main/java/org/bukkit/potion/PotionEffectType.java new file mode 100644 index 00000000..d43aea5e --- /dev/null +++ b/src/main/java/org/bukkit/potion/PotionEffectType.java @@ -0,0 +1,239 @@ +package org.bukkit.potion; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang.Validate; + +/** + * Represents a type of potion and its effect on an entity. + */ +public abstract class PotionEffectType { + /** + * Increases movement speed. + */ + public static PotionEffectType SPEED = new PotionEffectTypeWrapper(1); + + /** + * Decreases movement speed. + */ + public static PotionEffectType SLOW = new PotionEffectTypeWrapper(2); + + /** + * Increases dig speed. + */ + public static PotionEffectType FAST_DIGGING = new PotionEffectTypeWrapper(3); + + /** + * Decreases dig speed. + */ + public static PotionEffectType SLOW_DIGGING = new PotionEffectTypeWrapper(4); + + /** + * Increases damage dealt. + */ + public static PotionEffectType INCREASE_DAMAGE = new PotionEffectTypeWrapper(5); + + /** + * Heals an entity. + */ + public static PotionEffectType HEAL = new PotionEffectTypeWrapper(6); + + /** + * Hurts an entity. + */ + public static PotionEffectType HARM = new PotionEffectTypeWrapper(7); + + /** + * Increases jump height. + */ + public static PotionEffectType JUMP = new PotionEffectTypeWrapper(8); + + /** + * Warps vision on the client. + */ + public static PotionEffectType CONFUSION = new PotionEffectTypeWrapper(9); + + /** + * Regenerates health. + */ + public static PotionEffectType REGENERATION = new PotionEffectTypeWrapper(10); + + /** + * Decreases damage dealt to an entity. + */ + public static PotionEffectType DAMAGE_RESISTANCE = new PotionEffectTypeWrapper(11); + + /** + * Stops fire damage. + */ + public static PotionEffectType FIRE_RESISTANCE = new PotionEffectTypeWrapper(12); + + /** + * Allows breathing underwater. + */ + public static PotionEffectType WATER_BREATHING = new PotionEffectTypeWrapper(13); + + /** + * Grants invisibility. + */ + @Deprecated + public static PotionEffectType INVISIBILITY = new PotionEffectTypeWrapper(14); // unimplemented + + /** + * Blinds an entity. + */ + public static PotionEffectType BLINDNESS = new PotionEffectTypeWrapper(15); + + /** + * Allows an entity to see in the dark. + */ + @Deprecated + public static PotionEffectType NIGHT_VISION = new PotionEffectTypeWrapper(16); // unimplemented + + /** + * Increases hunger. + */ + public static PotionEffectType HUNGER = new PotionEffectTypeWrapper(17); + + /** + * Decreases damage dealt by an entity. + */ + public static PotionEffectType WEAKNESS = new PotionEffectTypeWrapper(18); + + /** + * Deals damage to an entity over time. + */ + public static PotionEffectType POISON = new PotionEffectTypeWrapper(19); + + private final int id; + + protected PotionEffectType(int id) { + this.id = id; + } + + public PotionEffect createEffect(int duration, int amplifier) { + return Potion.getBrewer().createEffect(this, duration, amplifier); + } + + /** + * Returns the duration modifier applied to effects of this type. + * + * @return duration modifier + */ + public abstract double getDurationModifier(); + + /** + * Returns the unique ID of this type. + * + * @return Unique ID + */ + public int getId() { + return id; + } + + /** + * Returns the name of this effect type. + * + * @return The name of this effect type + */ + public abstract String getName(); + + /** + * Returns whether the effect of this type happens once, immediately. + * + * @return whether this type is normally instant + */ + public abstract boolean isInstant(); + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof PotionEffectType)) { + return false; + } + final PotionEffectType other = (PotionEffectType) obj; + if (this.id != other.id) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public String toString() { + return "PotionEffectType[" + id + ", " + getName() + "]"; + } + + private static final PotionEffectType[] byId = new PotionEffectType[20]; + private static final Map<String, PotionEffectType> byName = new HashMap<String, PotionEffectType>(); + // will break on updates. + private static boolean acceptingNew = true; + + /** + * Gets the effect type specified by the unique id. + * + * @param id + * Unique ID to fetch + * @return Resulting type, or null if not found. + */ + public static PotionEffectType getById(int id) { + if (id >= byId.length || id < 0) + return null; + return byId[id]; + } + + /** + * Gets the effect type specified by the given name. + * + * @param name + * Name of PotionEffectType to fetch + * @return Resulting PotionEffectType, or null if not found. + */ + public static PotionEffectType getByName(String name) { + Validate.notNull(name, "name cannot be null"); + return byName.get(name.toLowerCase()); + } + + /** + * Registers an effect type with the given object. + * <p> + * Generally not to be used from within a plugin. + * + * @param potionType + * PotionType to register + */ + public static void registerPotionEffectType(PotionEffectType type) { + if (byId[type.id] != null || byName.containsKey(type.getName().toLowerCase())) { + throw new IllegalArgumentException("Cannot set already-set type"); + } else if (!acceptingNew) { + throw new IllegalStateException( + "No longer accepting new potion effect types (can only be done by the server implementation)"); + } + + byId[type.id] = type; + byName.put(type.getName().toLowerCase(), type); + } + + /** + * Stops accepting any effect type registrations. + */ + public static void stopAcceptingRegistrations() { + acceptingNew = false; + } + + /** + * Returns an array of all the registered {@link PotionEffectType}s. + * + * @return Array of types. + */ + public static PotionEffectType[] values() { + return byId.clone(); + } +} diff --git a/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java new file mode 100644 index 00000000..d1cc99f3 --- /dev/null +++ b/src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java @@ -0,0 +1,29 @@ +package org.bukkit.potion; + +public class PotionEffectTypeWrapper extends PotionEffectType { + protected PotionEffectTypeWrapper(int id) { + super(id); + } + + @Override + public double getDurationModifier() { + return getType().getDurationModifier(); + } + + @Override + public String getName() { + return getType().getName(); + } + + /** + * Get the potion type bound to this wrapper. + */ + public PotionEffectType getType() { + return PotionEffectType.getById(getId()); + } + + @Override + public boolean isInstant() { + return getType().isInstant(); + } +} diff --git a/src/main/java/org/bukkit/potion/PotionType.java b/src/main/java/org/bukkit/potion/PotionType.java new file mode 100644 index 00000000..851a5d99 --- /dev/null +++ b/src/main/java/org/bukkit/potion/PotionType.java @@ -0,0 +1,45 @@ +package org.bukkit.potion; + +public enum PotionType { + REGEN(1, PotionEffectType.REGENERATION), + SPEED(2, PotionEffectType.SPEED), + FIRE_RESISTANCE(3, PotionEffectType.FIRE_RESISTANCE), + POISON(4, PotionEffectType.POISON), + INSTANT_HEAL(5, PotionEffectType.HEAL), + WEAKNESS(8, PotionEffectType.SPEED), + STRENGTH(9, PotionEffectType.INCREASE_DAMAGE), + SLOWNESS(10, PotionEffectType.SLOW), + INSTANT_DAMAGE(12, PotionEffectType.HARM); + + private final int damageValue; + private final PotionEffectType effect; + + PotionType(int damageValue, PotionEffectType effect) { + this.damageValue = damageValue; + this.effect = effect; + } + + public PotionEffectType getEffectType() { + return effect; + } + + protected int getDamageValue() { + return damageValue; + } + + public static PotionType getByDamageValue(int damage) { + for (PotionType type : PotionType.values()) { + if (type.damageValue == damage) + return type; + } + return null; + } + + public static PotionType getByEffect(PotionEffectType effectType) { + for (PotionType type : PotionType.values()) { + if (type.effect.equals(effectType)) + return type; + } + return null; + } +} |