Package games.stendhal.client.entity

Source Code of games.stendhal.client.entity.RPEntity$TextIndicator

/* $Id: RPEntity.java,v 1.286 2011/04/02 15:44:21 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.client.entity;

import games.stendhal.client.ClientSingletonRepository;
import games.stendhal.client.GameObjects;
import games.stendhal.client.stendhal;
import games.stendhal.client.gui.chatlog.HeaderLessEventLine;
import games.stendhal.client.gui.chatlog.StandardEventLine;
import games.stendhal.client.gui.chatlog.StandardHeaderedEventLine;
import games.stendhal.common.ItemTools;
import games.stendhal.common.NotificationType;
import games.stendhal.common.constants.Nature;
import games.stendhal.common.grammar.Grammar;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import marauroa.common.game.RPObject;
import marauroa.common.game.RPObject.ID;

import org.apache.log4j.Logger;

/**
* This class is a link between client graphical objects and server attributes
* objects.<br>
* You need to extend this object in order to add new elements to the game.
*/
public abstract class RPEntity extends ActiveEntity {

 

  /**
   * Admin Level property.
   */
  public static final Property PROP_ADMIN_LEVEL = new Property();

  /**
   * ghostmode property.
   */
  public static final Property PROP_GHOSTMODE = new Property();

  /**
   * group membership.
   */
  public static final Property PROP_GROUP_MEMBERSHIP = new Property();

  /**
   * Indicator text property. Fired if they are added or removed.
   */
  public static final Property PROP_TEXT_INDICATORS = new Property();

  /**
   * Outfit property.
   */
  public static final Property PROP_OUTFIT = new Property();

  /**
   * Title Type property.
   */
  public static final Property PROP_TITLE_TYPE = new Property();
 
  /**
   * Hp and max HP property.
   */
  public static final Property PROP_HP_RATIO = new Property();

  /**
   * The value of an outfit that isn't set.
   */
  public static final int OUTFIT_UNSET = -1;
 
  private static final Logger LOGGER = Logger.getLogger(RPEntity.class);


  /**
   * Entity we are attacking. (need to reconsile this with 'attacking')
   */
  protected RPEntity attackTarget;

  /**
   * The entities attacking this entity.
   */
  protected List<Entity> attackers;
/*
  String[] attackSounds = { "punch-1", "punch-2", "punch-3",
      "punch-4", "punch-5", "punch-6", "swingaxe-1",
      "slap-1", "arrow-1" };
  */
 
  private Nature showBladeStrike;

  public enum Resolution {
    HIT,
    BLOCKED,
    MISSED;
  }
 
 

  private int atk;

  private int def;

  private int xp;

  private int hp;

  private int adminlevel;

  /**
   * The outfit code.
   */
  private int outfit;

  private int base_hp;

  private float hp_base_hp;

  private int level;

  private boolean eating;

  private boolean poisoned;

  private boolean choking;

  /**
   * Time stamp of previous attack event. Volatile to prevent reordering
   * assignments with <code>resolution</code>.
   */
  private volatile long combatIconTime;

  private final List<TextIndicator> textIndicators;

  private RPObject.ID attacking;

  private int mana;

  private int base_mana;

  private boolean ghostmode;

  private String titleType;

 

  /**
   * The result of previous attack against this entity. Volatile to prevent
   * reordering assignments with <code>combatIconTime</code>.
   */
  private volatile Resolution resolution;

  private int atkXP;

  private int defXp;

  private int atkItem = -1;

  private int defItem = -1;

  /** Creates a new game entity. */
  RPEntity() {
    textIndicators = new LinkedList<TextIndicator>();
    attackTarget = null;
    attackers = new LinkedList<Entity>();
  }

  //
  // RPEntity
  //

