Package games.stendhal.server.actions.equip

Source Code of games.stendhal.server.actions.equip.SourceObject$InvalidSource

/* $Id: SourceObject.java,v 1.67 2011/04/18 05:42:55 nhnb Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   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.actions.equip;

import games.stendhal.common.EquipActionConsts;
import games.stendhal.common.MathHelper;
import games.stendhal.server.core.engine.ItemLogger;
import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.core.events.EquipListener;
import games.stendhal.server.entity.Entity;
import games.stendhal.server.entity.item.Corpse;
import games.stendhal.server.entity.item.Item;
import games.stendhal.server.entity.item.Stackable;
import games.stendhal.server.entity.item.StackableItem;
import games.stendhal.server.entity.player.Player;
import games.stendhal.server.entity.slot.EntitySlot;

import java.util.Iterator;
import java.util.List;

import marauroa.common.game.RPAction;
import marauroa.common.game.RPObject;
import marauroa.common.game.RPSlot;

import org.apache.log4j.Logger;

/**
* this encapsulates the equip/drop source.
*/
class SourceObject extends MoveableObject {
  private static InvalidSource invalidSource = new InvalidSource();
  private static Logger logger = Logger.getLogger(SourceObject.class);
  /** the item . */
  private Item item;

  private int quantity;

  private boolean isLootingRewardable = false;

  public static SourceObject createSourceObject(final RPAction action, final Player player) {

    if ((action == null) || (player == null)) {
      return invalidSource;
    }
    // source item must be there
    if (!action.has(EquipActionConsts.SOURCE_PATH) && !action.has(EquipActionConsts.BASE_ITEM)) {
      logger.warn("action does not have a base item. action: " + action);

      return invalidSource;
    }

    if (player.getZone() == null) {
      return invalidSource;
    }

    SourceObject source;
    /* TODO: disabled because of
     * if (action.has(EquipActionConsts.SOURCE_PATH)) {
      source = createSource(action, player);
      // Otherwise use compatibility mode
    } else*/
    if (action.has(EquipActionConsts.BASE_OBJECT)) {
      source = createSourceForContainedItem(action, player);
    } else {
      source = createSourceForNonContainedItem(action, player);

    }

    if ((source.getEntity() != null) && source.getEntity().hasSlot("content") && source.getEntity().getSlot("content").size() > 0) {
      player.sendPrivateText("Please empty your " + source.getEntityName() + " before moving it around");
      return invalidSource;
    }

    adjustAmountForStackables(action, source);
    return source;
  }

  private static SourceObject createSourceForContainedItem(final RPAction action, final Player player) {
    SourceObject source;
    final Entity parent = EquipUtil.getEntityFromId(player, action.getInt(EquipActionConsts.BASE_OBJECT));

    if (!isValidParent(parent, player)) {
      return invalidSource;
    }

    final String slotName = action.get(EquipActionConsts.BASE_SLOT);

    if (!parent.hasSlot(slotName)) {
      player.sendPrivateText("Source " + slotName + " does not exist");
      logger.error(player.getName() + " tried to use non existing slot " + slotName + " of " + parent
          + " as source. player zone: " + player.getZone() + " object zone: " + parent.getZone());

      return invalidSource;
    }
    final RPSlot baseSlot = ((EntitySlot) parent.getSlot(slotName)).getWriteableSlot();

    if (!isValidBaseSlot(player, baseSlot)) {
      return invalidSource;
    }
    final RPObject.ID baseItemId = new RPObject.ID(action.getInt(EquipActionConsts.BASE_ITEM), "");
    if (!baseSlot.has(baseItemId)) {
      logger.debug("Base item(" + parent + ") doesn't contain item(" + baseItemId + ") on given slot(" + slotName
          + ")");
      // Remove message as discussed on #arianne 2010-04-25
      // player.sendPrivateText("There is no such item in the " + slotName + " of "
        //  + parent.getDescriptionName(true));
      return invalidSource;
    }

    final Entity entity = (Entity) baseSlot.get(baseItemId);
    if (!(entity instanceof Item)) {
      player.sendPrivateText("Oh, that " + entity.getDescriptionName(true)
          + " is not an item and therefore cannot be equipped");
      return invalidSource;
    }

    if (parent instanceof Corpse) {
      Corpse corpse = (Corpse) parent;
      if (!corpse.mayUse(player)) {
        logger.debug(player.getName() + " tried to access eCorpse owned by " + corpse.getCorpseOwner());
        player.sendPrivateText("Only " + corpse.getCorpseOwner() + " may access the corpse for now.");
        return invalidSource;
      }
    }

    source = new SourceObject(player, parent, slotName, (Item) entity);

    // handle logging of looting items
    if (parent instanceof Corpse) {
      Corpse corpse = (Corpse) parent;
      checkIfLootingIsRewardable(player, corpse, source, (Item) entity);
    }

    return source;
  }
 
