Search in sources :

Example 1 with Targeting

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();
}
Also used : Targeting(com.elmakers.mine.bukkit.utility.Targeting)

Example 2 with 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;
}
Also used : Entity(org.bukkit.entity.Entity) LivingEntity(org.bukkit.entity.LivingEntity) Targeting(com.elmakers.mine.bukkit.utility.Targeting) LivingEntity(org.bukkit.entity.LivingEntity) Target(com.elmakers.mine.bukkit.utility.Target) Random(java.util.Random) Block(org.bukkit.block.Block) Vector(org.bukkit.util.Vector) Location(org.bukkit.Location) SourceLocation(com.elmakers.mine.bukkit.magic.SourceLocation) DynamicLocation(de.slikey.effectlib.util.DynamicLocation)

Example 3 with Targeting

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();
}
Also used : Targeting(com.elmakers.mine.bukkit.utility.Targeting)

Aggregations

Targeting (com.elmakers.mine.bukkit.utility.Targeting)3 SourceLocation (com.elmakers.mine.bukkit.magic.SourceLocation)1 Target (com.elmakers.mine.bukkit.utility.Target)1 DynamicLocation (de.slikey.effectlib.util.DynamicLocation)1 Random (java.util.Random)1 Location (org.bukkit.Location)1 Block (org.bukkit.block.Block)1 Entity (org.bukkit.entity.Entity)1 LivingEntity (org.bukkit.entity.LivingEntity)1 Vector (org.bukkit.util.Vector)1