  /**
   * Create/add a text indicator message.
   *
   * @param text
   *            The text message.
   * @param type
   *            The indicator type.
   */
  protected void addTextIndicator(final String text,
      final NotificationType type) {
    textIndicators.add(new TextIndicator(text, type));
    fireChange(PROP_TEXT_INDICATORS);
  }

  /**
   * Get the admin level.
   *
   * @return The admin level.
   */
  public int getAdminLevel() {
    return adminlevel;
  }

  /**
   * @return Returns the atk.
   */
  public int getAtk() {
    return atk;
  }

  /**
   * @return Returns the atk of items
   */
  public int getAtkItem() {
    return atkItem;
  }

  /**
   * @return the attack xp
   */
  public int getAtkXP() {
    return atkXP;
  }

  /**
   * @return Returns the base_hp.
   */
  public int getBaseHP() {
    return base_hp;
  }

  /**
   * @return Returns the base mana value
   */
  public int getBaseMana() {
    return base_mana;
  }

  /**
   * @return Returns the def.
   */
  public int getDef() {
    return def;
  }

  /**
   * @return Returns the def of items
   */
  public int getDefItem() {
    return defItem;
  }

  /**
   * @return the defence xp
   */
  public int getDefXP() {
    return defXp;
  }

  public int getHP() {
    return hp;
  }

  /**
   * Get the ratio of HP to base HP.
   *
   * @return The HP ratio (0.0 - 1.0).
   */
  public float getHpRatio() {
    return hp_base_hp;
  }

  /**
   * Get the list of text indicator elements.
   *
   * @return An iterator of text indicators.
   */
  public Iterator<TextIndicator> getTextIndicators() {
    return textIndicators.iterator();
  }

  public int getLevel() {
    return level;
  }

  /**
   * @return Returns the total mana of a player
   */
  public int getMana() {
    return mana;
  }

  /**
   * Get the outfit code.
   *
   * @return The outfit code.
   */
  public int getOutfit() {
    return outfit;
  }

  public Resolution getResolution() {
    return resolution;
  }
 
  /**
   * Get the attack target of an entity.
   *
   * @return the target, or <code>null</code> if there is none
   */
  public RPEntity getAttackTarget() {
    return attackTarget;
  }

  /**
   * Update the target.
   *
   * @param targetString The target id as a string
   * @param zoneId zone of the entity
   */
  private void setTarget(String targetString, String zoneId) {
    final int target = Integer.parseInt(targetString);
   
    final RPObject.ID targetEntityID = new RPObject.ID(target, zoneId);
    final RPEntity targetEntity = (RPEntity) GameObjects.getInstance().get(
        targetEntityID);

    if (targetEntity != attackTarget) {
      onStopAttack();

      if (attackTarget != null) {
        attackTarget.onStopAttacked(this);
      }

      attackTarget = targetEntity;

      if (attackTarget != null) {
        onAttack(attackTarget);
        attackTarget.onAttacked(this);
      }
    }
  }
 
  /**
   * Update the target.
   *
   * @param targetString The target id as a string
   */
  private void setTarget(String targetString) {
    setTarget(targetString, rpObject.get("zoneid"));
  }


  /**
   * Get the nicely formatted entity title.
   *
   * This searches the follow attribute order: title, name (w/o underscore),
   * class (w/o underscore), type (w/o underscore).
   *
   * @return The title, or <code>null</code> if unknown.
   */
  @Override
  public String getTitle() {
    if (title != null) {
      return title;
    } else if (name != null) {
      return name;
    } else if (clazz != null) {
      // replace underscores in clazz and type without calling the function UpdateConverter.transformItemName() located in server code
      return ItemTools.itemNameToDisplayName(clazz);
    } else if (type != null) {
      return ItemTools.itemNameToDisplayName(type);
    } else {
      return null;
    }
  }

  /**
   * Get title type.
   *
   * @return The title type.
   */
  public String getTitleType() {
    return titleType;
  }

  /**
   * @return Returns the XP.
   */
  public int getXP() {
    return xp;
  }

