gt: 		if (attackWeapon != null) {
context: /***************************************************************************
   *                      (C) Copyright 2003 - Marauroa                      *
   ***************************************************************************
   ***************************************************************************
   *                                                                         *
   *   This program is free software; you can redistribute it and/or modify  *
   *   it under the terms of the GNU General Public License as published by  *
   *   the Free Software Foundation; either version 2 of the License, or     *
   *   (at your option) any later version.                                   *
   *                                                                         *
   ***************************************************************************/
  package games.stendhal.server.core.rp;
  
  import static games.stendhal.common.constants.Actions.MOVE_CONTINUOUS;
  
  import java.awt.Point;
  import java.awt.Rectangle;
  import java.awt.Shape;
  import java.util.ArrayList;
  import java.util.LinkedList;
  import java.util.List;
  
  import org.apache.log4j.Logger;
  
  import games.stendhal.common.Rand;
  import games.stendhal.common.constants.Testing;
  import games.stendhal.common.grammar.Grammar;
  import games.stendhal.server.core.engine.DataProvider;
  import games.stendhal.server.core.engine.GameEvent;
  import games.stendhal.server.core.engine.SingletonRepository;
  import games.stendhal.server.core.engine.StendhalRPZone;
  import games.stendhal.server.core.engine.db.StendhalKillLogDAO;
  import games.stendhal.server.core.events.TutorialNotifier;
  import games.stendhal.server.core.events.ZoneNotifier;
  import games.stendhal.server.core.pathfinder.Node;
  import games.stendhal.server.core.pathfinder.Path;
  import games.stendhal.server.core.rp.group.Group;
  import games.stendhal.server.core.rp.pvp.PlayerVsPlayerChallengeManager;
  import games.stendhal.server.entity.Entity;
  import games.stendhal.server.entity.RPEntity;
  import games.stendhal.server.entity.creature.DomesticAnimal;
  import games.stendhal.server.entity.creature.Pet;
  import games.stendhal.server.entity.creature.Sheep;
  import games.stendhal.server.entity.item.BreakableItem;
  import games.stendhal.server.entity.item.Item;
  import games.stendhal.server.entity.item.StackableItem;
  import games.stendhal.server.entity.npc.SpeakerNPC;
  import games.stendhal.server.entity.npc.TrainingDummy;
  import games.stendhal.server.entity.player.Player;
  import games.stendhal.server.events.AttackEvent;
  import marauroa.common.game.RPObject;
  import marauroa.common.net.message.TransferContent;
  import marauroa.server.game.db.DAORegister;
  import marauroa.server.game.rp.RPServerManager;
  
  /**
   * fighting and player teleport support
   */
  public class StendhalRPAction {
  	/** the logger instance. */
  	private static final Logger logger = Logger.getLogger(StendhalRPAction.class);
  
  	/**
  	 * The amount to weight ATK and DEF in player strength calculation. Higher
  	 * means more weight to stats vs level. Value 0.73 has been obtained from
  	 * a least square fit of players equally strong to an actual player killer.
  	 */
  	private static final double STRENGTH_STATS_MULTIPLIER = 0.73;
  	/**
  	 * Maximum strength ratio where it is still acceptable to attack another
  	 * player otherwise than in a self defense situation.
  	 */
  	private static final double ACCEPTABLE_STRENGTH_RATIO = 0.75;
  
  	/** server manager. */
  	private static RPServerManager rpman;
  
  	/**
  	 * initializes the StendhalRPAction
  	 *
  	 * @param rpMan RPServerManager
  	 */
  	public static void initialize(final RPServerManager rpMan) {
  		StendhalRPAction.rpman = rpMan;
  	}
  
  
  	/**
  	 * Do logic for starting an attack on an entity.
  	 *
  	 * @param player
  	 *            The player wanting to attack.
  	 * @param victim
  	 *            The target of attack.
  	 */
  	public static void startAttack(final Player player, final RPEntity victim) {
  
  		// Player's can't attack themselves
  		if (player.equals(victim)) {
  			return;
  		}
  
  		// if we are already attacking the target, do nothing
  		if (player.getAttackTarget() == victim) {
  			return;
  		}
  
  		// Disable attacking NPCS that are created as not attackable.
  		if (!victim.isAttackable()) {
  			if ((victim instanceof SpeakerNPC)) {
  				((SpeakerNPC) victim).onRejectedAttackStart(player);
  			}
  			logger.info("REJECTED. " + player.getName() + " is attacking " + victim.getName());
  			return;
  		}
  
  		// Enabled PVP
  		if ((victim instanceof Player) || (victim instanceof DomesticAnimal)) {
  			final StendhalRPZone zone = player.getZone();
  
  			// Make sure that you can't attack players or sheep (even wild
  			// sheep) who are inside a protection area. Also prevent attacking
  			// from such an area, in name of fairness
  			if (zone.isInProtectionArea(victim) || (zone.isInProtectionArea(player))) {
  				logger.info("REJECTED. " + victim.getName()
  						+ " is protected by zone");
  
  				final String name = getNiceVictimName(victim);
  
  				player.sendPrivateText("The powerful protective aura in this place prevents you from attacking "
  						+ name + ".");
  				return;
  			}
  
  			if (victim instanceof Player) {
  				// if challenges system property is set, use challenge manager instead.
  				if (System.getProperty("stendhal.pvpchallenge") != null) {
  					PlayerVsPlayerChallengeManager cm = SingletonRepository.getChallengeManager();
  					boolean activeChallenge = cm.playersHaveActiveChallenge(player, (Player) victim);
  					if(!activeChallenge) {
  						StringBuilder msgBuilder = new StringBuilder();
  						msgBuilder.append("You cannot attack ");
  						msgBuilder.append("unless ");
  						msgBuilder.append(victim.getName());
  						msgBuilder.append(" has accepted a challenge from you.");
  						player.sendPrivateText(msgBuilder.toString());
  						return;
  					}
  				}
  				// disable attacking much weaker players, except in/ self defense
  				if (!mayAttackPlayer(player, (Player) victim)) {
  					player.sendPrivateText("Your conscience would trouble you if you carried out this attack.");
  					return;
  				}
  			} else {
  				// Only allow owners, if there is one, to attack the pet
  				final Player owner = ((DomesticAnimal) victim).getOwner();
  				if ((owner != null) && (owner != player)) {
  					player.sendPrivateText("You pity " + getNiceVictimName(victim) + " too much to kill it.");
  
  					return;
  				}
  			}
  
  			logger.info(player.getName() + " is attacking " + victim.getName());
  		}
  
  		StendhalKillLogDAO killLog = DAORegister.get().get(StendhalKillLogDAO.class);
  		new GameEvent(player.getName(), "attack", victim.getName(), killLog.entityToType(player), killLog.entityToType(victim)).raise();
  
  		player.setTarget(victim);
  		player.faceToward(victim);
  		player.applyClientDirection(false);
  		player.notifyWorldAboutChanges();
  	}
  
  	/**
  	 * checks whether a player may attack another player
  	 *
  	 * @param attacker attacker
  	 * @param victim   victim
  	 * @return true, if the attack is acceptable
  	 */
  	private static boolean mayAttackPlayer(final Player attacker, final Player victim) {
  
  		// is the victim is of similar strength
  		if (victimIsStrongEnough(attacker, victim)) {
  			return true;
  		}
  
  		// allow self defence
  		RPEntity victimsTarget = victim.getAttackTarget();
  		if ((victimsTarget == null) || !(victimsTarget instanceof Player)) {
  			return false;
  		}
  		if (victimsTarget == attacker) {
  			return true;
  		}
  
  		// allow defence of group members
  		Group group = SingletonRepository.getGroupManager().getGroup(victimsTarget.getName());
  		if (group == null) {
  			return false;
  		}
  
  		return group.hasMember(attacker.getName());
  	}
  
  	/**
  	 * Check that the victim has high enough level compared to the attacker.
  	 *
  	 * @param player The player trying to attack
  	 * @param victim The entity being attacked
  	 * @return <code>true</code> if the victim is strong enough to allow
  	 *  the attack to happen, <code>false</code> otherwise.
  	 */
  	private static boolean victimIsStrongEnough(final Player player, final Player victim) {
  		return getPlayerStrength(victim) >= ACCEPTABLE_STRENGTH_RATIO * getPlayerStrength(player);
  	}
  
  	/**
  	 * Get the relative strength of a player, ignoring equipment.
  	 *
  	 * @param player
  	 * @return player strength
  	 */
  	private static double getPlayerStrength(final Player player) {
  		int combatSum;
  		combatSum = player.getAtk() + player.getDef();
  
  		return STRENGTH_STATS_MULTIPLIER * combatSum + player.getLevel();
  	}
  
  	/**
  	 * Get a nice target description string to be sent to the attacker in case
  	 * the attacking action is forbidden.
  	 *
  	 * @param victim The attacked entity
  	 * @return Description of the attacked pet or player
  	 */
  	private static String getNiceVictimName(final RPEntity victim) {
  		String name = victim.getTitle();
  
  		if (victim instanceof DomesticAnimal) {
  			final Player owner = ((DomesticAnimal) victim).getOwner();
  
  			if (owner != null) {
  				name = Grammar.suffix_s(owner.getTitle()) + " " + name;
  			} else {
  				if (victim instanceof Sheep) {
  					name = "that " + name;
  				} else {
  					name = "that poor little " + name;
  				}
  			}
  		}
  
  		return name;
  	}
  
  	/**
  	 * Lets the attacker try to attack the defender.
  	 * @param player
  	 *
  	 * @param defender
  	 *            The defending RPEntity.
  	 * @return true iff the attacker has done damage to the defender.
  	 *
  	 */
  	public static boolean playerAttack(final Player player, final RPEntity defender) {
  		boolean result = false;
  
  		final StendhalRPZone zone = player.getZone();
  		if (!zone.has(defender.getID()) || (defender.getHP() == 0)) {
  			logger.debug("Attack from " + player + " to " + defender
  					+ " stopped because target was lost("
  					+ zone.has(defender.getID()) + ") or dead.");
  			player.stopAttack();
  
  			return false;
  		}
  
  		final boolean usesTrainingDummy = defender instanceof TrainingDummy;
  
  		defender.rememberAttacker(player);
  		if (defender instanceof Player) {
  			player.storeLastPVPActionTime();
  
  			// did the player or victim move into a protected area?
  			if(zone.isInProtectionArea(defender) || zone.isInProtectionArea(player)) {
  				logger.debug("Attack from " + player + " to " + defender
  						+ " stopped because " + player + " or " + defender + " moved into protected area.");
  				player.stopAttack();
  				return false;
  			}
  		}
  
  		boolean isRanged = false;
  		if (!player.nextTo(defender)) {
  			// The attacker is not directly standing next to the defender.
  			// Find out if he can attack from the distance.
  			if (player.canDoRangeAttack(defender, player.getMaxRangeForArcher())) {
  
  				// Check line of view to see if there is any obstacle.
  				if (!player.hasLineOfSight(defender)) {
  					return false;
  				}
  
  				isRanged = true;
  			} else {
  				logger.debug("Attack from " + player + " to " + defender
  						+ " failed because target is not near.");
  				return false;
  			}
  		}
  
  		// Weapon for the purpose of attack image
  		Item attackWeapon = player.getWeapon();
  		String weaponClass = null;
  