/* * 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-2014 Peter Güttinger * */ package ch.njol.skript.effects; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.ScriptLoader; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Conditional; import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.Loop; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.TriggerItem; import ch.njol.skript.lang.TriggerSection; import ch.njol.skript.lang.While; import ch.njol.skript.log.ErrorQuality; import ch.njol.util.Kleenean; /** * @author Peter Güttinger */ @Name("Exit") @Description("Exits a given amount of loops and conditionals, or the entire trigger.") @Examples({"if player has any ore:", " stop", "message \"%player% has no ores!\"", "loop blocks above the player:", " loop-block is not air:", " exit 2 sections", " set loop-block to water"}) @Since("") public class EffExit extends Effect { // TODO [code style] warn user about code after a stop effect static { Skript.registerEffect(EffExit.class, "(exit|stop) [trigger]", "(exit|stop) [(1|a|the|this)] (0¦section|1¦loop|2¦conditional)", "(exit|stop) <\\d+> (0¦section|1¦loop|2¦conditional)s", "(exit|stop) all (0¦section|1¦loop|2¦conditional)s"); } private int breakLevels; private final static int EVERYTHING = 0, LOOPS = 1, CONDITIONALS = 2; private final static String[] names = {"sections", "loops", "conditionals"}; private int type; @Override public boolean init(final Expression<?>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) { switch (matchedPattern) { case 0: breakLevels = ScriptLoader.currentSections.size() + 1; type = EVERYTHING; break; case 1: case 2: breakLevels = matchedPattern == 1 ? 1 : Integer.parseInt(parser.regexes.get(0).group()); type = parser.mark; if (breakLevels > numLevels(type)) { if (numLevels(type) == 0) Skript.error("can't stop any " + names[type] + " as there are no " + names[type] + " present", ErrorQuality.SEMANTIC_ERROR); else Skript.error("can't stop " + breakLevels + " " + names[type] + " as there are only " + numLevels(type) + " " + names[type] + " present", ErrorQuality.SEMANTIC_ERROR); return false; } break; case 3: type = parser.mark; breakLevels = numLevels(type); if (breakLevels == 0) { Skript.error("can't stop any " + names[type] + " as there are no " + names[type] + " present", ErrorQuality.SEMANTIC_ERROR); return false; } break; } return true; } private final static int numLevels(final int type) { if (type == EVERYTHING) return ScriptLoader.currentSections.size(); int r = 0; for (final TriggerSection s : ScriptLoader.currentSections) { if (type == CONDITIONALS ? s instanceof Conditional : s instanceof Loop || s instanceof While) r++; } return r; } @Override @Nullable protected TriggerItem walk(final Event e) { debug(e, false); TriggerItem n = this; for (int i = breakLevels; i > 0;) { n = n.getParent(); if (n == null) { assert false : this; return null; } if (type == EVERYTHING || type == CONDITIONALS && n instanceof Conditional || type == LOOPS && (n instanceof Loop || n instanceof While)) i--; } return n instanceof Loop ? ((Loop) n).getActualNext() : n instanceof While ? ((While) n).getActualNext() : n.getNext(); } @Override protected void execute(final Event e) { assert false; } @Override public String toString(final @Nullable Event e, final boolean debug) { return "stop " + breakLevels + " " + names[type]; } }