Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,14 @@ private void dodge(LivingEntity caster, ParticleProjectileTracker tracker, Spell
Vector v = RandomUtils.getRandomCircleVector().multiply(distance);
targetLoc.add(v);
targetLoc.setDirection(caster.getLocation().getDirection());
targetLoc = BlockUtils.adjustToSafeLocation(caster, targetLoc);

if (spellBeforeDodge != null) {
SpellData castData = subData.builder().caster(caster).target(null).location(casterLoc).recipient(null).build();
spellBeforeDodge.subcast(castData);
}

if (!targetLoc.getBlock().isPassable() || !targetLoc.getBlock().getRelative(BlockFace.UP).isPassable()) return;
if (targetLoc == null) return;
caster.teleportAsync(targetLoc);
addUseAndChargeCost(caster);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.bukkit.World;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Vehicle;

import com.nisovin.magicspells.util.*;
Expand Down Expand Up @@ -84,8 +83,8 @@ public CastResult cast(SpellData data) {
}
MagicSpells.debug(3, "Gate location: " + location);

Block b = location.getBlock();
if (!b.isPassable() || !b.getRelative(0, 1, 0).isPassable()) {
location = BlockUtils.adjustToSafeLocation(data.caster(), location);
if (location == null) {
MagicSpells.error("GateSpell '" + internalName + "' has landing spot blocked!");
sendMessage(strGateFailed, data.caster(), data);
return new CastResult(PostCastAction.ALREADY_HANDLED, data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import java.util.List;
import java.util.ArrayList;
import java.util.function.Predicate;

import org.bukkit.Material;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.util.BoundingBox;
import org.bukkit.FluidCollisionMode;
import org.bukkit.util.BlockIterator;

import com.nisovin.magicspells.util.*;
Expand All @@ -15,34 +18,45 @@

public class PhaseSpell extends InstantSpell {

private final List<Material> phasableBlocks;
private final List<Material> nonPhasableBlocks;

private final ConfigData<Integer> maxDistance;
private final ConfigData<Integer> requireGroundDistance;

private final ConfigData<Boolean> airOnlyExit;
private final ConfigData<Boolean> snapToGround;
private final ConfigData<Boolean> ignoreTransparentBlocks;
private final ConfigData<Boolean> powerAffectsMaxDistance;
private String strCantPhase;

private final String strCantPhase;

private final List<Material> enterBlocks = new ArrayList<>();
private final List<Material> nonExitBlocks = new ArrayList<>();
private final List<Material> phasableBlocks = new ArrayList<>();
private final List<Material> nonPhasableBlocks = new ArrayList<>();

public PhaseSpell(MagicConfig config, String spellName) {
super(config, spellName);

maxDistance = getConfigDataInt("max-distance", 15);
strCantPhase = getConfigString("str-cant-phase", "Unable to find place to phase to.");
requireGroundDistance = getConfigDataInt("require-ground-distance", 0);

airOnlyExit = getConfigDataBoolean("air-only-exit", true);
snapToGround = getConfigDataBoolean("snap-to-ground", false);
ignoreTransparentBlocks = getConfigDataBoolean("ignore-transparent-blocks", false);
powerAffectsMaxDistance = getConfigDataBoolean("power-affects-max-distance", true);

phasableBlocks = new ArrayList<>();
nonPhasableBlocks = new ArrayList<>();
strCantPhase = getConfigString("str-cant-phase", "Unable to find place to phase to.");

processMaterials(enterBlocks, "enter-blocks");
processMaterials(nonExitBlocks, "non-exit-blocks");
processMaterials(phasableBlocks, "phasable-blocks");
processMaterials(nonPhasableBlocks, "non-phasable-blocks");
}

private void processMaterials(List<Material> materials, String path) {
List<String> matList = getConfigStringList(path, null);
if (matList == null || matList.isEmpty()) return;
for (String mat : matList) {
for (String mat : getConfigStringList(path, List.of())) {
Material material = Util.getMaterial(mat);
if (material == null) {
MagicSpells.error("PhaseSpell has an invalid material specified on '" + path + "': " + mat);
MagicSpells.error("PhaseSpell '" + internalName + "' has an invalid material specified on '" + path + "': " + mat);
continue;
}
materials.add(material);
Expand All @@ -51,51 +65,68 @@ private void processMaterials(List<Material> materials, String path) {

@Override
public CastResult cast(SpellData data) {
int r = getRange(data);
int range = getRange(data);
int rangeSquared = range * range;
Location casterLoc = data.caster().getLocation();

int distance = maxDistance.get(data);
if (powerAffectsMaxDistance.get(data)) distance = Math.round(distance * data.power());
int distanceSquared = distance * distance;

BlockIterator iter;
try {
iter = new BlockIterator(data.caster(), distance << 1);
iter = new BlockIterator(data.caster(), distance);
} catch (IllegalStateException e) {
sendMessage(strCantPhase, data.caster(), data);
sendMessage(strCantPhase, data);
return new CastResult(PostCastAction.ALREADY_HANDLED, data);
}

int i = 0;
Block start = null;
Location location = null, casterLoc = data.caster().getLocation();
Predicate<Location> transparent = ignoreTransparentBlocks.get(data) ? isTransparent(data) : l -> l.getBlock().isEmpty();

while (i++ < r << 1 && iter.hasNext()) {
while (iter.hasNext()) {
Block b = iter.next();
if (b.getType().isAir()) continue;
if (casterLoc.distanceSquared(b.getLocation()) >= r * r) continue;
start = b;
break;
Location loc = b.getLocation();

if (enterBlocks.contains(b.getType())) break;
if (transparent.test(loc)) continue;

if (casterLoc.distanceSquared(loc) < rangeSquared && canPassThrough(b)) break;

sendMessage(strCantPhase, data);
return new CastResult(PostCastAction.ALREADY_HANDLED, data);
}

if (start != null) {
if (canPassThrough(start)) {
while (i++ < distance << 1 && iter.hasNext()) {
Block block = iter.next();
if (block.getType().isAir() && block.getRelative(0, 1, 0).getType().isAir() && casterLoc.distanceSquared(block.getLocation()) < distance * distance) {
location = block.getLocation();
break;
}
if (!canPassThrough(block)) break;
}
Location location = null;
boolean airOnlyExit = this.airOnlyExit.get(data);
boolean snapToGround = this.snapToGround.get(data);
int requireGroundDistance = this.requireGroundDistance.get(data);

while (iter.hasNext()) {
Block block = iter.next();
Location loc = block.getLocation().add(0.5, 0, 0.5);

if (casterLoc.distanceSquared(loc) >= distanceSquared) break;

Location adjusted = BlockUtils.adjustToSafeLocation(data.caster(), loc, requireGroundDistance, snapToGround);
if (adjusted == null) continue;

BoundingBox box = data.caster().getBoundingBox();
box.shift(adjusted.clone().subtract(casterLoc));
if (!Util.hasCollisionsIn(data.caster().getWorld(), box, false, FluidCollisionMode.NEVER,
b -> (airOnlyExit && !b.isEmpty()) || nonExitBlocks.contains(b.getType())
)) {
location = adjusted;
break;
}

if (!canPassThrough(adjusted.getBlock())) break;
}

if (location == null) {
sendMessage(strCantPhase, data.caster(), data);
sendMessage(strCantPhase, data);
return new CastResult(PostCastAction.ALREADY_HANDLED, data);
}

location.setX(location.getX() + 0.5);
location.setZ(location.getZ() + 0.5);
location.setPitch(casterLoc.getPitch());
location.setYaw(casterLoc.getYaw());
data = data.location(location);
Expand All @@ -107,25 +138,8 @@ public CastResult cast(SpellData data) {
}

private boolean canPassThrough(Block block) {
// Check only blacklist.
if (phasableBlocks.isEmpty()) return !nonPhasableBlocks.contains(block.getType());
return phasableBlocks.contains(block.getType()) && !nonPhasableBlocks.contains(block.getType());
}

public List<Material> getPhasableBlocks() {
return phasableBlocks;
}

public List<Material> getNonPhasableBlocks() {
return nonPhasableBlocks;
}

public String getStrCantPhase() {
return strCantPhase;
}

public void setStrCantPhase(String strCantPhase) {
this.strCantPhase = strCantPhase;
Material type = block.getType();
return !nonPhasableBlocks.contains(type) && (phasableBlocks.isEmpty() || phasableBlocks.contains(type));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.util.RayTraceResult;

import com.nisovin.magicspells.util.*;
Expand All @@ -12,15 +13,21 @@

public class BlinkSpell extends TargetedSpell implements TargetedLocationSpell {

private final ConfigData<Boolean> passThroughCeiling;

private final String strCantBlink;

private final ConfigData<Integer> requireGroundDistance;

private final ConfigData<Boolean> snapToGround;
private final ConfigData<Boolean> passThroughCeiling;

public BlinkSpell(MagicConfig config, String spellName) {
super(config, spellName);

strCantBlink = getConfigString("str-cant-blink", "You can't blink there.");

requireGroundDistance = getConfigDataInt("require-ground-distance", 0);

snapToGround = getConfigDataBoolean("snap-to-ground", false);
passThroughCeiling = getConfigDataBoolean("pass-through-ceiling", false);
}

Expand All @@ -30,21 +37,25 @@ public CastResult cast(SpellData data) {
if (result == null) return noTarget(strCantBlink, data);

Block found = result.getHitBlock();
Block prev = found.getRelative(result.getHitBlockFace());
BlockFace face = result.getHitBlockFace();
Block prev = found.getRelative(face);

Location loc = null;
if (!passThroughCeiling.get(data) && found.getRelative(0, -1, 0).equals(prev) && prev.isPassable()) {
Block under = prev.getRelative(0, -1, 0);
if (under.isPassable()) loc = under.getLocation().add(0.5, 0, 0.5);
} else if (found.getRelative(0, 1, 0).isPassable() && found.getRelative(0, 2, 0).isPassable()) {
loc = found.getLocation().add(0.5, 1, 0.5);
} else if (prev.isPassable() && prev.getRelative(0, 1, 0).isPassable()) {
loc = prev.getLocation().add(0.5, 0, 0.5);

boolean snapToGround = this.snapToGround.get(data);
int requireGroundDistance = this.requireGroundDistance.get(data);

// Under
if (face == BlockFace.DOWN && !passThroughCeiling.get(data)) {
Location target = prev.getLocation().add(0.5, -1, 0.5);
loc = BlockUtils.adjustToSafeLocation(data.caster(), target, requireGroundDistance, snapToGround);
}
if (loc == null) return noTarget(strCantBlink, data);
// Above
if (loc == null) loc = BlockUtils.adjustToSafeLocation(data.caster(), found.getLocation().add(0.5, 0, 0.5));
// Side
if (loc == null) loc = BlockUtils.adjustToSafeLocation(data.caster(), prev.getLocation().add(0.5, 0, 0.5), requireGroundDistance, snapToGround);

loc.setPitch(data.caster().getPitch());
loc.setYaw(data.caster().getYaw());
if (loc == null) return noTarget(strCantBlink, data);

SpellTargetLocationEvent targetEvent = new SpellTargetLocationEvent(this, data, loc);
if (!targetEvent.callEvent()) return noTarget(strCantBlink, targetEvent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.bukkit.Material;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.util.BoundingBox;
import org.bukkit.event.EventHandler;
import org.bukkit.entity.LivingEntity;
import org.bukkit.block.data.BlockData;
Expand All @@ -29,6 +30,8 @@ public class EntombSpell extends TargetedSpell implements TargetedEntitySpell {
private final ConfigData<Integer> duration;

private final boolean allowBreaking;

private final ConfigData<Boolean> centerTarget;
private final ConfigData<Boolean> closeTopAndBottom;
private final ConfigData<Boolean> powerAffectsDuration;

Expand All @@ -42,6 +45,8 @@ public EntombSpell(MagicConfig config, String spellName) {
duration = getConfigDataInt("duration", 20);

allowBreaking = getConfigBoolean("allow-breaking", true);

centerTarget = getConfigDataBoolean("center-target", true);
closeTopAndBottom = getConfigDataBoolean("close-top-and-bottom", true);
powerAffectsDuration = getConfigDataBoolean("power-affects-duration", true);

Expand Down Expand Up @@ -73,27 +78,44 @@ public CastResult castAtEntity(SpellData data) {
List<Block> tombBlocks = new ArrayList<>();

LivingEntity target = data.target();
Block feet = target.getLocation().getBlock();
float pitch = target.getLocation().getPitch();
float yaw = target.getLocation().getYaw();

Location tpLoc = feet.getLocation().add(0.5, 0, 0.5);
tpLoc.setYaw(yaw);
tpLoc.setPitch(pitch);
target.teleportAsync(tpLoc);

tempBlocks.add(feet.getRelative(1, 0, 0));
tempBlocks.add(feet.getRelative(1, 1, 0));
tempBlocks.add(feet.getRelative(-1, 0, 0));
tempBlocks.add(feet.getRelative(-1, 1, 0));
tempBlocks.add(feet.getRelative(0, 0, 1));
tempBlocks.add(feet.getRelative(0, 1, 1));
tempBlocks.add(feet.getRelative(0, 0, -1));
tempBlocks.add(feet.getRelative(0, 1, -1));

if (closeTopAndBottom.get(data)) {
tempBlocks.add(feet.getRelative(0, -1, 0));
tempBlocks.add(feet.getRelative(0, 2, 0));

if (centerTarget.get(data)) {
Location location = target.getLocation();
location.setX(location.getBlockX() + 0.5);
location.setZ(location.getBlockZ() + 0.5);
target.teleport(location);
}

BoundingBox box = target.getBoundingBox();
BoundingBox exp = box.clone().expand(1 - 1e-7);

int minX = (int) Math.floor(exp.getMinX());
int minY = (int) Math.floor(exp.getMinY());
int minZ = (int) Math.floor(exp.getMinZ());

int maxX = (int) Math.ceil(exp.getMaxX());
int maxY = (int) Math.ceil(exp.getMaxY());
int maxZ = (int) Math.ceil(exp.getMaxZ());

boolean closeTopAndBottom = this.closeTopAndBottom.get(data);
for (int x = minX; x < maxX; x++) {
for (int y = minY; y < maxY; y++) {
for (int z = minZ; z < maxZ; z++) {
Block block = target.getWorld().getBlockAt(x, y, z);
if (box.overlaps(BoundingBox.of(block))) continue;

int boundary = 0;
if (x == minX || x == maxX - 1) boundary++;
if (y == minY || y == maxY - 1) {
if (!closeTopAndBottom) continue;
boundary++;
}
if (z == minZ || z == maxZ - 1) boundary++;
if (boundary > 1) continue;

tempBlocks.add(block);
}
}
}

BlockData blockType = this.blockType.get(data);
Expand Down
Loading
Loading