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
109         * shooter.
110         */
111        public static final PotionEffectType WITHER = new PotionEffectTypeWrapper(20);
112    
113        /**
114         * Increases the maximum health of an entity.
115         */
116        public static final PotionEffectType HEALTH_BOOST = new PotionEffectTypeWrapper(21);
117    
118        /**
119         * Increases the maximum health of an entity with health that cannot be
120         * regenerated, but is refilled every 30 seconds.
121         */
122        public static final PotionEffectType ABSORPTION = new PotionEffectTypeWrapper(22);
123    
124        /**
125         * Increases the food level of an entity each tick.
126         */
127        public static final PotionEffectType SATURATION = new PotionEffectTypeWrapper(23);
128    
129        private final int id;
130    
131        protected PotionEffectType(int id) {
132            this.id = id;
133        }
134    
135        /**
136         * Creates a PotionEffect from this PotionEffectType, applying duration
137         * modifiers and checks.
138         *
139         * @see PotionBrewer#createEffect(PotionEffectType, int, int)
140         * @param duration time in ticks
141         * @param amplifier the effect's amplifier
142         * @return a resulting potion effect
143         */
144        public PotionEffect createEffect(int duration, int amplifier) {
145            return Potion.getBrewer().createEffect(this, duration, amplifier);
146        }
147    
148        /**
149         * Returns the duration modifier applied to effects of this type.
150         *
151         * @return duration modifier
152         */
153        public abstract double getDurationModifier();
154    
155        /**
156         * Returns the unique ID of this type.
157         *
158         * @return Unique ID
159         * @deprecated Magic value
160         */
161        @Deprecated
162        public int getId() {
163            return id;
164        }
165    
166        /**
167         * Returns the name of this effect type.
168         *
169         * @return The name of this effect type
170         */
171        public abstract String getName();
172    
173        /**
174         * Returns whether the effect of this type happens once, immediately.
175         *
176         * @return whether this type is normally instant
177         */
178        public abstract boolean isInstant();
179    
180        @Override
181        public boolean equals(Object obj) {
182            if (obj == null) {
183                return false;
184            }
185            if (!(obj instanceof PotionEffectType)) {
186                return false;
187            }
188            final PotionEffectType other = (PotionEffectType) obj;
189            if (this.id != other.id) {
190                return false;
191            }
192            return true;
193        }
194    
195        @Override
196        public int hashCode() {
197            return id;
198        }
199    
200        @Override
201        public String toString() {
202            return "PotionEffectType[" + id + ", " + getName() + "]";
203        }
204    
205        private static final PotionEffectType[] byId = new PotionEffectType[24];
206        private static final Map<String, PotionEffectType> byName = new HashMap<String, PotionEffectType>();
207        // will break on updates.
208        private static boolean acceptingNew = true;
209    
210        /**
211         * Gets the effect type specified by the unique id.
212         *
213         * @param id Unique ID to fetch
214         * @return Resulting type, or null if not found.
215         * @deprecated Magic value
216         */
217        @Deprecated
218        public static PotionEffectType getById(int id) {
219            if (id >= byId.length || id < 0)
220                return null;
221            return byId[id];
222        }
223    
224        /**
225         * Gets the effect type specified by the given name.
226         *
227         * @param name Name of PotionEffectType to fetch
228         * @return Resulting PotionEffectType, or null if not found.
229         */
230        public static PotionEffectType getByName(String name) {
231            Validate.notNull(name, "name cannot be null");
232            return byName.get(name.toLowerCase());
233        }
234    
235        /**
236         * Registers an effect type with the given object.
237         * <p>
238         * Generally not to be used from within a plugin.
239         *
240         * @param type PotionType to register
241         */
242        public static void registerPotionEffectType(PotionEffectType type) {
243            if (byId[type.id] != null || byName.containsKey(type.getName().toLowerCase())) {
244                throw new IllegalArgumentException("Cannot set already-set type");
245            } else if (!acceptingNew) {
246                throw new IllegalStateException(
247                        "No longer accepting new potion effect types (can only be done by the server implementation)");
248            }
249    
250            byId[type.id] = type;
251            byName.put(type.getName().toLowerCase(), type);
252        }
253    
254        /**
255         * Stops accepting any effect type registrations.
256         */
257        public static void stopAcceptingRegistrations() {
258            acceptingNew = false;
259        }
260    
261        /**
262         * Returns an array of all the registered {@link PotionEffectType}s.
263         *
264         * @return Array of types.
265         */
266        public static PotionEffectType[] values() {
267            return byId.clone();
268        }
269    }