  public boolean isAttacking() {
    if (attacking == null) {
      /*
       * Check for disagreement, and update if needs be.
       * Can happen when the target is added to the zone after the attacker.
       */
      String id = rpObject.get("target");
      if (id != null) {
        setTarget(id);
      }
    }
    return (attacking != null);
  }

  public boolean isAttacking(final IEntity defender) {
    if (defender == null) {
      return false;
    }
   
    final ID defenderID = defender.getID();
    return (isAttacking() && attacking.equals(defenderID));
  }

  public boolean isBeingAttacked() {
    return !attackers.isEmpty();
  }

  public boolean isAttackedBy(final IEntity attacker) {
    return attackers.contains(attacker);
  }

  /**
   * Get the damage type of the current strike.
   *
   * @return type of damage, or <code>null</code> if the entity is not striking
   */
  public Nature getShownDamageType() {
    return showBladeStrike;
  }

  public void doneStriking() {
    showBladeStrike = null;
  }

  /**
   * Check if the entity is defending against an attack right now. The entity
   * is defending if the last attack happened within 1.2s.
   *
   * @return <code>true</code> if the entity is defending against an attack,
   *   <code>false</code> otherwise
   */
  public boolean isDefending() {
    return (isBeingAttacked() && (System.currentTimeMillis()
        - combatIconTime < 4 * 300));
  }

  public boolean isEating() {
    return eating;
  }

  /**
   * Determine if in full ghostmode.
   *
   * @return <code>true</code> is in full ghostmode.
   */
  public boolean isGhostMode() {
    return ghostmode;
  }

  public boolean isPoisoned() {
    return poisoned;
  }

  public boolean isChoking() {
    return choking;
  }

  // TODO: this is just an ugly workaround to avoid cyclic dependencies with
  // Creature
  protected void nonCreatureClientAddEventLine(final String text) {
    ClientSingletonRepository.getUserInterface().addEventLine(new StandardHeaderedEventLine(getTitle(), text));
  }

  // When this entity attacks target.
  public void onAttack(final IEntity target) {
    attacking = target.getID();
  }

  // When this entity's attack is blocked by the adversary
  public void onAttackBlocked(final Nature type) {
    showBladeStrike = type;
  }

  // When this entity causes damaged to adversary, with damage amount
  public void onAttackDamage(final Nature type) {
    showBladeStrike = type;
  }

  // When this entity's attack is missing the adversary
  public void onAttackMissed(final Nature type) {
    showBladeStrike = type;
  }

  // When attacker attacks this entity.
  public void onAttacked(final Entity attacker) {
    attackers.remove(attacker);
    attackers.add(attacker);
  }

  // When this entity blocks the attack by attacker
  public void onBlocked(final IEntity attacker) {
    // Resolution must be set before isDefending may return true.
    resolution = Resolution.BLOCKED;
    combatIconTime = System.currentTimeMillis();
  }

 
 
  // When this entity is damaged by attacker with damage amount
  public void onDamaged(final Entity attacker, final int damage) {
    // Resolution must be set before isDefending may return true.
    resolution = Resolution.HIT;
    combatIconTime = System.currentTimeMillis();
    /*try {
      SoundSystemFacade.get().play(attackSounds[Rand.rand(attackSounds.length)], x, y, SoundLayer.CREATURE_NOISE, 100);
    } catch (final NullPointerException e) {
      // ignore errors
    }*/

    boolean showAttackInfoForPlayer = (this.isUser() || attacker.isUser());
    showAttackInfoForPlayer = showAttackInfoForPlayer
        & (!stendhal.FILTER_ATTACK_MESSAGES);

    if (stendhal.SHOW_EVERYONE_ATTACK_INFO || showAttackInfoForPlayer) {
      ClientSingletonRepository.getUserInterface().addEventLine(new HeaderLessEventLine(
          getTitle() + " suffers "
              + Grammar.quantityplnoun(damage, "point")
              + " of damage from " + attacker.getTitle(),
          NotificationType.NEGATIVE));
    }
  }