  /**
   * Create a SourceObject for an item path.
   *
   * @param action
   * @param player
   * @return source object
   */
  private static SourceObject createSource(RPAction action, final Player player) {
    List<String> path = action.getList(EquipActionConsts.SOURCE_PATH);
    Iterator<String> it = path.iterator();
    // The ultimate parent object
    Entity parent = EquipUtil.getEntityFromId(player, MathHelper.parseInt(it.next()));
    if (parent == null) {
      return invalidSource;
    }
   
    // Walk the slot path
    Entity entity = parent;
    String slotName = null;
    while (it.hasNext()) {
      slotName = it.next();
      if (!entity.hasSlot(slotName)) {
        player.sendPrivateText("Source " + slotName + " does not exist");
        logger.error(player.getName() + " tried to use non existing slot " + slotName + " of " + entity
            + " as source. player zone: " + player.getZone() + " object zone: " + parent.getZone());
      }
     
      final RPSlot slot = ((EntitySlot) entity.getSlot(slotName)).getWriteableSlot();
      if (!isValidBaseSlot(player, slot)) {
        return invalidSource;
      }
      if (!it.hasNext()) {
        logger.error("Missing item id");
        return invalidSource;
      }
      final RPObject.ID itemId = new RPObject.ID(MathHelper.parseInt(it.next()), "");
      if (!slot.has(itemId)) {
        logger.debug("Base item(" + entity + ") doesn't contain item(" + itemId + ") on given slot(" + slotName
            + ")");
        return invalidSource;
      }
     
      entity = (Entity) slot.get(itemId);
      if (!(entity instanceof Item)) {
        player.sendPrivateText("Oh, that " + entity.getDescriptionName(true)
            + " is not an item and therefore cannot be equipped");
        return invalidSource;
      }
    }
    // wipe parent, if the item is not contained
    if (parent == entity) {
      parent = null;
    }
   
    SourceObject source = new SourceObject(player, parent, slotName, (Item) entity);
   
    // handle logging of looting items
    if (parent instanceof Corpse) {
      Corpse corpse = (Corpse) parent;
      checkIfLootingIsRewardable(player, corpse, source, (Item) entity);
    }
   
    return source;
  }

  private static boolean isValidBaseSlot(final Player player, final RPSlot baseSlot) {
    if (! (baseSlot instanceof EntitySlot)) {
      return false;
    }
    EntitySlot slot = (EntitySlot) baseSlot;
    slot.clearErrorMessage();
    boolean res = slot.isReachableForTakingThingsOutOfBy(player);
    if (!res) {
      logger.debug("Unreachable slot");
      player.sendPrivateText(slot.getErrorMessage());
    }
    return res;
  }

  private static SourceObject createSourceForNonContainedItem(final RPAction action, final Player player) {
    final SourceObject source = new SourceObject(player);
    final RPObject.ID baseItemId = new RPObject.ID(action.getInt(EquipActionConsts.BASE_ITEM), player.getID().getZoneID());

    source.item = source.getNonContainedItem(baseItemId);
    if (source.item == null) {
      return invalidSource;
    }
    return source;
  }

  private static void adjustAmountForStackables(final RPAction action, final SourceObject source) {
    if ((source.item instanceof Stackable< ? >) && action.has(EquipActionConsts.QUANTITY)) {
      final int entityQuantity = ((Stackable< ? >) source.item).getQuantity();

      source.quantity = action.getInt(EquipActionConsts.QUANTITY);
      if ((entityQuantity < 1) || (source.quantity < 1) || (source.quantity >= entityQuantity)) {
        // quantity == 0 performs a regular move
        // of the entire item
        source.quantity = 0;
      }
    }
  }

  /**
   * Represents the source of a movement of a contained Item as in Drop or Equip.
   *
   * @param player
   *            who want to do action
   * @param parent
   *            who contains it right now
   * @param slotName
   *            where to get it from
   * @param entity
   *            the item to move
   *
   */
  private SourceObject(final Player player, final Entity parent, final String slotName, final Item entity) {
    super(player);
    this.parent = parent;
    this.slot = slotName;
    this.item = entity;
  }

  private static boolean isValidParent(final Entity parent, final Player player) {
    if (parent == null) {
      // Object doesn't exist.
      return false;
    }

    // TODO: Check that this code is not required because this check is
    // done in PlayerSlot
    // is the container a player and not the current one?
    if ((parent instanceof Player) && !parent.getID().equals(player.getID())) {
      // trying to remove an item from another player
      return false;
    }
    return true;
  }

  private Item getNonContainedItem(final RPObject.ID baseItemId) {
    Entity entity = null;
    if (SingletonRepository.getRPWorld().has(baseItemId)) {
      entity = (Entity) SingletonRepository.getRPWorld().get(baseItemId);
      if ((entity instanceof Item)) {
        if (isItemBelowOtherPlayer((Item) entity)) {
          entity = null;
        }
      } else {
        entity = null;
      }
    }
    return (Item) entity;
  }

  public SourceObject(final Player player) {
    super(player);
  }

