/* * Copyright 2015 Demigods RPG * Copyright 2015 Alexander Chauncey * Copyright 2015 Alex Bennett * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.demigodsrpg.util; import com.demigodsrpg.DGData; import com.demigodsrpg.Setting; import com.demigodsrpg.model.PlayerModel; import com.google.common.collect.Lists; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.util.BlockIterator; import java.util.List; import java.util.Random; import java.util.Set; import java.util.stream.Collectors; public class TargetingUtil { private static final int TARGET_OFFSET = 5; @Deprecated public static LivingEntity autoTarget(Player player) { return autoTarget(player, Setting.MAX_TARGET_RANGE); } /** * Returns the LivingEntity that <code>player</code> is target. * * @param player the player * @return the targeted LivingEntity */ public static LivingEntity autoTarget(Player player, int range) { // Define variables final int correction = 3; Location target = null; try { target = player.getTargetBlock((Set<Material>) null, range).getLocation(); } catch (Exception ignored) { } if (target == null) return null; BlockIterator iterator = new BlockIterator(player, range); List<Entity> targets = Lists.newArrayList(); final PlayerModel looking = DGData.PLAYER_R.fromPlayer(player); // Iterate through the blocks and find the target while (iterator.hasNext()) { final Block block = iterator.next(); targets.addAll(player.getWorld().getEntitiesByClass(LivingEntity.class).stream().filter(entity -> { Location location = entity.getLocation(); if (location.distance(player.getLocation()) < range) { if (entity.getLocation().distance(block.getLocation()) <= correction) { if (entity instanceof Player) { PlayerModel target1 = DGData.PLAYER_R.fromPlayer((Player) entity); if (!Setting.FRIENDLY_FIRE && looking.getFamily().equals(target1.getFamily()) || ((Player) entity).getGameMode().equals(GameMode.CREATIVE)) return false; } return true; } } return false; }).collect(Collectors.toList())); } // Attempt to return the closest entity to the cursor for (Entity entity : targets) { if (entity.getLocation().distance(target) <= correction) { return (LivingEntity) entity; } } // If it failed to do that then just return the first entity try { return (LivingEntity) targets.get(0); } catch (Exception ignored) { } return null; } public static Location directTarget(Player player) { return player.getTargetBlock((Set<Material>) null, 140).getLocation(); } /** * Returns true if the <code>player</code> ability hits <code>target</code>. * * @param player the player using the ability * @param target the targeted LivingEntity * @return true/false depending on if the ability hits or misses */ public static boolean target(Player player, Location target, boolean notify) { PlayerModel model = DGData.PLAYER_R.fromPlayer(player); Location toHit = adjustedAimLocation(model, target); if (isHit(target, toHit)) return true; if (notify) player.sendMessage(ChatColor.RED + "Missed..."); // TODO Better message. return false; } /** * Returns the location that <code>character</code> is actually aiming * at when target <code>target</code>. * * @param player the character triggering the ability callAbilityEvent * @param target the location the character is target at * @return the aimed at location */ public static Location adjustedAimLocation(PlayerModel player, Location target) { // FIXME: This needs major work. int accuracy = 15; int offset = (int) (TARGET_OFFSET + player.getOfflinePlayer().getPlayer().getLocation().distance(target)); int adjustedOffset = offset / accuracy; if (adjustedOffset < 1) adjustedOffset = 1; Random random = new Random(); World world = target.getWorld(); int randomInt = random.nextInt(adjustedOffset); int sampleSpace = random.nextInt(3); double X = target.getX(); double Z = target.getZ(); double Y = target.getY(); if (sampleSpace == 0) { X += randomInt; Z += randomInt; } else if (sampleSpace == 1) { X -= randomInt; Z -= randomInt; } else if (sampleSpace == 2) { X -= randomInt; Z += randomInt; } else if (sampleSpace == 3) { X += randomInt; Z -= randomInt; } return new Location(world, X, Y, Z); } /** * Returns true if <code>target</code> is hit at <code>hit</code>. * * @param target the LivingEntity being targeted * @param hit the location actually hit * @return true/false if <code>target</code> is hit */ public static boolean isHit(Location target, Location hit) { return hit.distance(target) <= 2; } }