  // When entity eats food
  public final void onEat() {
    eating = true;
  }

  public void onStopEating() {
    eating = false;
  }

  // When entity gets healed
  public void onHealed(final int amount) {
    // do nothing for normal rpentities
  }

  // When entity chokes on food
  public final void onChoking() {
    choking = true;
  }

  public void onStopChoking() {
    choking = false;
  }

  // When entity adjusts HP
  public void onHPChange(final int amount) {
    if (User.squaredDistanceTo(x, y) < 15 * 15) {
      if (amount > 0) {
        addTextIndicator("+" + amount, NotificationType.POSITIVE);
      } else {
        addTextIndicator(String.valueOf(amount),
            NotificationType.NEGATIVE);
      }
    }
  }

  // When this entity skip attacker's attack.
  public void onMissed(final IEntity attacker) {
    // Resolution must be set before isDefending may return true.
    resolution = Resolution.MISSED;
    combatIconTime = System.currentTimeMillis();
  }

  // When entity is poisoned
  public final void onPoisoned(final int amount) {
    if ((User.squaredDistanceTo(x, y) < 15 * 15)) {
      poisoned = true;
      ClientSingletonRepository.getUserInterface().addEventLine(
          new HeaderLessEventLine(
          getTitle() + " is poisoned, losing "
              + Grammar.quantityplnoun(amount, "health point")
              + ".", NotificationType.NEGATIVE));
    }
  }

  public void onPoisonEnd() {
    poisoned = false;
  }

  // Called when entity listen to text from talker
  public void onPrivateListen(final String texttype, final String text) {
    NotificationType type;
    try {
      type = NotificationType.valueOf(texttype);
    } catch (final RuntimeException e) {
      LOGGER.error("Unkown texttype: ", e);
      type = NotificationType.PRIVMSG;
    }

   
    ClientSingletonRepository.getUserInterface().addEventLine(new HeaderLessEventLine(text, type));

    // Scene settings messages should not disturb playing, just create some atmosphere
    if (type != NotificationType.SCENE_SETTING) {
      ClientSingletonRepository.getUserInterface().addGameScreenText(
          getX() + (getWidth() / 2.0), getY(),
          text.replace("|", ""), type, false);
    }
  }

  // When this entity stops attacking
  public void onStopAttack() {
    attacking = null;
  }
 
  // When attacker stop attacking us
  public void onStopAttacked(final IEntity attacker) {
    attackers.remove(attacker);
  }
 
  public void onReachAchievement(String achievementTitle, String achievementDescription, String achievementCategory) {
    ClientSingletonRepository.getUserInterface().addAchievementBox(achievementTitle, achievementDescription, achievementCategory);
  }

  // Called when entity says text
  public void onTalk(final String text) {
    if (User.isAdmin() || (User.squaredDistanceTo(x, y) < 15 * 15)) {
      String line = text.replace("|", "");
     
      //an emote action is changed server side to an chat action with a leading !me
      //this supports also invoking an emote with !me instead of /me
      if (text.startsWith("!me")) {
        line = line.replace("!me", getTitle());
        ClientSingletonRepository.getUserInterface().addEventLine(new HeaderLessEventLine(line, NotificationType.EMOTE));
       
        return;
      } else {
        //add the original version
        nonCreatureClientAddEventLine(text);
      }

      // Allow for more characters and cut the text if possible at the
      // nearest space etc.
      if (line.length() > 84) {
        line = line.substring(0, 84);
        int l = line.lastIndexOf(" ");
        int ln = line.lastIndexOf("-");

        if (ln > l) {
          l = ln;
        }

        ln = line.lastIndexOf(".");

        if (ln > l) {
          l = ln;
        }

        ln = line.lastIndexOf(",");

        if (ln > l) {
          l = ln;
        }

        if (l > 0) {
          line = line.substring(0, l);
        }

        line = line + " ...";
      }

      ClientSingletonRepository.getUserInterface().addGameScreenText(
          getX() + getWidth(), getY(), line,
          NotificationType.NORMAL, true);
    }
  }

