/*
* 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.events;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.eclipse.jdt.annotation.Nullable;
import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.classes.Comparator.Relation;
import ch.njol.skript.classes.data.DefaultComparators;
import ch.njol.skript.entity.EntityData;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.log.ErrorQuality;
import ch.njol.util.Checker;
import ch.njol.util.coll.CollectionUtils;
/**
* @author Peter Güttinger
*/
@SuppressWarnings("unchecked")
public class EvtClick extends SkriptEvent {
// Important: a click on an entity fires both an PlayerInteractEntityEvent and a PlayerInteractEvent
private final static int RIGHT = 1, LEFT = 2, ANY = RIGHT | LEFT;
static {
Skript.registerEvent("Click", EvtClick.class, CollectionUtils.array(PlayerInteractEvent.class, PlayerInteractEntityEvent.class),
"[(" + RIGHT + "¦right|" + LEFT + "¦left)(| |-)][mouse(| |-)]click[ing] [on %-entitydata/itemtype%] [(with|using|holding) %itemtype%]",
"[(" + RIGHT + "¦right|" + LEFT + "¦left)(| |-)][mouse(| |-)]click[ing] (with|using|holding) %itemtype% on %entitydata/itemtype%")
.description("Called when a user clicks on a block, an entity or air with or without an item in their hand.",
"Please note that rightclick events with an empty hand while not looking at a block are not sent to the server, so there's no way to detect them.")
.examples("on click",
"on rightclick holding a fishing rod",
"on leftclick on a stone or obsidian",
"on rightclick on a creeper",
"on click with a sword")
.since("1.0");
}
@Nullable
private Literal<?> types = null;
@Nullable
private Literal<ItemType> tools;
private int click = ANY;
@Override
public boolean init(final Literal<?>[] args, final int matchedPattern, final ParseResult parser) {
click = parser.mark == 0 ? ANY : parser.mark;
types = args[matchedPattern];
if (types != null && !ItemType.class.isAssignableFrom(types.getReturnType())) {
if (click == LEFT) {
Skript.error("A leftclick on an entity is an attack and thus not covered by the 'click' event, but the 'damage' event.", ErrorQuality.SEMANTIC_ERROR);
return false;
} else if (click == ANY) {
Skript.warning("A leftclick on an entity is an attack and thus not covered by the 'click' event, but the 'damage' event. Change this event to a rightclick to disable this warning message.");
}
}
tools = (Literal<ItemType>) args[1 - matchedPattern];
return true;
}
@Override
public boolean check(final Event e) {
final Player player;
final Block block;
final Entity entity;
if (e instanceof PlayerInteractEntityEvent) {
if (click == LEFT || types == null) // types == null will be handled by the PlayerInteractEvent that is fired as well
return false;
player = ((PlayerInteractEntityEvent) e).getPlayer();
entity = ((PlayerInteractEntityEvent) e).getRightClicked();
block = null;
} else if (e instanceof PlayerInteractEvent) {
final Action a = ((PlayerInteractEvent) e).getAction();
final int click;
switch (a) {
case LEFT_CLICK_AIR:
case LEFT_CLICK_BLOCK:
click = LEFT;
break;
case RIGHT_CLICK_AIR:
case RIGHT_CLICK_BLOCK:
click = RIGHT;
break;
case PHYSICAL:
default:
return false;
}
if ((this.click & click) == 0)
return false;
player = ((PlayerInteractEvent) e).getPlayer();
block = ((PlayerInteractEvent) e).getClickedBlock();
entity = null;
} else {
assert false;
return false;
}
if (tools != null && !tools.check(e, new Checker<ItemType>() {
@Override
public boolean check(final ItemType t) {
return t.isOfType(player.getItemInHand());
}
})) {
return false;
}
if (types != null) {
return types.check(e, new Checker<Object>() {
@Override
public boolean check(final Object o) {
if (entity != null) {
return o instanceof EntityData ? ((EntityData<?>) o).isInstance(entity) : Relation.EQUAL.is(DefaultComparators.entityItemComparator.compare(EntityData.fromEntity(entity), (ItemType) o));
} else {
return o instanceof EntityData ? false : ((ItemType) o).isOfType(block);
}
}
});
}
return true;
}
@Override
public String toString(final @Nullable Event e, final boolean debug) {
return (click == LEFT ? "left" : click == RIGHT ? "right" : "") + "click" + (types != null ? " on " + types.toString(e, debug) : "") + (tools != null ? " holding " + tools.toString(e, debug) : "");
}
}