package com.nisovin.magicspells.spells;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.Subspell;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.TargetInfo;
import com.nisovin.magicspells.util.Util;
public abstract class TargetedSpell extends InstantSpell {
protected boolean alwaysActivate;
protected boolean playFizzleSound;
protected boolean targetSelf;
protected String spellNameOnFail;
protected Subspell spellOnFail;
protected String strCastTarget;
protected String strNoTarget;
public TargetedSpell(MagicConfig config, String spellName) {
super(config, spellName);
alwaysActivate = getConfigBoolean("always-activate", false);
playFizzleSound = getConfigBoolean("play-fizzle-sound", false);
targetSelf = getConfigBoolean("target-self", false);
spellNameOnFail = getConfigString("spell-on-fail", null);
strCastTarget = getConfigString("str-cast-target", "");
strNoTarget = getConfigString("str-no-target", "");
}
@Override
public void initialize() {
super.initialize();
if (spellNameOnFail != null && !spellNameOnFail.isEmpty()) {
spellOnFail = new Subspell(spellNameOnFail);
if (!spellOnFail.process()) {
spellOnFail = null;
MagicSpells.error("Invalid spell-on-fail for spell " + internalName);
}
}
}
protected void sendMessages(Player caster, LivingEntity target) {
String targetName = getTargetName(target);
Player playerTarget = null;
if (target instanceof Player) {
playerTarget = (Player)target;
}
sendMessage(caster, prepareMessage(strCastSelf, caster, targetName, playerTarget));
if (playerTarget != null) {
sendMessage(playerTarget, prepareMessage(strCastTarget, caster, targetName, playerTarget));
}
sendMessageNear(caster, playerTarget, prepareMessage(strCastOthers, caster, targetName, playerTarget), broadcastRange);
}
private String prepareMessage(String message, Player caster, String targetName, Player playerTarget) {
if (message != null && !message.isEmpty()) {
message = message.replace("%a", caster.getDisplayName());
message = message.replace("%t", targetName);
if (playerTarget != null && MagicSpells.getVariableManager() != null && message.contains("%targetvar")) {
Matcher matcher = chatVarTargetMatchPattern.matcher(message);
while (matcher.find()) {
String varText = matcher.group();
String[] varData = varText.substring(5, varText.length() - 1).split(":");
double val = MagicSpells.getVariableManager().getValue(varData[0], playerTarget);
String sval = varData.length == 1 ? Util.getStringNumber(val, -1) : Util.getStringNumber(val, Integer.parseInt(varData[1]));
message = message.replace(varText, sval);
}
}
if (caster != null && MagicSpells.getVariableManager() != null && message.contains("%castervar")) {
Matcher matcher = chatVarCasterMatchPattern.matcher(message);
while (matcher.find()) {
String varText = matcher.group();
String[] varData = varText.substring(5, varText.length() - 1).split(":");
double val = MagicSpells.getVariableManager().getValue(varData[0], caster);
String sval = varData.length == 1 ? Util.getStringNumber(val, -1) : Util.getStringNumber(val, Integer.parseInt(varData[1]));
message = message.replace(varText, sval);
}
}
}
return message;
}
static private Pattern chatVarCasterMatchPattern = Pattern.compile("%castervar:[A-Za-z0-9_]+(:[0-9]+)?%", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
static private Pattern chatVarTargetMatchPattern = Pattern.compile("%targetvar:[A-Za-z0-9_]+(:[0-9]+)?%", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
protected String getTargetName(LivingEntity target) {
if (target instanceof Player) {
return ((Player)target).getDisplayName();
} else {
String name = MagicSpells.getEntityNames().get(target.getType());
if (name != null) {
return name;
} else {
return "unknown";
}
}
}
/**
* Checks whether two locations are within a certain distance from each other.
* @param loc1 The first location
* @param loc2 The second location
* @param range The maximum distance
* @return true if the distance is less than the range, false otherwise
*/
protected boolean inRange(Location loc1, Location loc2, int range) {
return loc1.distanceSquared(loc2) < range*range;
}
/**
* Plays the fizzle sound if it is enabled for this spell.
*/
protected void fizzle(Player player) {
if (playFizzleSound) {
player.playEffect(player.getLocation(), Effect.EXTINGUISH, null);
}
}
@Override
protected TargetInfo<LivingEntity> getTargetedEntity(Player player, float power, boolean forceTargetPlayers, ValidTargetChecker checker) {
if (targetSelf) {
return new TargetInfo<LivingEntity>(player, power);
} else {
return super.getTargetedEntity(player, power, forceTargetPlayers, checker);
}
}
/**
* This should be called if a target should not be found. It sends the no target message
* and returns the appropriate return value.
* @param player the casting player
* @return the appropriate PostcastAction value
*/
protected PostCastAction noTarget(Player player) {
return noTarget(player, strNoTarget);
}
/**
* This should be called if a target should not be found. It sends the provided message
* and returns the appropriate return value.
* @param player the casting player
* @param message the message to send
* @return
*/
protected PostCastAction noTarget(Player player, String message) {
fizzle(player);
sendMessage(player, message);
if (spellOnFail != null) {
spellOnFail.cast(player, 1.0F);
}
return alwaysActivate ? PostCastAction.NO_MESSAGES : PostCastAction.ALREADY_HANDLED;
}
}