use of com.elmakers.mine.bukkit.utility.Targeting in project MagicPlugin by elBukkit.
the class CustomProjectileAction method initialize.
@Override
public void initialize(Spell spell, ConfigurationSection parameters) {
super.initialize(spell, parameters);
targeting = new Targeting();
}
use of com.elmakers.mine.bukkit.utility.Targeting in project MagicPlugin by elBukkit.
the class CustomProjectileAction method step.
@Override
public SpellResult step(CastContext context) {
long now = System.currentTimeMillis();
if (now < nextUpdate) {
return SpellResult.PENDING;
}
if (attachedDeadline > 0) {
Entity targetEntity = actionContext.getTargetEntity();
if (attachedOffset != null && targetEntity != null) {
Location targetLocation = targetEntity.getLocation();
targetLocation.add(attachedOffset);
actionContext.setTargetLocation(targetLocation);
if (effectLocation != null) {
effectLocation.updateFrom(targetLocation);
}
}
if (now > attachedDeadline) {
return finishAttach();
}
return SpellResult.PENDING;
}
if (now > deadline) {
return miss();
}
if (targetSelfDeadline > 0 && now > targetSelfDeadline && actionContext != null) {
targetSelfDeadline = 0;
actionContext.setTargetsCaster(true);
}
nextUpdate = now + interval;
// Check for initialization required
// TODO: Move this to start()?
Location projectileLocation = null;
if (velocity == null) {
projectileLocation = sourceLocation.getLocation(context).clone();
/* This feels confusing however...
* Looking straight down in Minecraft gives a pitch of 90
* While looking straight up is a pitch of -90
* We don't want to normalize these values as other functions need the non-normalize numbers.
* So if the projectile pitch value is found to be higher or lower than the min or max, it's set to the min or max respectively
*/
if (pitchMin < projectileLocation.getPitch()) {
projectileLocation.setPitch(pitchMin);
} else if (pitchMax > projectileLocation.getPitch()) {
projectileLocation.setPitch(pitchMax);
}
launchLocation = projectileLocation.clone();
velocity = projectileLocation.getDirection().clone().normalize();
if (spread > 0) {
Random random = context.getRandom();
velocity.setX(velocity.getX() + (random.nextDouble() * spread - spread / 2));
velocity.setY(velocity.getY() + (random.nextDouble() * spread - spread / 2));
velocity.setZ(velocity.getZ() + (random.nextDouble() * spread - spread / 2));
velocity.normalize();
}
if (startDistance != 0) {
projectileLocation.add(velocity.clone().multiply(startDistance));
}
if (reverseDirection) {
velocity = velocity.multiply(-1);
}
projectileLocation.setDirection(velocity);
actionContext.setTargetLocation(projectileLocation);
actionContext.setTargetEntity(null);
actionContext.setDirection(velocity);
// Start up projectile FX
startProjectileEffects(context, projectileEffectKey);
context.getMage().sendDebugMessage(ChatColor.BLUE + "Projectile launched from " + ChatColor.GRAY + projectileLocation.toVector() + ChatColor.BLUE, 7);
} else {
projectileLocation = actionContext.getTargetLocation();
if (effectLocation != null) {
effectLocation.updateFrom(projectileLocation);
effectLocation.setDirection(velocity);
}
}
// Check plan
if (plan != null && !plan.isEmpty()) {
PlanStep next = plan.peek();
if ((next.distance > 0 && distanceTravelled > next.distance) || (next.time > 0 && flightTime > next.time) || (next.returnBuffer > 0 && returnDistanceAway != null && returnDistanceAway < next.returnBuffer)) {
plan.remove();
if (next.parameters != null) {
modifyParameters(next.parameters);
}
if (next.effectsKey != null) {
startProjectileEffects(context, next.effectsKey);
}
context.getMage().sendDebugMessage("Changing flight plan at distance " + ((int) distanceTravelled) + " and time " + flightTime, 4);
if (resetTimeOnPathChange) {
flightTime = 0;
}
}
}
if (updateLaunchLocation) {
launchLocation = context.getCastLocation().clone();
}
// Advance position
// We default to 50 ms travel time (one tick) for the first iteration.
long delta = lastUpdate > 0 ? now - lastUpdate : 50;
lastUpdate = now;
flightTime += delta;
// Apply gravity, drag or other velocity modifiers
Vector targetVelocity = null;
if (trackEntity) {
Entity targetEntity = context.getTargetEntity();
if (targetEntity != null && targetEntity.isValid() && context.canTarget(targetEntity)) {
Location targetLocation = targetEntity instanceof LivingEntity ? ((LivingEntity) targetEntity).getEyeLocation() : targetEntity.getLocation();
targetVelocity = targetLocation.toVector().subtract(projectileLocation.toVector()).normalize();
}
} else if (trackCursorRange > 0) {
/* We need to first find out where the player is looking and multiply it by how far the player wants the whip to extend
* Finally after all that, we adjust the velocity of the projectile to go towards the cursor point
*/
Vector playerCursor = context.getMage().getDirection().clone().normalize();
Vector targetPoint = playerCursor.multiply(trackCursorRange);
Vector worldPoint = targetPoint.add(context.getMage().getEyeLocation().clone().toVector());
Vector projectileOffset = worldPoint.subtract(projectileLocation.clone().toVector());
targetVelocity = projectileOffset.normalize();
} else if (reorient) {
targetVelocity = context.getMage().getDirection().clone().normalize();
} else {
if (gravity > 0) {
// Reduce / change speed based on gravity
velocity.normalize().multiply(speed);
velocity.setY(velocity.getY() - gravity * delta / 50);
speed = velocity.length();
velocity.normalize();
}
if (drag > 0) {
speed -= drag * delta / 50;
if (speed <= 0) {
return miss();
}
}
}
if (targetVelocity != null) {
if (trackSpeed > 0) {
double steerDistanceSquared = trackSpeed * trackSpeed;
double distanceSquared = targetVelocity.distanceSquared(velocity);
if (distanceSquared <= steerDistanceSquared) {
velocity = targetVelocity;
} else {
Vector targetDirection = targetVelocity.subtract(velocity).normalize().multiply(steerDistanceSquared);
velocity.add(targetDirection);
}
} else {
velocity = targetVelocity;
}
launchLocation.setDirection(velocity);
}
if (velocityTransform != null) {
targetVelocity = velocityTransform.get(launchLocation, (double) flightTime / 1000);
// with targeting and range-checking
if (targetVelocity != null) {
speed = targetVelocity.length();
if (speed > 0) {
targetVelocity.normalize();
} else {
targetVelocity.setX(1);
}
velocity = targetVelocity;
}
}
if (returnToCaster) {
Vector targetLocation = context.getMage().getEyeLocation().toVector();
if (returnOffset != null) {
targetLocation.add(returnOffset);
}
if (returnRelativeOffset != null) {
Vector relativeOffset = VectorUtils.rotateVector(returnRelativeOffset, context.getMage().getEyeLocation());
targetLocation.add(relativeOffset);
}
Vector projectileOffset = targetLocation.clone().subtract(projectileLocation.toVector());
returnDistanceAway = projectileOffset.length();
velocity = projectileOffset.normalize();
}
if (projectileFollowPlayer) {
Vector currentLocation = context.getMage().getLocation().toVector();
if (previousLocation != null) {
Vector offset = currentLocation.clone().subtract(previousLocation);
previousLocation = currentLocation;
velocity = velocity.add(offset);
} else {
previousLocation = currentLocation;
}
}
projectileLocation.setDirection(velocity);
// Advance targeting to find Entity or Block
distanceTravelledThisTick = speed * delta / 1000;
if (range > 0) {
distanceTravelledThisTick = Math.min(distanceTravelledThisTick, range - distanceTravelled);
}
context.addWork((int) Math.ceil(distanceTravelledThisTick));
Location targetLocation;
Targeting.TargetingResult targetingResult = Targeting.TargetingResult.MISS;
Target target = null;
if (!ignoreTargeting) {
targeting.start(projectileLocation);
target = targeting.target(actionContext, distanceTravelledThisTick);
targetingResult = targeting.getResult();
targetLocation = target.getLocation();
boolean keepGoing = distanceTravelled < minRange;
Location tempLocation = projectileLocation.clone();
int checkIterations = 0;
while (keepGoing) {
// TODO if all of these distance() calls are necessary, they should be optimized to distanceSquared()
if (targetingResult == Targeting.TargetingResult.MISS) {
keepGoing = false;
} else if (targetingResult != null && targetLocation.distance(projectileLocation) + distanceTravelled >= minRange) {
keepGoing = false;
} else if (targetLocation.distance(projectileLocation) + distanceTravelled >= minEntityRange && targetingResult == Targeting.TargetingResult.ENTITY) {
keepGoing = false;
} else if (targetLocation.distance(projectileLocation) + distanceTravelled >= minBlockRange && targetingResult == Targeting.TargetingResult.BLOCK) {
keepGoing = false;
} else if (targetLocation.distance(projectileLocation) >= distanceTravelledThisTick) {
keepGoing = false;
} else if (checkIterations > 1000) {
keepGoing = false;
} else {
if (tempLocation.distance(projectileLocation) < targetLocation.distance(projectileLocation)) {
tempLocation.add(velocity.clone().multiply(targetLocation.distance(projectileLocation) + 0.1));
} else {
tempLocation.add(velocity.clone().multiply(0.2));
}
actionContext.setTargetLocation(tempLocation);
actionContext.setTargetEntity(null);
actionContext.setDirection(velocity);
// TODO: This whole procedure, particularly retargeting, is going to be very costly
// This is hopefully an easier way
targeting.start(tempLocation);
target = targeting.target(actionContext, distanceTravelledThisTick - tempLocation.distance(projectileLocation));
targetingResult = targeting.getResult();
targetLocation = target.getLocation();
checkIterations++;
}
}
}
if (targetingResult == Targeting.TargetingResult.MISS) {
if (hasBlockMissEffects && target != null) {
actionContext.setTargetLocation(target.getLocation());
actionContext.playEffects("blockmiss");
}
targetLocation = projectileLocation.clone().add(velocity.clone().multiply(distanceTravelledThisTick));
context.getMage().sendDebugMessage(ChatColor.DARK_BLUE + "Projectile miss: " + ChatColor.DARK_PURPLE + " at " + targetLocation.getBlock().getType() + " : " + targetLocation.toVector() + " from range of " + distanceTravelledThisTick + " over time " + delta, 14);
} else {
if (hasPreHitEffects) {
actionContext.playEffects("prehit");
}
targetLocation = target.getLocation();
// Debugging
if (targetLocation == null) {
targetLocation = projectileLocation;
context.getLogger().warning("Targeting hit, with no target location: " + targetingResult + " with " + targeting.getTargetType() + " from " + context.getSpell().getName());
}
context.getMage().sendDebugMessage(ChatColor.BLUE + "Projectile hit: " + ChatColor.LIGHT_PURPLE + targetingResult.name().toLowerCase() + ChatColor.BLUE + " at " + ChatColor.GOLD + targetLocation.getBlock().getType() + ChatColor.BLUE + " from " + ChatColor.GRAY + projectileLocation.getBlock() + ChatColor.BLUE + " to " + ChatColor.GRAY + targetLocation.toVector() + ChatColor.BLUE + " from range of " + ChatColor.GOLD + distanceTravelledThisTick + ChatColor.BLUE + " over time " + ChatColor.DARK_PURPLE + delta, 8);
distanceTravelledThisTick = targetLocation.distance(projectileLocation);
}
distanceTravelled += distanceTravelledThisTick;
effectDistanceTravelled += distanceTravelledThisTick;
// Max Height check
int y = targetLocation.getBlockY();
boolean maxHeight = y >= targetLocation.getWorld().getMaxHeight();
boolean minHeight = y <= 0;
if (maxHeight) {
targetLocation.setY(targetLocation.getWorld().getMaxHeight());
} else if (minHeight) {
targetLocation.setY(0);
}
if (hasTickEffects && effectDistanceTravelled > tickSize) {
// Sane limit here
Vector speedVector = velocity.clone().multiply(tickSize);
for (int i = 0; i < 256; i++) {
actionContext.setTargetLocation(projectileLocation);
actionContext.playEffects(tickEffectKey);
projectileLocation.add(speedVector);
effectDistanceTravelled -= tickSize;
if (effectDistanceTravelled < tickSize)
break;
}
}
actionContext.setTargetLocation(targetLocation);
if (target != null) {
actionContext.setTargetEntity(target.getEntity());
}
if (hasStepEffects) {
actionContext.playEffects("step");
}
if (maxHeight || minHeight) {
return miss();
}
if (range > 0 && distanceTravelled >= range) {
return miss();
}
Block block = targetLocation.getBlock();
if (!block.getChunk().isLoaded()) {
return miss();
}
if (distanceTravelled < minRange && targetingResult != null) {
// TODO : Should this be < ?
if (distanceTravelled >= minBlockRange && targetingResult == Targeting.TargetingResult.BLOCK) {
return miss();
}
if (distanceTravelled >= minEntityRange && targetingResult == Targeting.TargetingResult.ENTITY) {
return miss();
}
} else if (targetingResult == Targeting.TargetingResult.BLOCK) {
return hitBlock(block);
} else if (targetingResult == Targeting.TargetingResult.ENTITY) {
return hitEntity(target);
}
if (hasTickActions) {
return startActions("tick");
}
return SpellResult.PENDING;
}
use of com.elmakers.mine.bukkit.utility.Targeting in project MagicPlugin by elBukkit.
the class ConeOfEffectAction method initialize.
@Override
public void initialize(Spell spell, ConfigurationSection baseParameters) {
super.initialize(spell, baseParameters);
targeting = new Targeting();
}
Aggregations