  //
  // Entity
  //

  /**
   * Get the resistance this has on other entities (0-100).
   *
   * @return The resistance, or 0 if in ghostmode.
   */
  @Override
  public int getResistance() {
    if (isGhostMode()) {
      return 0;
    } else {
      return super.getResistance();
    }
  }

  /**
   * Initialize this entity for an object.
   *
   * @param object
   *            The object.
   *
   * @see #release()
   */
  @Override
  public void initialize(final RPObject object) {
    super.initialize(object);

    /*
     * Base HP
     */
    if (object.has("base_hp")) {
      base_hp = object.getInt("base_hp");
    } else {
      base_hp = 0;
    }

    /*
     * HP
     */
    if (object.has("hp")) {
      hp = object.getInt("hp");
    } else {
      hp = 0;
    }

    /*
     * HP ratio
     */
    if (hp >= base_hp) {
      hp_base_hp = 1.0f;
    } else if (hp <= 0) {
      hp_base_hp = 0.0f;
    } else {
      hp_base_hp = hp / (float) base_hp;
    }

    /*
     * Public chat
     */
    if (object.has("text")) {
      onTalk(object.get("text"));
    }

    /*
     * Outfit
     */
    if (object.has("outfit")) {
      outfit = object.getInt("outfit");
    } else {
      outfit = OUTFIT_UNSET;
    }

    /*
     * Eating
     */
    if (object.has("eating")) {
      onEat();
    }

    /*
     * Choking
     */
    if (object.has("choking")) {
      onChoking();
    }
    /*
     * Poisoned
     */
//    if (object.has("poisoned")) {
//      // TODO: To remove the - sign on poison.
//      // onPoisoned(Math.abs(object.getInt("poisoned")));
//    }

    /*
     * Ghost mode feature.
     */
    if (object.has("ghostmode")) {
      ghostmode = true;
    }

    /*
     * Healed
     */
    if (object.has("heal")) {
      onHealed(object.getInt("heal"));
    }

    /*
     * Attack Target is handled later, as it can not be checked reliably
     * now anyway.
     */

    /*
     * Admin level
     */
    if (object.has("adminlevel")) {
      adminlevel = object.getInt("adminlevel");
    } else {
      adminlevel = 0;
    }

    /*
     * Title type
     */
    if (object.has("title_type")) {
      titleType = object.get("title_type");
    } else {
      titleType = null;
    }
  }

  /**
   * Release this entity. This should clean anything that isn't automatically
   * released (such as unregister callbacks, cancel external operations, etc).
   *
   * @see #initialize(RPObject)
   */
  @Override
  public void release() {
    onStopAttack();

    if (attackTarget != null) {
      attackTarget.onStopAttacked(this);
      attackTarget = null;
    }

    super.release();
  }

  /**
   * Update cycle.
   *
   * @param delta
   *            The time (in ms) since last call.
   */
  @Override
  public void update(final int delta) {
    super.update(delta);

    if (!textIndicators.isEmpty()) {
      final Iterator<TextIndicator> iter = textIndicators.iterator();

      boolean changed = false;
      while (iter.hasNext()) {
        final TextIndicator textIndicator = iter.next();

        if (textIndicator.addAge(delta) > 2000L) {
          iter.remove();
          changed = true;
        }
      }

      if (changed) {
        fireChange(PROP_TEXT_INDICATORS);
      }
    }
  }

  //
  // RPObjectChangeListener
  //

