Package games.stendhal.server.entity.mapstuff.chest

Source Code of games.stendhal.server.entity.mapstuff.chest.PersonalChest

/* $Id: PersonalChest.java,v 1.21 2011/04/02 15:44:18 kymara 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.entity.mapstuff.chest;

import games.stendhal.common.grammar.Grammar;
import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.core.engine.StendhalRPZone;
import games.stendhal.server.core.events.TurnListener;
import games.stendhal.server.entity.RPEntity;
import games.stendhal.server.entity.item.Item;
import games.stendhal.server.entity.player.Player;
import games.stendhal.server.entity.slot.PersonalChestSlot;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

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

import org.apache.log4j.Logger;

/**
* A PersonalChest is a Chest that can be used by everyone, but shows different
* contents depending on the player who is currently using it. Thus, a player
* can put in items into this chest and be sure that nobody else will be able to
* take them out.
* <p>
* Caution: each PersonalChest must be placed in such a way that only one player
* can stand next to it at a time, to prevent other players from stealing while
* the owner is looking at his items.
*/
public class PersonalChest extends Chest {
 
  /**
   * The default bank slot name.
   */
  public static final String DEFAULT_BANK = "bank";

  private static Logger LOGGER = Logger.getLogger(PersonalChest.class);

 
  private RPEntity attending;

  private final String bankName;

  private SyncContent chestSynchronizer;

  /**
   * Create a personal chest using the default bank slot.
   */
  public PersonalChest() {
    this(DEFAULT_BANK);
  }

  /**
   * Create a personal chest using a specific bank slot.
   *
   * @param bankName
   *            The name of the bank slot.
   */
  public PersonalChest(final String bankName) {
    this.bankName = bankName;
    attending = null;

    super.removeSlot("content");
    super.addSlot(new PersonalChestSlot(this));
  }

  /**
   * Gets the entitiy which is currently served by this chest.
   *
   * @return Entity
   */
  public RPEntity getAttending() {
    return attending;
  }

  /**
   * Copies an item.
   *
   *
   * @param item
   *            item to copy
   * @return copy
   * @throws SecurityException
   * @throws NoSuchMethodException
   * @throws IllegalArgumentException
   * @throws InstantiationException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   */
  private RPObject cloneItem(final RPObject item) throws NoSuchMethodException,
      InstantiationException, IllegalAccessException,
      InvocationTargetException {
    final Class< ? > clazz = item.getClass();
    final Constructor< ? > ctor = clazz.getConstructor(clazz);
    final Item clone = (Item) ctor.newInstance(item);
    return clone;
  }

  /**
   * Get the slot that holds items for this chest.
   *
   * @return A per-player/per-bank slot.
   */
  public RPSlot getBankSlot() {
    if (attending == null) {
      LOGGER.error("Calling getBankSlot on non-attending PersonalChest " + this, new Throwable());
      return null;
    }
    return attending.getSlot(bankName);
  }

  /**
   * Sync the slot contents.
   *
   * @return <code>true</code> if it should be called again.
   */
  protected boolean syncContent() {
    if (attending != null) {
      /* Can be replaced when we add Equip event */
      /* Mirror chest content into player's bank slot */
      final RPSlot bank = getBankSlot();
      bank.clear();

      for (final RPObject item : getSlot("content")) {
        try {
          bank.addPreservingId(cloneItem(item));
        } catch (final Exception e) {
          LOGGER.error("Cannot clone item " + item, e);
        }
      }

      // Verify the user is next to the chest
      if (getZone().has(attending.getID()) && nextTo(attending)) {
        return true;
      } else {
        // If player is not next to depot, close it (also clears it).
        close();
        notifyWorldAboutChanges();
      }
    }

    return false;
  }

  /**
   * Open the chest for an attending user.
   *
   * @param user
   *            The attending user.
   */
  public void open(final RPEntity user) {
    attending = user;

    chestSynchronizer = new SyncContent();
    SingletonRepository.getTurnNotifier().notifyInTurns(0, chestSynchronizer);

    final RPSlot content = getSlot("content");
    content.clear();

    for (final RPObject item : getBankSlot()) {
      try {
        content.addPreservingId(cloneItem(item));
      } catch (final Exception e) {
        LOGGER.error("Cannot clone item " + item, e);
      }
    }

    super.open();
  }

  /**
   * Close the chest.
   */
  @Override
  public void close() {
    super.close();

    getSlot("content").clear();
    attending = null;

  }

  /**
   * Don't let this be called directly for personal chests.
   */
  @Override
  public void open() {
    throw new RuntimeException("User context required to open");
  }

  @Override
  public boolean onUsed(final RPEntity user) {
    if (user.nextTo(this)) {
      if (isOpen()) {
        close();
      } else {
        open(user);
      }

      notifyWorldAboutChanges();
      return true;
    }
    if (user instanceof Player) {
      final Player player = (Player) user;
      player.sendPrivateText("You cannot reach the chest from there.");
    }
    return false;
  }

  @Override
    public String getDescriptionName(final boolean definite) {
      return Grammar.article_noun(bankName + " chest", definite);
    }

  /**
   * A listener for syncing the slot contents.
   */
  protected class SyncContent implements TurnListener {
    /**
     * This method is called when the turn number is reached.
     *
     * @param currentTurn
     *            The current turn number.
     */
    public void onTurnReached(final int currentTurn) {
      if (syncContent()) {
        SingletonRepository.getTurnNotifier().notifyInTurns(0, this);
      }
    }
   
   
  }
@Override
public void onRemoved(final StendhalRPZone zone) {
  SingletonRepository.getTurnNotifier().dontNotify(chestSynchronizer);

  super.onRemoved(zone);
}
}
TOP

Related Classes of games.stendhal.server.entity.mapstuff.chest.PersonalChest

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.