Package games.stendhal.server.entity.item

Source Code of games.stendhal.server.entity.item.Corpse$CorpseReleaseRewardingForEveryoneTurnListener

/* $Id: Corpse.java,v 1.106 2011/04/02 15:44:18 kymara Exp $ */
/***************************************************************************
*                      (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.entity.item;

import games.stendhal.common.ItemTools;
import games.stendhal.common.MathHelper;
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.EquipListener;
import games.stendhal.server.core.events.TurnListener;
import games.stendhal.server.core.rp.group.Group;
import games.stendhal.server.entity.PassiveEntity;
import games.stendhal.server.entity.RPEntity;
import games.stendhal.server.entity.player.Player;
import games.stendhal.server.entity.slot.LootableSlot;

import java.awt.geom.Rectangle2D;
import java.util.Iterator;

import marauroa.common.game.Definition.Type;
import marauroa.common.game.RPClass;
import marauroa.common.game.RPObject;
import marauroa.common.game.RPSlot;

import org.apache.log4j.Logger;

/**
* A corpse created when a creature or player is killed. It may contain items.
*/
public class Corpse extends PassiveEntity implements EquipListener {

  /**
   * TurnListener to degradate a corpse
   *  
   * @author madmetzger
   */
  private final class CorpseRottingTurnListener implements TurnListener {
    public void onTurnReached(final int currentTurn) {
      Corpse.this.onTurnReached(currentTurn);
    }
  }
 
  /**
   * TurnListener to release this corpse to get everyone able to be rewarded for looting this corpse
   * (i.e. for achievements)
   * 
   * @author madmetzger
   */
  private final class CorpseReleaseRewardingForEveryoneTurnListener implements TurnListener {
    public void onTurnReached(final int currentTurn) {
      setCorpseOwner(null);
    }
  }

  /**
   * The killer's name attribute name.
   */
  protected static final String ATTR_KILLER = "killer";

  /**
   * The name attribute name.
   */
  protected static final String ATTR_NAME = "name";
 
  /**
   * The image name
   */
  private static final String ATTR_IMAGE = "image";

 
  /**
   * The owner of the corpse
   */
  private static final String ATTR_CORPSE_OWNER = "corpse_owner";

  private static final Logger logger = Logger.getLogger(Corpse.class);

  /** Time (in seconds) until a corpse disappears. */
  private static final int DEGRADATION_TIMEOUT = 15 * MathHelper.SECONDS_IN_ONE_MINUTE;
 
  /** number of degradation steps. */
  private static final int MAX_STAGE = 5;

  /** time between two degradation steps */
  private static final int DEGRADATION_STEP_TIMEOUT = DEGRADATION_TIMEOUT / MAX_STAGE;
 
  /** Minimum resistance of a single corpse */
  private static final int MIN_RESISTANCE = 5;
  /** Theoretical resistance of a single corpse */
  private static final int MAX_RESISTANCE = 70;
 
  /** Time (in seconds) until everyone may loot this corpse */
  private static final int PROTECTION_TIME = 5;
 
  /** Who can loot this corpse?*/
  private String corpseOwner = null;
 
  private int stage;

  private TurnListener corpseDegradator = new CorpseRottingTurnListener();
  private TurnListener itemForRewardsReleaser = new CorpseReleaseRewardingForEveryoneTurnListener();
 
  @Override
  public void onRemoved(final StendhalRPZone zone) {
    SingletonRepository.getTurnNotifier().dontNotify(corpseDegradator);
    SingletonRepository.getTurnNotifier().dontNotify(itemForRewardsReleaser);
    super.onRemoved(zone);
  }

  public static void generateRPClass() {
    final RPClass entity = new RPClass("corpse");
    entity.isA("entity");
    entity.addAttribute("class", Type.STRING);
    entity.addAttribute("stage", Type.BYTE);

    entity.addAttribute(ATTR_NAME, Type.STRING);
    entity.addAttribute(ATTR_KILLER, Type.STRING);
    entity.addAttribute(ATTR_IMAGE, Type.STRING);
    entity.addAttribute(ATTR_CORPSE_OWNER, Type.STRING);

    entity.addRPSlot("content", 4);
  }
 