  /**
   * The object added/changed attribute(s).
   *
   * @param object
   *            The base object.
   * @param changes
   *            The changes.
   */
  @Override
  public void onChangedAdded(final RPObject object, final RPObject changes) {
    super.onChangedAdded(object, changes);

    if (!inAdd) {
      /*
       * Public chat
       */
      if (changes.has("text")) {
        onTalk(changes.get("text"));
      }

      /*
       * Outfit
       */
      if (changes.has("outfit")) {
        outfit = changes.getInt("outfit");
        fireChange(PROP_OUTFIT);
      }

      /*
       * Eating
       */
      if (changes.has("eating")) {
        onEat();
      }

      /*
       * Choking
       */
      if (changes.has("choking")) {
        onChoking();
      }

      /*
       * Poisoned
       */
      if (changes.has("poisoned")) {
        // To remove the - sign on poison.
        onPoisoned(Math.abs(changes.getInt("poisoned")));
      }

      /*
       * Healed
       */
      if (changes.has("heal")) {
        onHealed(changes.getInt("heal"));
      }

      boolean hpRatioChange = false;

      /*
       * Base HP
       */
      if (changes.has("base_hp")) {
        base_hp = changes.getInt("base_hp");
        hpRatioChange = true;
      }

      /*
       * HP
       */
      if (changes.has("hp")) {
        final int newHP = changes.getInt("hp");
        final int change = newHP - hp;

        hp = newHP;

        if (object.has("hp") && (change != 0)) {
          onHPChange(change);
        }

        hpRatioChange = true;
      }

      /*
       * HP ratio
       */
      if (hpRatioChange) {
        if (hp >= base_hp) {
          hp_base_hp = 1.0f;
        } else if (hp <= 0) {
          hp_base_hp = 0.0f;
        } else {
          hp_base_hp = hp / (float) base_hp;
        }
        if (hp == 0) {
          onDeath(attackers);
        }
        fireChange(PROP_HP_RATIO);
      }

      /*
       * Attack Target
       */

      String target = changes.get("target");
      if (target != null) {
        setTarget(target, changes.get("zoneid"));
      }

      /*
       * Admin level
       */
      if (changes.has("adminlevel")) {
        adminlevel = changes.getInt("adminlevel");
        fireChange(PROP_ADMIN_LEVEL);
      }

      /*
       * Title type
       */
      if (changes.has("title_type")) {
        titleType = changes.get("title_type");
        fireChange(PROP_TITLE_TYPE);
      }

      /*
       * Title
       */
      if (changes.has("class") || changes.has("name")
          || changes.has("title")) {
        fireChange(PROP_TITLE);
      }
    }

    if (changes.has("atk")) {
      atk = changes.getInt("atk");
    }

    if (changes.has("def")) {
      def = changes.getInt("def");
    }

    if (changes.has("level")) {
      level = changes.getInt("level");
    }

    if (changes.has("atk_xp")) {
      atkXP = changes.getInt("atk_xp");
    }

    if (changes.has("def_xp")) {
      defXp = changes.getInt("def_xp");
    }

    if (changes.has("atk_item")) {
      atkItem = changes.getInt("atk_item");
    }

    if (changes.has("def_item")) {
      defItem = changes.getInt("def_item");
    }

    if (changes.has("mana")) {
      mana = changes.getInt("mana");
    }

    if (changes.has("base_mana")) {
      base_mana = changes.getInt("base_mana");
    }

    if (changes.has("ghostmode")) {
      ghostmode = true;
      fireChange(PROP_GHOSTMODE);
    }

    if (changes.has("xp")) {
      int newXp = changes.getInt("xp");
     
      if (object.has("xp")) {
        if (User.squaredDistanceTo(x, y) < 15 * 15) {
          final int amount = newXp - xp;
          if (amount > 0) {
            addTextIndicator("+" + amount,
                NotificationType.SIGNIFICANT_POSITIVE);
            ClientSingletonRepository.getUserInterface().addEventLine(new HeaderLessEventLine(
                getTitle()
                + " earns "
                + Grammar.quantityplnoun(amount,
                "experience point") + ".",
                NotificationType.SIGNIFICANT_POSITIVE));
          } else if (amount < 0) {
            addTextIndicator("" + amount,
                NotificationType.SIGNIFICANT_NEGATIVE);
            ClientSingletonRepository.getUserInterface().addEventLine(new HeaderLessEventLine(
                getTitle()
                + " loses "
                + Grammar.quantityplnoun(-amount,
                "experience point") + ".",
                NotificationType.SIGNIFICANT_NEGATIVE));
          }
        }
      }
     
      xp = newXp;
    }

    if (changes.has("level") && object.has("level")) {
      if (User.squaredDistanceTo(x, y) < 15 * 15) {
        final String text = getTitle() + " reaches Level " + getLevel();
        ClientSingletonRepository.getUserInterface().addEventLine(new HeaderLessEventLine(text,
            NotificationType.SIGNIFICANT_POSITIVE));

        ClientSingletonRepository.getUserInterface().addGameScreenText(
            getX() + (getWidth() / 2.0), getY(),
            text, NotificationType.SIGNIFICANT_POSITIVE, false);
      }
    }
  }

