package com.nisovin.magicspells; import java.util.Random; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import com.nisovin.magicspells.Spell.PostCastAction; import com.nisovin.magicspells.Spell.SpellCastResult; import com.nisovin.magicspells.Spell.SpellCastState; import com.nisovin.magicspells.events.SpellCastEvent; import com.nisovin.magicspells.events.SpellCastedEvent; import com.nisovin.magicspells.spells.TargetedEntityFromLocationSpell; import com.nisovin.magicspells.spells.TargetedEntitySpell; import com.nisovin.magicspells.spells.TargetedLocationSpell; import com.nisovin.magicspells.util.Util; public class Subspell { private static Random random = new Random(); private String spellName; private Spell spell; private CastMode mode = CastMode.PARTIAL; private float subPower = 1F; private int delay = 0; private double chance = -1; private boolean isTargetedEntity = false; private boolean isTargetedLocation = false; private boolean isTargetedEntityFromLocation = false; public Subspell(String data) { String[] split = data.split("\\(", 2); spellName = split[0].trim(); if (split.length > 1) { split[1] = split[1].trim(); if (split[1].endsWith(")")) split[1] = split[1].substring(0, split[1].length() - 1); String[] args = Util.splitParams(split[1]); for (String arg : args) { if (arg.contains("=")) { String[] keyval = arg.split("="); if (keyval[0].equalsIgnoreCase("mode")) { if (keyval[1].equalsIgnoreCase("hard")) { mode = CastMode.HARD; } else if (keyval[1].equalsIgnoreCase("full")) { mode = CastMode.FULL; } else if (keyval[1].equalsIgnoreCase("partial")) { mode = CastMode.PARTIAL; } else if (keyval[1].equalsIgnoreCase("direct")) { mode = CastMode.DIRECT; } } else if (keyval[0].equalsIgnoreCase("power")) { try { subPower = Float.parseFloat(keyval[1]); } catch (NumberFormatException e) {} } else if (keyval[0].equalsIgnoreCase("delay")) { try { delay = Integer.parseInt(keyval[1]); } catch (NumberFormatException e) {} } else if (keyval[0].equalsIgnoreCase("chance")) { try { chance = Double.parseDouble(keyval[1]) / 100; } catch (NumberFormatException e) {} } } else if (arg.equalsIgnoreCase("hard")) { mode = CastMode.HARD; } else if (arg.equalsIgnoreCase("full")) { mode = CastMode.FULL; } else if (arg.equalsIgnoreCase("partial")) { mode = CastMode.PARTIAL; } else if (arg.equalsIgnoreCase("direct")) { mode = CastMode.DIRECT; } else if (arg.matches("^[0-9]+$")) { delay = Integer.parseInt(arg); } else if (arg.matches("^[0-9]+\\.[0-9]+$")) { subPower = Float.parseFloat(arg); } } } } public boolean process() { spell = MagicSpells.getSpellByInternalName(spellName); if (spell != null) { isTargetedEntity = spell instanceof TargetedEntitySpell; isTargetedLocation = spell instanceof TargetedLocationSpell; isTargetedEntityFromLocation = spell instanceof TargetedEntityFromLocationSpell; } return spell != null; } public Spell getSpell() { return spell; } public boolean isTargetedEntitySpell() { return isTargetedEntity; } public boolean isTargetedLocationSpell() { return isTargetedLocation; } public boolean isTargetedEntityFromLocationSpell() { return isTargetedEntityFromLocation; } public PostCastAction cast(final Player player, final float power) { if (chance > 0 && chance < 1) { if (random.nextDouble() > chance) { return PostCastAction.ALREADY_HANDLED; } } if (delay <= 0) { return castReal(player, power); } else { MagicSpells.scheduleDelayedTask(new Runnable() { public void run() { castReal(player, power); } }, delay); return PostCastAction.HANDLE_NORMALLY; } } private PostCastAction castReal(Player player, float power) { if ((mode == CastMode.HARD || mode == CastMode.FULL) && player != null) { return spell.cast(player, power * subPower, null).action; } else if (mode == CastMode.PARTIAL) { SpellCastEvent event = new SpellCastEvent(spell, player, SpellCastState.NORMAL, power * subPower, null, 0, null, 0); Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled() && event.getSpellCastState() == SpellCastState.NORMAL) { PostCastAction act = spell.castSpell(player, SpellCastState.NORMAL, event.getPower(), null); Bukkit.getPluginManager().callEvent(new SpellCastedEvent(spell, player, SpellCastState.NORMAL, event.getPower(), null, 0, null, act)); return act; } return PostCastAction.ALREADY_HANDLED; } else { return spell.castSpell(player, SpellCastState.NORMAL, power * subPower, null); } } public boolean castAtEntity(final Player player, final LivingEntity target, final float power) { if (delay <= 0) { return castAtEntityReal(player, target, power); } else { MagicSpells.scheduleDelayedTask(new Runnable() { public void run() { castAtEntityReal(player, target, power); } }, delay); return true; } } private boolean castAtEntityReal(Player player, LivingEntity target, float power) { boolean ret = false; if (isTargetedEntity) { if (mode == CastMode.HARD && player != null) { SpellCastResult result = spell.cast(player, power, null); return result.state == SpellCastState.NORMAL && result.action == PostCastAction.HANDLE_NORMALLY; } else if (mode == CastMode.FULL && player != null) { boolean success = false; SpellCastEvent spellCast = spell.preCast(player, power * subPower, null); if (spellCast != null && spellCast.getSpellCastState() == SpellCastState.NORMAL) { success = ((TargetedEntitySpell)spell).castAtEntity(player, target, spellCast.getPower()); spell.postCast(spellCast, success ? PostCastAction.HANDLE_NORMALLY : PostCastAction.ALREADY_HANDLED); } return success; } else if (mode == CastMode.PARTIAL) { SpellCastEvent event = new SpellCastEvent(spell, player, SpellCastState.NORMAL, power * subPower, null, 0, null, 0); Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled() && event.getSpellCastState() == SpellCastState.NORMAL) { if (player != null) { ret = ((TargetedEntitySpell)spell).castAtEntity(player, target, event.getPower()); } else { ret = ((TargetedEntitySpell)spell).castAtEntity(target, event.getPower()); } if (ret) { Bukkit.getPluginManager().callEvent(new SpellCastedEvent(spell, player, SpellCastState.NORMAL, event.getPower(), null, 0, null, PostCastAction.HANDLE_NORMALLY)); } } } else { if (player != null) { ret = ((TargetedEntitySpell)spell).castAtEntity(player, target, power * subPower); } else { ret = ((TargetedEntitySpell)spell).castAtEntity(target, power * subPower); } } } else if (isTargetedLocation) { castAtLocationReal(player, target.getLocation(), power); } return ret; } public boolean castAtLocation(final Player player, final Location target, final float power) { if (delay <= 0) { return castAtLocationReal(player, target, power); } else { MagicSpells.scheduleDelayedTask(new Runnable() { public void run() { castAtLocationReal(player, target, power); } }, delay); return true; } } private boolean castAtLocationReal(Player player, Location target, float power) { boolean ret = false; if (isTargetedLocation) { if (mode == CastMode.HARD && player != null) { SpellCastResult result = spell.cast(player, power, null); return result.state == SpellCastState.NORMAL && result.action == PostCastAction.HANDLE_NORMALLY; } else if (mode == CastMode.FULL && player != null) { boolean success = false; SpellCastEvent spellCast = spell.preCast(player, power * subPower, null); if (spellCast != null && spellCast.getSpellCastState() == SpellCastState.NORMAL) { success = ((TargetedLocationSpell)spell).castAtLocation(player, target, spellCast.getPower()); spell.postCast(spellCast, success ? PostCastAction.HANDLE_NORMALLY : PostCastAction.ALREADY_HANDLED); } return success; } else if (mode == CastMode.PARTIAL) { SpellCastEvent event = new SpellCastEvent(spell, player, SpellCastState.NORMAL, power * subPower, null, 0, null, 0); Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled() && event.getSpellCastState() == SpellCastState.NORMAL) { if (player != null) { ret = ((TargetedLocationSpell)spell).castAtLocation(player, target, event.getPower()); } else { ret = ((TargetedLocationSpell)spell).castAtLocation(target, event.getPower()); } if (ret) { Bukkit.getPluginManager().callEvent(new SpellCastedEvent(spell, player, SpellCastState.NORMAL, event.getPower(), null, 0, null, PostCastAction.HANDLE_NORMALLY)); } } } else { if (player != null) { ret = ((TargetedLocationSpell)spell).castAtLocation(player, target, power * subPower); } else { ret = ((TargetedLocationSpell)spell).castAtLocation(target, power * subPower); } } } return ret; } public boolean castAtEntityFromLocation(final Player player, final Location from, final LivingEntity target, final float power) { if (delay <= 0) { return castAtEntityFromLocationReal(player, from, target, power); } else { MagicSpells.scheduleDelayedTask(new Runnable() { public void run() { castAtEntityFromLocationReal(player, from, target, power); } }, delay); return true; } } private boolean castAtEntityFromLocationReal(Player player, Location from, LivingEntity target, float power) { boolean ret = false; if (isTargetedEntityFromLocation) { if (mode == CastMode.HARD && player != null) { SpellCastResult result = spell.cast(player, power, null); return result.state == SpellCastState.NORMAL && result.action == PostCastAction.HANDLE_NORMALLY; } else if (mode == CastMode.FULL && player != null) { boolean success = false; SpellCastEvent spellCast = spell.preCast(player, power * subPower, null); if (spellCast != null && spellCast.getSpellCastState() == SpellCastState.NORMAL) { success = ((TargetedEntityFromLocationSpell)spell).castAtEntityFromLocation(player, from, target, spellCast.getPower()); spell.postCast(spellCast, success ? PostCastAction.HANDLE_NORMALLY : PostCastAction.ALREADY_HANDLED); } return success; } else if (mode == CastMode.PARTIAL) { SpellCastEvent event = new SpellCastEvent(spell, player, SpellCastState.NORMAL, power * subPower, null, 0, null, 0); Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled() && event.getSpellCastState() == SpellCastState.NORMAL) { if (player != null) { ret = ((TargetedEntityFromLocationSpell)spell).castAtEntityFromLocation(player, from, target, event.getPower()); } else { ret = ((TargetedEntityFromLocationSpell)spell).castAtEntityFromLocation(from, target, event.getPower()); } if (ret) { Bukkit.getPluginManager().callEvent(new SpellCastedEvent(spell, player, SpellCastState.NORMAL, event.getPower(), null, 0, null, PostCastAction.HANDLE_NORMALLY)); } } } else { if (player != null) { ret = ((TargetedEntityFromLocationSpell)spell).castAtEntityFromLocation(player, from, target, power * subPower); } else { ret = ((TargetedEntityFromLocationSpell)spell).castAtEntityFromLocation(from, target, power * subPower); } } } return ret; } public enum CastMode { HARD, FULL, PARTIAL, DIRECT } }