  /**
   * non rotting corpse.
   *
   * @param clazz
   * @param x
   * @param y
   */
  public Corpse(final String clazz, final int x, final int y) {
    setRPClass("corpse");
    put("type", "corpse");

    setEntityClass(clazz);

    setPosition(x, y);
    stage = 0;
    put("stage", stage);
    // default to player corpse image
    put(ATTR_IMAGE, "player");
    setResistance(calculateResistance());
   
    final RPSlot slot = new LootableSlot(this);
    addSlot(slot);
  }

  /**
   * Create a corpse.
   *
   * @param victim
   *            The killed entity.
   * @param killerName
   *            The killer name.
   *
   *
   */
  public Corpse(final RPEntity victim, final String killerName) {
    setRPClass("corpse");
    put("type", "corpse");

    if (victim.has("class")) {
      setEntityClass(victim.get("class"));
    } else {
      setEntityClass(victim.get("type"));
    }
   
    put(ATTR_IMAGE, victim.getCorpseName());
    setSize(victim.getCorpseWidth(), victim.getCorpseHeight());

    if ((killerName != null)) {
      put(ATTR_NAME, victim.getTitle());
      put(ATTR_KILLER, killerName);
    } else if (has(ATTR_KILLER)) {
      logger.error("Corpse: (" + victim + ") with null killer");
      remove(ATTR_KILLER);
    }

    final Rectangle2D rect = victim.getArea();

    setPosition(
        (int) (rect.getX() + ((rect.getWidth() - getWidth()) / 2.0)),
        (int) (rect.getY() + ((rect.getHeight() - getHeight()) / 2.0)));

    SingletonRepository.getTurnNotifier().notifyInSeconds(getDegradationStepTimeout(), this.corpseDegradator);

    if (victim.getCorpseDeserver() != null) {
      setCorpseOwner(victim.getCorpseDeserver());
      SingletonRepository.getTurnNotifier().notifyInSeconds(PROTECTION_TIME, this.itemForRewardsReleaser);
    }
   
    stage = 0;
    put("stage", stage);
    setResistance(calculateResistance());

    final RPSlot slot = new LootableSlot(this);
    addSlot(slot);
  }

  /**
   * sets the owner of the corpse, while set only this person may loot.
   *
   * @param owner name of owner
   */
  private void setCorpseOwner(String owner) {
    this.corpseOwner = owner;
    if (owner != null) {
      put(ATTR_CORPSE_OWNER, owner);
    } else {
      remove(ATTR_CORPSE_OWNER);
    }
    modify();
  }

  /**
   * Get the name of the owner of this corpse (the player who's
   * deemend worthy to access the items within).
   * 
   * @return the name of the owner or <code>null</code> if anyone
   * may use the items
   */
  public String getCorpseOwner() {
    return corpseOwner;
  }

  /**
   * Calculate walking resistance for the corpse.
   * 
   * @return resistance value between <code>100 * MIN_RESISTANCE</code> and
   * <code>100 * MAX_RESISTANCE</code>
   */
  private int calculateResistance() {
    // Using area would make the resistance grow very fast for large corpses
    double mean = Math.sqrt(getWidth() * getHeight());
    // Get a [0, 1[ value for a corpse size index
    double normalized = 1 - 1 / Math.max(1.0, mean);
    // Scale between max and min
    return Math.max(MIN_RESISTANCE, (int) (MAX_RESISTANCE * normalized));
  }

  //
  // Corpse
  //

  /**
   * Get the entity name.
   *
   * @return The entity's name, or <code>null</code> if undefined.
   */
  public String getName() {
    if (has(ATTR_NAME)) {
      return get(ATTR_NAME);
    } else {
      return null;
    }
  }

  /**
   * Set the killer name of the corpse.
   *
   * @param killer
   *            The corpse's killer name.
   */
  public void setKiller(final String killer) {
    put(ATTR_KILLER, killer);
  }

  /**
   * Set the name of the corpse.
   *
   * @param name
   *            The corpse name.
   */
  public void setName(final String name) {
    put(ATTR_NAME, name);
  }

  private void modify() {
    if (getZone() != null) {
      if (isContained()) {
        SingletonRepository.getRPWorld().modify(getBaseContainer());
      } else {
        notifyWorldAboutChanges();
      }
    }
  }

  /**
   * @return true iff this corpse is completely rotten
   */
  private boolean isCompletelyRotten() {
    return stage >= MAX_STAGE;
  }

  /**
   * degradate this corpse
   */
  private void degradateCorpse() {
    stage++;
    put("stage", stage);
    modify();
  }