  private void onDeath(final List<Entity> attackers) {
    if (!attackers.isEmpty()) {
      Collection<String> attackerNames = new LinkedList<String>();
      for (Entity ent : attackers) {
          attackerNames.add(ent.getTitle());
      }
      ClientSingletonRepository.getUserInterface().addEventLine(new StandardEventLine(
          getTitle() + " has been killed by " + Grammar.enumerateCollection(attackerNames)));
    }
  }

  /**
   * The object removed attribute(s).
   *
   * @param object
   *            The base object.
   * @param changes
   *            The changes.
   */
  @Override
  public void onChangedRemoved(final RPObject object, final RPObject changes) {
    super.onChangedRemoved(object, changes);

    /*
     * Outfit
     */
    if (changes.has("outfit")) {
      outfit = OUTFIT_UNSET;
      fireChange(PROP_OUTFIT);
    }

    /*
     * No longer poisoned?
     */
    if (changes.has("poisoned")) {
      onPoisonEnd();
    }

    /*
     * No longer eating?
     */
    if (changes.has("eating")) {
      onStopEating();
    }

    /*
     * No longer choking?
     */
    if (changes.has("choking")) {
      onStopChoking();
    }

    if (changes.has("ghostmode")) {
      ghostmode = false;
      fireChange(PROP_GHOSTMODE);
    }

    /*
     * Attack target gone?
     */
    if (changes.has("target")) {
      onStopAttack();

      if (attackTarget != null) {
        attackTarget.onStopAttacked(this);
        attackTarget = null;
      }
    }
  }

  //
  //

  public static class TextIndicator {
    /**
     * The age of the message (in ms).
     */
    protected int age;

    /**
     * The message text.
     */
    protected String text;

    /**
     * The indicator type.
     */
    protected NotificationType type;

    /**
     * Create a floating message.
     *
     * @param text
     *            The text to drawn.
     * @param type
     *            The indicator type.
     */
    public TextIndicator(final String text, final NotificationType type) {
      this.text = text;
      this.type = type;

      age = 0;
    }

    //
    // TextIndicator
    //

    /**
     * Add to the age of this message.
     *
     * @param time
     *            The amout to add.
     *
     * @return The new age (in milliseconds).
     */
    public int addAge(final int time) {
      age += time;

      return age;
    }

    /**
     * Get the age of this message.
     *
     * @return The age (in milliseconds).
     */
    public int getAge() {
      return age;
    }

    /**
     * Get the text message.
     *
     * @return The text message.
     */
    public String getText() {
      return text;
    }

    /**
     * Get the indicator type.
     *
     * @return The indicator type.
     */
    public NotificationType getType() {
      return type;
    }
  }
}
TOP

Related Classes of games.stendhal.client.entity.RPEntity$TextIndicator

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.