001    package org.bukkit.potion;
002    
003    import java.util.HashMap;
004    import java.util.Map;
005    
006    import org.apache.commons.lang.Validate;
007    
008    /**
009     * Represents a type of potion and its effect on an entity.
010     */
011    public abstract class PotionEffectType {
012        /**
013         * Increases movement speed.
014         */
015        public static final PotionEffectType SPEED = new PotionEffectTypeWrapper(1);
016    
017        /**
018         * Decreases movement speed.
019         */
020        public static final PotionEffectType SLOW = new PotionEffectTypeWrapper(2);
021    
022        /**
023         * Increases dig speed.
024         */
025        public static final PotionEffectType FAST_DIGGING = new PotionEffectTypeWrapper(3);
026    
027        /**
028         * Decreases dig speed.
029         */
030        public static final PotionEffectType SLOW_DIGGING = new PotionEffectTypeWrapper(4);
031    
032        /**
033         * Increases damage dealt.
034         */
035        public static final PotionEffectType INCREASE_DAMAGE = new PotionEffectTypeWrapper(5);
036    
037        /**
038         * Heals an entity.
039         */
040        public static final PotionEffectType HEAL = new PotionEffectTypeWrapper(6);
041    
042        /**
043         * Hurts an entity.
044         */
045        public static final PotionEffectType HARM = new PotionEffectTypeWrapper(7);
046    
047        /**
048         * Increases jump height.
049         */
050        public static final PotionEffectType JUMP = new PotionEffectTypeWrapper(8);
051    
052        /**
053         * Warps vision on the client.
054         */
055        public static final PotionEffectType CONFUSION = new PotionEffectTypeWrapper(9);
056    
057        /**
058         * Regenerates health.
059         */
060        public static final PotionEffectType REGENERATION = new PotionEffectTypeWrapper(10);
061    
062        /**
063         * Decreases damage dealt to an entity.
064         */
065        public static final PotionEffectType DAMAGE_RESISTANCE = new PotionEffectTypeWrapper(11);
066    
067        /**
068         * Stops fire damage.
069         */
070        public static final PotionEffectType FIRE_RESISTANCE = new PotionEffectTypeWrapper(12);
071    
072        /**
073         * Allows breathing underwater.
074         */
075        public static final PotionEffectType WATER_BREATHING = new PotionEffectTypeWrapper(13);
076    
077        /**
078         * Grants invisibility.
079         */
080        public static final PotionEffectType INVISIBILITY = new PotionEffectTypeWrapper(14);
081    
082        /**
083         * Blinds an entity.
084         */
085        public static final PotionEffectType BLINDNESS = new PotionEffectTypeWrapper(15);
086    
087        /**
088         * Allows an entity to see in the dark.
089         */
090        public static final PotionEffectType NIGHT_VISION = new PotionEffectTypeWrapper(16);
091    
092        /**
093         * Increases hunger.
094         */
095        public static final PotionEffectType HUNGER = new PotionEffectTypeWrapper(17);
096    
097        /**
098         * Decreases damage dealt by an entity.
099         */
100        public static final PotionEffectType WEAKNESS = new PotionEffectTypeWrapper(18);
101    
102        /**
103         * Deals damage to an entity over time.
104         */
105        public static final PotionEffectType POISON = new PotionEffectTypeWrapper(19);
106    
107        /**
108         * Deals damage to an entity over time and gives the health to the shooter.
109         */
110        public static final PotionEffectType WITHER = new PotionEffectTypeWrapper(20);
111    
112        private final int id;
113    
114        protected PotionEffectType(int id) {
115            this.id = id;
116        }
117    
118        /**
119         * Creates a PotionEffect from this PotionEffectType, applying duration modifiers and checks.
120         *
121         * @see PotionBrewer#createEffect(PotionEffectType, int, int)
122         * @param duration time in ticks
123         * @param amplifier the effect's amplifier
124         * @return a resulting potion effect
125         */
126        public PotionEffect createEffect(int duration, int amplifier) {
127            return Potion.getBrewer().createEffect(this, duration, amplifier);
128        }
129    
130        /**
131         * Returns the duration modifier applied to effects of this type.
132         *
133         * @return duration modifier
134         */
135        public abstract double getDurationModifier();
136    
137        /**
138         * Returns the unique ID of this type.
139         *
140         * @return Unique ID
141         */
142        public int getId() {
143            return id;
144        }
145    
146        /**
147         * Returns the name of this effect type.
148         *
149         * @return The name of this effect type
150         */
151        public abstract String getName();
152    
153        /**
154         * Returns whether the effect of this type happens once, immediately.
155         *
156         * @return whether this type is normally instant
157         */
158        public abstract boolean isInstant();
159    
160        @Override
161        public boolean equals(Object obj) {
162            if (obj == null) {
163                return false;
164            }
165            if (!(obj instanceof PotionEffectType)) {
166                return false;
167            }
168            final PotionEffectType other = (PotionEffectType) obj;
169            if (this.id != other.id) {
170                return false;
171            }
172            return true;
173        }
174    
175        @Override
176        public int hashCode() {
177            return id;
178        }
179    
180        @Override
181        public String toString() {
182            return "PotionEffectType[" + id + ", " + getName() + "]";
183        }
184    
185        private static final PotionEffectType[] byId = new PotionEffectType[21];
186        private static final Map<String, PotionEffectType> byName = new HashMap<String, PotionEffectType>();
187        // will break on updates.
188        private static boolean acceptingNew = true;
189    
190        /**
191         * Gets the effect type specified by the unique id.
192         *
193         * @param id Unique ID to fetch
194         * @return Resulting type, or null if not found.
195         */
196        public static PotionEffectType getById(int id) {
197            if (id >= byId.length || id < 0)
198                return null;
199            return byId[id];
200        }
201    
202        /**
203         * Gets the effect type specified by the given name.
204         *
205         * @param name Name of PotionEffectType to fetch
206         * @return Resulting PotionEffectType, or null if not found.
207         */
208        public static PotionEffectType getByName(String name) {
209            Validate.notNull(name, "name cannot be null");
210            return byName.get(name.toLowerCase());
211        }
212    
213        /**
214         * Registers an effect type with the given object.
215         * <p />
216         * Generally not to be used from within a plugin.
217         *
218         * @param type PotionType to register
219         */
220        public static void registerPotionEffectType(PotionEffectType type) {
221            if (byId[type.id] != null || byName.containsKey(type.getName().toLowerCase())) {
222                throw new IllegalArgumentException("Cannot set already-set type");
223            } else if (!acceptingNew) {
224                throw new IllegalStateException(
225                        "No longer accepting new potion effect types (can only be done by the server implementation)");
226            }
227    
228            byId[type.id] = type;
229            byName.put(type.getName().toLowerCase(), type);
230        }
231    
232        /**
233         * Stops accepting any effect type registrations.
234         */
235        public static void stopAcceptingRegistrations() {
236            acceptingNew = false;
237        }
238    
239        /**
240         * Returns an array of all the registered {@link PotionEffectType}s.
241         *
242         * @return Array of types.
243         */
244        public static PotionEffectType[] values() {
245            return byId.clone();
246        }
247    }