  /**
   * moves this entity to the destination.
   *
   * @param dest
   *            to move to
   * @param player
   *            who moves the Source
   * @return true if successful
   */
  public boolean moveTo(final DestinationObject dest, final Player player) {
    if (!((EquipListener) item).canBeEquippedIn(dest.getContentSlotName())) {
      // give some feedback
      player.sendPrivateText("You can't carry this " + item.getTitle() + " on your " + dest.getContentSlotName());
      logger.warn("tried to equip an entity into disallowed slot: " + item.getClass() + "; equip rejected");
      return false;
    }

    if (!dest.isValid() || !dest.preCheck(item, player)) {
      // no extra logger warning needed here as each is inside the methods called above, where necessary
      return false;
    }

    final String[] srcInfo = getLogInfo();
    final Item entity = removeFromWorld();
    logger.debug("item removed");
    dest.addToWorld(entity, player);
    logger.debug("item readded");

    new ItemLogger().equipAction(player, entity, srcInfo, dest.getLogInfo());

    return true;
  }

  /** returns true when this SourceObject is valid. */
  @Override
  public boolean isValid() {
    return (item != null);
  }

  /**
   * returns true when this entity and the other is within the given distance.
   */
  @Override
  public boolean checkDistance(final Entity other, final double distance) {
    final Entity checker;
    if (parent != null) {
      checker = parent;
    } else {
      checker = item;
    }
    if (other.nextTo(checker, distance)) {
      return true;
    }
    logger.debug("distance check failed " + other.squaredDistance(checker));
    player.sendPrivateText("You cannot reach that far.");
    return false;
  }

  /**
   * removes the entity from the world and returns it (so it may be added
   * again). In case of splitted StackableItem the only item is reduced and a
   * new StackableItem with the splitted off amount is returned.
   *
   * @return Entity to place somewhere else in the world
   */
  public Item removeFromWorld() {
    if (quantity != 0) {
      final StackableItem newItem = ((StackableItem) item).splitOff(quantity);
      new ItemLogger().splitOff(player, item, newItem, quantity);
      return newItem;
    } else {
      item.removeFromWorld();
      return item;
    }
  }

  /**
   * Gets the entity that should be equipped.
   *
   * @return entity
   */
  public Entity getEntity() {
    return item;
  }

  /**
   * @return  the amount of objects.
   */
  public int getQuantity() {

    int temp = quantity;
    if (quantity == 0) {
      // everything
      temp = 1;
      if (item instanceof StackableItem) {
        temp = ((StackableItem) item).getQuantity();
      }

    }
    return temp;
  }

  /**
   * Sets the quantity.
   *
   * @param amount
   */
  public void setQuantity(final int amount) {
    quantity = amount;
  }

  /**
   * Checks whether the item is below <b>another</b> player.
   *
   * @param sourceItem
   *            to check
   *
   * @return true, if it cannot be taken; false otherwise
   */
  private boolean isItemBelowOtherPlayer(final Item sourceItem) {
    final List<Player> players = player.getZone().getPlayers();
    for (final Player otherPlayer : players) {
      if (player.equals(otherPlayer)) {
        continue;
      }
      if (otherPlayer.getArea().intersects(sourceItem.getArea())) {
        player.sendPrivateText("You cannot take items which are below other players");
        return true;
      }
    }
    return false;
  }

  /**
   * Checks if looting the item is rewardable as looted item
   *
   * @return true iff the player deserves it
   */
  public boolean isLootingRewardable() {
    return isLootingRewardable;
  }

  /**
   * Determines if looting should be logged for the player
   *
   * @param player
   * @param corpse
   * @param source
   * @param item
   */
  private static void checkIfLootingIsRewardable(Player player, Corpse corpse, SourceObject source, Item item) {
    if (item.isFromCorpse()) {
      if (corpse.isItemLootingRewardable()) {
        source.isLootingRewardable = true;
      } else {
        if (player.getName().equals(corpse.getKiller())) {
          source.isLootingRewardable = true;
        }
      }
    }
  }

  @Override
  public String[] getLogInfo() {
    final String[] res = new String[3];
    if (parent != null) {
      res[0] = "slot";
      if (parent.has("name")) {
        res[1] = parent.get("name");
      } else {
        res[1] = parent.getDescriptionName(false);
      }
      res[2] = slot;
    } else {
      res[0] = "ground";
      res[1] = item.getZone().getName();
      res[2] = item.getX() + " " + item.getY();
    }
    return res;
  }

  String getEntityName() {
    Entity entity1 = getEntity();
    final String itemName;
    if (entity1.has("name")) {
      itemName = entity1.get("name");
    } else if (entity1 instanceof Item) {
      itemName = "item";
    } else {
      itemName = "entity";
    }
    return itemName;
  }

  private static class InvalidSource extends SourceObject {
    /**
     * Constructor.
     */
    public InvalidSource() {
      super(null);

    }

    /**
     *
     * @return false
     */
    @Override
    public boolean isValid() {
      return false;
    }
  }
}
TOP

Related Classes of games.stendhal.server.actions.equip.SourceObject$InvalidSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.