/* * This file is part of Skript. * * Skript is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Skript is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Skript. If not, see <http://www.gnu.org/licenses/>. * * * Copyright 2011, 2012 Peter Güttinger * */ package ch.njol.skript.util; import java.util.ArrayList; import java.util.List; import org.bukkit.Effect; import org.bukkit.EntityEffect; import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.SyntaxElement; import ch.njol.skript.lang.SyntaxElementInfo; import ch.njol.skript.localization.Language; import ch.njol.skript.localization.LanguageChangeListener; import ch.njol.skript.localization.Noun; import ch.njol.skript.variables.Variables; import ch.njol.util.Kleenean; import ch.njol.util.StringUtils; import ch.njol.util.coll.iterator.SingleItemIterator; import ch.njol.yggdrasil.YggdrasilSerializable; /** * @author Peter Güttinger */ public final class VisualEffect implements SyntaxElement, YggdrasilSerializable { private final static String LANGUAGE_NODE = "visual effects"; private static enum Type implements YggdrasilSerializable { ENDER_SIGNAL(Effect.ENDER_SIGNAL), MOBSPAWNER_FLAMES(Effect.MOBSPAWNER_FLAMES), POTION_BREAK(Effect.POTION_BREAK) { @Override public Object getData(final @Nullable Object raw, final Location l) { return new PotionEffect(raw == null ? PotionEffectType.SPEED : (PotionEffectType) raw, 1, 0); } }, SMOKE(Effect.SMOKE) { @Override public Object getData(final @Nullable Object raw, final Location l) { if (raw == null) return BlockFace.SELF; return Direction.getFacing(((Direction) raw).getDirection(l), false); // TODO allow this to not be a literal } }, HURT(EntityEffect.HURT), SHEEP_EAT(EntityEffect.SHEEP_EAT), WOLF_HEARTS(EntityEffect.WOLF_HEARTS), WOLF_SHAKE(EntityEffect.WOLF_SHAKE), WOLF_SMOKE(EntityEffect.WOLF_SMOKE); final Object effect; private Type(final Effect effect) { this.effect = effect; } private Type(final EntityEffect effect) { this.effect = effect; } /** * Converts the data from the pattern to the data required by Bukkit */ @Nullable public Object getData(final @Nullable Object raw, final Location l) { assert raw == null; return null; } } private final static String TYPE_ID = "VisualEffect.Type"; static { Variables.yggdrasil.registerSingleClass(Type.class, TYPE_ID); Variables.yggdrasil.registerSingleClass(Effect.class, "Bukkit_Effect"); Variables.yggdrasil.registerSingleClass(EntityEffect.class, "Bukkit_EntityEffect"); } @Nullable static SyntaxElementInfo<VisualEffect> info; final static List<Type> types = new ArrayList<Type>(Type.values().length); final static Noun[] names = new Noun[Type.values().length]; static { Language.addListener(new LanguageChangeListener() { @Override public void onLanguageChange() { final Type[] ts = Type.values(); types.clear(); final List<String> patterns = new ArrayList<String>(ts.length); for (int i = 0; i < ts.length; i++) { final String node = LANGUAGE_NODE + "." + ts[i].name(); final String pattern = Language.get_(node + ".pattern"); if (pattern == null) { if (Skript.testing()) Skript.warning("Missing pattern at '" + (node + ".pattern") + "' in the " + Language.getName() + " language file"); } else { types.add(ts[i]); patterns.add(pattern); } if (names[i] == null) names[i] = new Noun(node + ".name"); } final String[] ps = patterns.toArray(new String[patterns.size()]); assert ps != null; info = new SyntaxElementInfo<VisualEffect>(ps, VisualEffect.class); } }); } private Type type; @Nullable private Object data; /** * For parsing & deserialisation */ @SuppressWarnings("null") public VisualEffect() {} @SuppressWarnings("null") @Override public boolean init(final Expression<?>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { type = types.get(matchedPattern); assert exprs.length <= 1; data = exprs.length == 0 || exprs[0] == null ? null : exprs[0].getSingle(null); return true; } public boolean isEntityEffect() { return type.effect instanceof EntityEffect; } @Nullable public final static VisualEffect parse(final String s) { final SyntaxElementInfo<VisualEffect> info = VisualEffect.info; if (info == null) return null; return SkriptParser.parseStatic(Noun.stripIndefiniteArticle(s), new SingleItemIterator<SyntaxElementInfo<VisualEffect>>(info), null); } public void play(final @Nullable Player[] ps, final Location l, final @Nullable Entity e) { assert e == null || l.equals(e.getLocation()); if (isEntityEffect()) { if (e != null) e.playEffect((EntityEffect) type.effect); } else { if (ps == null) { l.getWorld().playEffect(l, (Effect) type.effect, type.getData(data, l)); } else { for (final Player p : ps) p.playEffect(l, (Effect) type.effect, type.getData(data, l)); } } } @Override public String toString() { return toString(0); } public String toString(final int flags) { return names[type.ordinal()].toString(flags); } public static String getAllNames() { return StringUtils.join(names, ", "); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + type.hashCode(); final Object d = data; result = prime * result + ((d == null) ? 0 : d.hashCode()); return result; } @Override public boolean equals(final @Nullable Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof VisualEffect)) return false; final VisualEffect other = (VisualEffect) obj; if (type != other.type) return false; final Object d = data; if (d == null) { if (other.data != null) return false; } else if (!d.equals(other.data)) { return false; } return true; } }