  /**
   * degradates this corpse and remove it if it is completely rotten
   *
   * @param currentTurn ignored
   */
  public void onTurnReached(final int currentTurn) {
    degradateCorpse();
    if (isCompletelyRotten()) {
        this.getZone().remove(this);
    } else {
      SingletonRepository.getTurnNotifier().notifyInSeconds(getDegradationStepTimeout(), this.corpseDegradator);
    }
  }

  /**
   * Sets the current degrading state. Set it to MAX_STAGE will remove the
   * corpse.
   *
   * @param newStage
   */
  public void setStage(final int newStage) {
    if ((newStage >= 0) && (newStage <= MAX_STAGE)) {
      stage = newStage;
      put("stage", stage);
      modify();
    }
  }

  /**
   * adds content to this corpse
   *
   * @param entity PassiveEntity to add
   */
  public void add(final PassiveEntity entity) {
    final RPSlot content = getSlot("content");
    content.add(entity);
  }

  /**
   * is the corpse full so that there is no more room for additinal items?
   *
   * @return true if the corpse is full, false otherwise
   */
  public boolean isFull() {
    return getSlot("content").isFull();
  }

  @Override
  public int size() {
    return getSlot("content").size();
  }

  /**
   * gets an iterator over the content
   *
   * @return Iterator
   */
  public Iterator<RPObject> getContent() {
    final RPSlot content = getSlot("content");
    return content.iterator();
  }

  @Override
  public String describe() {
    final String[] stageText = { "new", "fresh", "cold", "slightly rotten",
        "rotten", "very rotten" };

    String text = "You see the " + stageText[stage] + " corpse of ";

    if (hasDescription()) {
      text = getDescription();
    } else if (has(ATTR_NAME)) {
      text += get(ATTR_NAME);

      if (has(ATTR_KILLER)) {
        // only display the killer if it is the corpse of a player
        if (get("class").equals("player")) {
          text += ", killed by " + get(ATTR_KILLER);
        }
      }
    } else {
      text += Grammar.a_noun(ItemTools.itemNameToDisplayName(get("class")));
    }

    text += ". You can #inspect it to see its contents.";

    return (text);
  }

  public boolean canBeEquippedIn(final String slot) {
    return false;
  }

  //
  // Entity
  //

  /**
   * Returns the name or something that can be used to identify the entity for
   * the player.
   *
   * @param definite
   *            <code>true</code> for "the", and <code>false</code> for
   *            "a/an" in case the entity has no name.
   *
   * @return The description name.
   */
  @Override
  public String getDescriptionName(final boolean definite) {
    final String name = getName();

    if (name != null) {
      return name;
    } else {
      return super.getDescriptionName(definite);
    }
  }

  /**
   * Get the nicely formatted entity title/name.
   *
   * @return The title, or <code>null</code> if unknown.
   */
  @Override
  public String getTitle() {
    final String name = getName();

    if (name != null) {
      return name;
    } else {
      return super.getTitle();
    }
  }

  /**
   * The length of a degradation step
   *
   * @return in seconds
   */
  protected int getDegradationStepTimeout() {
    return DEGRADATION_STEP_TIMEOUT;
  }

 
  /**
   * Check if a player may access the slots of this corpse
   *
   * @param player the player trying to use the items in the corpse
   * @return true iff the player may access the items in the slots
   */
  public boolean mayUse(Player player) {

    // check the simple cases first
    if (corpseOwner == null || corpseOwner.equals(player.getName()) || get("class").equals("player")) {
      return true;
    }

    // okay, now check the group rules
    Group group = SingletonRepository.getGroupManager().getGroup(player.getName());
    if (group != null) {
      if (group.getLootmode().equals("shared") && group.hasMember(corpseOwner)) {
        return true;
      }
    }

    return false;
  }

  /**
   * Checks if looting this corpse will be rewarded (i.e. for achievements).
   *
   * @return true if looting should be rewarded
   */
  public boolean isItemLootingRewardable() {
    return !get("class").equals("player");
  }

  /**
   * gets the killer of this corpse
   *
   * @return the name of the killer
   */
  public String getKiller() {
    return get(ATTR_KILLER);
  }
}
TOP

Related Classes of games.stendhal.server.entity.item.Corpse$CorpseReleaseRewardingForEveryoneTurnListener

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.