summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorfullwall <fullwall@optusnet.com>2012-01-09 14:39:06 +0800
committerEvilSeph <evilseph@gmail.com>2012-02-10 17:26:38 -0500
commitd99c95f6d1b9a91f5f9c254b8e2fa615ea31e3c6 (patch)
treef9b8f32218a2a35d3a90e35eda71d2c297106ee4 /src
parentec01da91bbba8d4a1d928df6273389923491e75e (diff)
downloadbukkit-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')
-rw-r--r--src/main/java/org/bukkit/entity/LivingEntity.java52
-rw-r--r--src/main/java/org/bukkit/entity/Player.java1
-rw-r--r--src/main/java/org/bukkit/entity/ThrownPotion.java9
-rw-r--r--src/main/java/org/bukkit/potion/Potion.java265
-rw-r--r--src/main/java/org/bukkit/potion/PotionBrewer.java31
-rw-r--r--src/main/java/org/bukkit/potion/PotionEffect.java85
-rw-r--r--src/main/java/org/bukkit/potion/PotionEffectType.java239
-rw-r--r--src/main/java/org/bukkit/potion/PotionEffectTypeWrapper.java29
-rw-r--r--src/main/java/org/bukkit/potion/PotionType.java45
-rw-r--r--src/test/java/org/bukkit/plugin/messaging/TestPlayer.java27
-rw-r--r--src/test/java/org/bukkit/potion/PotionTest.java109
11 files changed, 891 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;
+ }
+}
diff --git a/src/test/java/org/bukkit/plugin/messaging/TestPlayer.java b/src/test/java/org/bukkit/plugin/messaging/TestPlayer.java
index 95e02c76..63180720 100644
--- a/src/test/java/org/bukkit/plugin/messaging/TestPlayer.java
+++ b/src/test/java/org/bukkit/plugin/messaging/TestPlayer.java
@@ -1,6 +1,7 @@
package org.bukkit.plugin.messaging;
import java.net.InetSocketAddress;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -23,6 +24,8 @@ import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
public class TestPlayer implements Player {
@@ -621,4 +624,28 @@ public class TestPlayer implements Player {
public boolean canSee(Player player) {
throw new UnsupportedOperationException("Not supported yet.");
}
+
+ public boolean addPotionEffect(PotionEffect effect) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean addPotionEffect(PotionEffect effect, boolean force) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean addPotionEffects(Collection<PotionEffect> effects) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean hasPotionEffect(PotionEffectType type) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void removePotionEffect(PotionEffectType type) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Collection<PotionEffect> getActivePotionEffects() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
}
diff --git a/src/test/java/org/bukkit/potion/PotionTest.java b/src/test/java/org/bukkit/potion/PotionTest.java
new file mode 100644
index 00000000..fe641b86
--- /dev/null
+++ b/src/test/java/org/bukkit/potion/PotionTest.java
@@ -0,0 +1,109 @@
+package org.bukkit.potion;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+
+import org.bukkit.Material;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.Potion.Tier;
+import org.junit.Test;
+
+public class PotionTest {
+ @Test
+ public void applyToItemStack() {
+ Potion potion = new Potion(PotionType.POISON);
+ ItemStack stack = new ItemStack(Material.POTION, 1);
+ potion.apply(stack);
+ assertTrue(stack.getDurability() == potion.toDamageValue());
+ }
+
+ @Test
+ public void fromDamage() {
+ Potion potion = Potion.fromDamage(PotionType.POISON.getDamageValue());
+ assertTrue(potion.getType() == PotionType.POISON);
+ potion = Potion.fromDamage(PotionType.POISON.getDamageValue() | SPLASH_BIT);
+ assertTrue(potion.getType() == PotionType.POISON && potion.isSplash());
+ potion = Potion.fromDamage(0x25 /* Potion of Healing II */);
+ assertTrue(potion.getType() == PotionType.INSTANT_HEAL && potion.getTier() == Tier.TWO);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void illegalApplyToItemStack() {
+ Potion potion = new Potion(PotionType.POISON);
+ potion.apply(new ItemStack(Material.AIR, 1));
+ }
+
+ @Test
+ public void ItemStackConversion() {
+ Potion potion = new Potion(PotionType.POISON);
+ ItemStack itemstack = potion.toItemStack(1);
+ assertThat(itemstack.getType(), is(Material.POTION));
+ assertTrue(itemstack.getAmount() == 1);
+ assertTrue(itemstack.getDurability() == potion.toDamageValue());
+ }
+
+ @Test
+ public void setExtended() {
+ Potion potion = new Potion(PotionType.POISON);
+ assertFalse(potion.hasExtendedDuration());
+ potion.setHasExtendedDuration(true);
+ assertTrue(potion.hasExtendedDuration());
+ assertTrue((potion.toDamageValue() & EXTENDED_BIT) != 0);
+ }
+
+ @Test
+ public void setSplash() {
+ Potion potion = new Potion(PotionType.POISON);
+ assertFalse(potion.isSplash());
+ potion.setSplash(true);
+ assertTrue(potion.isSplash());
+ assertTrue((potion.toDamageValue() & SPLASH_BIT) != 0);
+ }
+
+ @Test
+ public void setTier() {
+ Potion potion = new Potion(PotionType.POISON);
+ assertThat(potion.getTier(), is(Tier.ONE));
+ potion.setTier(Tier.TWO);
+ assertThat(potion.getTier(), is(Tier.TWO));
+ assertTrue(potion.toDamageValue() == (PotionType.POISON.getDamageValue() | potion.getTier().getDamageBit()));
+ }
+
+ @Test
+ public void useNulls() {
+ try {
+ new Potion(null);
+ fail("cannot use null type in constructor");
+ } catch (IllegalArgumentException ex) {
+ }
+
+ try {
+ new Potion(PotionType.POISON, null);
+ fail("cannot use null tier in constructor");
+ } catch (IllegalArgumentException ex) {
+ }
+
+ Potion potion = new Potion(PotionType.POISON);
+ try {
+ potion.setTier(null);
+ fail("cannot set a null tier");
+ } catch (IllegalArgumentException ex) {
+ }
+
+ try {
+ potion.apply((ItemStack) null);
+ fail("cannot apply to a null itemstack");
+ } catch (IllegalArgumentException ex) {
+ }
+
+ try {
+ potion.apply((LivingEntity) null);
+ fail("cannot apply to a null entity");
+ } catch (IllegalArgumentException ex) {
+ }
+ }
+
+ private static final int EXTENDED_BIT = 0x40;
+ private static final int SPLASH_BIT = 0x4000;
+}