001 package org.bukkit.potion; 002 003 import java.util.Map; 004 import java.util.NoSuchElementException; 005 006 import org.apache.commons.lang.Validate; 007 import org.bukkit.configuration.serialization.ConfigurationSerializable; 008 import org.bukkit.configuration.serialization.SerializableAs; 009 import org.bukkit.entity.LivingEntity; 010 011 import com.google.common.collect.ImmutableMap; 012 013 /** 014 * Represents a potion effect, that can be added to a {@link LivingEntity}. A 015 * potion effect has a duration that it will last for, an amplifier that will 016 * enhance its effects, and a {@link PotionEffectType}, that represents its 017 * effect on an entity. 018 */ 019 @SerializableAs("PotionEffect") 020 public class PotionEffect implements ConfigurationSerializable { 021 private static final String AMPLIFIER = "amplifier"; 022 private static final String DURATION = "duration"; 023 private static final String TYPE = "effect"; 024 private static final String AMBIENT = "ambient"; 025 private final int amplifier; 026 private final int duration; 027 private final PotionEffectType type; 028 private final boolean ambient; 029 030 /** 031 * Creates a potion effect. 032 * 033 * @param type effect type 034 * @param duration measured in ticks, see {@link 035 * PotionEffect#getDuration()} 036 * @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()} 037 * @param ambient the ambient status, see {@link PotionEffect#isAmbient()} 038 */ 039 public PotionEffect(PotionEffectType type, int duration, int amplifier, boolean ambient) { 040 Validate.notNull(type, "effect type cannot be null"); 041 this.type = type; 042 this.duration = duration; 043 this.amplifier = amplifier; 044 this.ambient = ambient; 045 } 046 047 /** 048 * Creates a potion effect. Assumes ambient is true. 049 * 050 * @param type Effect type 051 * @param duration measured in ticks 052 * @param amplifier the amplifier for the effect 053 * @see PotionEffect#PotionEffect(PotionEffectType, int, int, boolean) 054 */ 055 public PotionEffect(PotionEffectType type, int duration, int amplifier) { 056 this(type, duration, amplifier, true); 057 } 058 059 /** 060 * Constructor for deserialization. 061 * 062 * @param map the map to deserialize from 063 */ 064 public PotionEffect(Map<String, Object> map) { 065 this(getEffectType(map), getInt(map, DURATION), getInt(map, AMPLIFIER), getBool(map, AMBIENT)); 066 } 067 068 private static PotionEffectType getEffectType(Map<?,?> map) { 069 int type = getInt(map, TYPE); 070 PotionEffectType effect = PotionEffectType.getById(type); 071 if (effect != null) { 072 return effect; 073 } 074 throw new NoSuchElementException(map + " does not contain " + TYPE); 075 } 076 077 private static int getInt(Map<?,?> map, Object key) { 078 Object num = map.get(key); 079 if (num instanceof Integer) { 080 return (Integer) num; 081 } 082 throw new NoSuchElementException(map + " does not contain " + key); 083 } 084 085 private static boolean getBool(Map<?,?> map, Object key) { 086 Object bool = map.get(key); 087 if (bool instanceof Boolean) { 088 return (Boolean) bool; 089 } 090 throw new NoSuchElementException(map + " does not contain " + key); 091 } 092 093 public Map<String, Object> serialize() { 094 return ImmutableMap.<String, Object>of( 095 TYPE, type.getId(), 096 DURATION, duration, 097 AMPLIFIER, amplifier, 098 AMBIENT, ambient 099 ); 100 } 101 102 /** 103 * Attempts to add the effect represented by this object to the given 104 * {@link LivingEntity}. 105 * 106 * @see LivingEntity#addPotionEffect(PotionEffect) 107 * @param entity The entity to add this effect to 108 * @return Whether the effect could be added 109 */ 110 public boolean apply(LivingEntity entity) { 111 return entity.addPotionEffect(this); 112 } 113 114 @Override 115 public boolean equals(Object obj) { 116 if (this == obj) { 117 return true; 118 } 119 if (!(obj instanceof PotionEffect)) { 120 return false; 121 } 122 PotionEffect that = (PotionEffect) obj; 123 return this.type.equals(that.type) && this.ambient == that.ambient && this.amplifier == that.amplifier && this.duration == that.duration; 124 } 125 126 /** 127 * Returns the amplifier of this effect. A higher amplifier means the 128 * potion effect happens more often over its duration and in some cases 129 * has more effect on its target. 130 * 131 * @return The effect amplifier 132 */ 133 public int getAmplifier() { 134 return amplifier; 135 } 136 137 /** 138 * Returns the duration (in ticks) that this effect will run for when 139 * applied to a {@link LivingEntity}. 140 * 141 * @return The duration of the effect 142 */ 143 public int getDuration() { 144 return duration; 145 } 146 147 /** 148 * Returns the {@link PotionEffectType} of this effect. 149 * 150 * @return The potion type of this effect 151 */ 152 public PotionEffectType getType() { 153 return type; 154 } 155 156 /** 157 * Makes potion effect produce more, translucent, particles. 158 * 159 * @return if this effect is ambient 160 */ 161 public boolean isAmbient() { 162 return ambient; 163 } 164 165 @Override 166 public int hashCode() { 167 int hash = 1; 168 hash = hash * 31 + type.hashCode(); 169 hash = hash * 31 + amplifier; 170 hash = hash * 31 + duration; 171 hash ^= 0x22222222 >> (ambient ? 1 : -1); 172 return hash; 173 } 174 175 @Override 176 public String toString() { 177 return type.getName() + (ambient ? ":(" : ":") + duration + "t-x" + amplifier + (ambient ? ")" : ""); 178 } 179 }