Package com.github.zathrus_writer.commandsex.helpers

Source Code of com.github.zathrus_writer.commandsex.helpers.ExperienceManager

package com.github.zathrus_writer.commandsex.helpers;

import java.util.Arrays;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;


/**
* @author desht
*
* Adapted from ExperienceUtils code originally in ScrollingMenuSign.
*
* Credit to nisovin (http://forums.bukkit.org/threads/experienceutils-make-giving-taking-exp-a-bit-more-intuitive.54450/#post-1067480)
* for an implementation that avoids the problems of getTotalExperience(), which doesn't work properly after a player has enchanted something.
*/
public class ExperienceManager {
  // this is to stop the lookup tables growing without control
  private static int hardMaxLevel = 100000;
 
  private static int xpRequiredForNextLevel[];
  private static int xpTotalToReachLevel[];

  private final String playerName;

  static {
    // 25 is an arbitrary value for the initial table size - the actual value isn't critically
    // important since the tables are resized as needed.
    initLookupTables(25);
  }

  public static int getHardMaxLevel() {
    return hardMaxLevel;
  }

  public static void setHardMaxLevel(int hardMaxLevel) {
    ExperienceManager.hardMaxLevel = hardMaxLevel;
  }

  /**
   * Initialise the XP lookup tables.  Basing this on observations noted in https://bukkit.atlassian.net/browse/BUKKIT-47
   *
   * 7 xp to get to level 1, 17 to level 2, 31 to level 3...
   * At each level, the increment to get to the next level increases alternately by 3 and 4
   *
   * @param maxLevel  The highest level handled by the lookup tables
   */
  private static void initLookupTables(int maxLevel) {
    xpRequiredForNextLevel = new int[maxLevel];
    xpTotalToReachLevel = new int[maxLevel];

    xpTotalToReachLevel[0] = 0;
//     Code valid for MC 1.2 and earlier
//    int incr = 7;
//    for (int i = 1; i < xpTotalToReachLevel.length; i++) {
//      xpRequiredForNextLevel[i - 1] = incr;
//      xpTotalToReachLevel[i] = xpTotalToReachLevel[i - 1] + incr;
//      incr += (i % 2 == 0) ? 4 : 3;
//    }
   
    // Valid for MC 1.3 and later
    int incr = 17;
    for (int i = 1; i < xpTotalToReachLevel.length; i++) {
      xpRequiredForNextLevel[i - 1] = incr;
      xpTotalToReachLevel[i] = xpTotalToReachLevel[i - 1] + incr;
      if (i >= 30) {
        incr += 7;
      } else if (i >= 16) {
        incr += 3;
      }
    }
    xpRequiredForNextLevel[xpRequiredForNextLevel.length - 1] = incr;
  }

  /**
   * Calculate the level that the given XP quantity corresponds to, without using the lookup tables.
   * This is needed if getLevelForExp() is called with an XP quantity beyond the range of the existing
   * lookup tables.
   *
   * @param exp
   * @return
   */
  private static int calculateLevelForExp(int exp) {
    int level = 0;
    int curExp = 7// level 1
    int incr = 10;
    while (curExp <= exp) {
      curExp += incr;
      level++;
      incr += (level % 2 == 0) ? 3 : 4;
    }
    return level;
  }

  /**
   * Create a new ExperienceManager for the given player.
   *
   * @param player  The player for this ExperienceManager object
   */
  public ExperienceManager(Player player) {
    this.playerName = player.getName();
    getPlayer()// ensure it's a valid player name
  }

  /**
   * Get the Player associated with this ExperienceManager.
   *
   * @return  the Player object
   * @throws IllegalStateException if the player is no longer online
   */
  public Player getPlayer() {
    Player p = Bukkit.getPlayer(playerName);
    if (p == null) {
      throw new IllegalStateException("Player " + playerName + " is not online");
    }
    return p;
  }

  /**
   * Adjust the player's XP by the given amount in an intelligent fashion.  Works around
   * some of the non-intuitive behaviour of the basic Bukkit player.giveExp() method.
   *  
   * @param amt    Amount of XP, may be negative
   */
  public void changeExp(int amt) {
    setExp(getCurrentExp(), amt);
  }

  /**
   * Set the player's experience
   *
   * @param amt        Amount of XP, should not be negative
   */
  public void setExp(int amt) {
    setExp(0, amt);
  }

  private void setExp(int base, int amt) {
    int xp = base + amt;
    if (xp < 0) xp = 0;

    Player player = getPlayer();
    int curLvl = player.getLevel();
    int newLvl = getLevelForExp(xp);
    if (curLvl != newLvl) {
      player.setLevel(newLvl);
    }

    float pct = ((float)(xp - getXpForLevel(newLvl)) / (float)xpRequiredForNextLevel[newLvl]);
    player.setExp(pct);
  }

  /**
   * Get the player's current XP total.
   *
   * @return  the player's total XP
   */
  public int getCurrentExp() {
    Player player = getPlayer();
    int lvl = player.getLevel();
    int cur = getXpForLevel(lvl) + (int) Math.round(xpRequiredForNextLevel[lvl] * player.getExp());
    return cur;
  }

  /**
   * Checks if the player has the given amount of XP.
   *
   * @param amt  The amount to check for.
   * @return    true if the player has enough XP, false otherwise
   */
  public boolean hasExp(int amt) {
    return getCurrentExp() >= amt;
  }

  /**
   * Get the level that the given amount of XP falls within.
   *
   * @param exp  The amount to check for.
   * @return    The level that a player with this amount total XP would be.
   */
  public int getLevelForExp(int exp) {
    if (exp <= 0) return 0;
    if (exp > xpTotalToReachLevel[xpTotalToReachLevel.length - 1]) {
      // need to extend the lookup tables
      int newMax = calculateLevelForExp(exp) * 2;
      if (newMax > hardMaxLevel) {
        throw new IllegalArgumentException("Level for exp " + exp + " > hard max level " + hardMaxLevel);
      }
      initLookupTables(newMax);
    }
    int pos = Arrays.binarySearch(xpTotalToReachLevel, exp);
    return pos < 0 ? -pos - 2 : pos;
  }

  /**
   * Return the total XP needed to be the given level.
   *
   * @param level  The level to check for.
   * @return  The amount of XP needed for the level.
   */
  public int getXpForLevel(int level) {
    if (level > hardMaxLevel) {
      throw new IllegalArgumentException("Level " + level + " > hard max level " + hardMaxLevel);
    }
   
    if (level >= xpTotalToReachLevel.length) {
      initLookupTables(level * 2);
    }
    return xpTotalToReachLevel[level];
  }
}
TOP

Related Classes of com.github.zathrus_writer.commandsex.helpers.ExperienceManager

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.