Skip to content

Commit

Permalink
Experience command with offline players
Browse files Browse the repository at this point in the history
also modernizen
  • Loading branch information
mcmonkey4eva committed Oct 23, 2022
1 parent 64a6074 commit 8a3181a
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 73 deletions.
Expand Up @@ -524,6 +524,51 @@ public void setFoodLevel(int foodLevel) {
}
}

public float getExp() {
if (isOnline()) {
return getPlayerEntity().getExp();
}
else {
return getNBTEditor().getExp();
}
}

public void setExp(float xp) {
if (isOnline()) {
getPlayerEntity().setExp(xp);
}
else {
getNBTEditor().setExp(xp);
}
}

public int getTotalExperience() {
if (isOnline()) {
return getPlayerEntity().getTotalExperience();
}
else {
return getNBTEditor().getTotalExperience();
}
}

public void setTotalExperience(int xp) {
if (isOnline()) {
getPlayerEntity().setTotalExperience(xp);
}
else {
getNBTEditor().setTotalExperience(xp);
}
}

public int getLevel() {
if (isOnline()) {
return getPlayerEntity().getLevel();
}
else {
return getNBTEditor().getLevel();
}
}

public void setLevel(int level) {
if (isOnline()) {
getPlayerEntity().setLevel(level);
Expand Down Expand Up @@ -2131,30 +2176,33 @@ else if (foodLevel / maxHunger < 1) {
// @returns ElementTag(Number)
// @description
// Returns the calculated total amount of XP the player has, based on the amount of experience needed per level, for each level the player has.
// Works with offline players.
// -->
registerOnlineOnlyTag(ElementTag.class, "calculate_xp", (attribute, object) -> {
int level = object.getPlayerEntity().getLevel();
return new ElementTag(ExperienceCommand.TOTAL_XP_FOR_LEVEL(level) + (object.getPlayerEntity().getExp() * ExperienceCommand.XP_FOR_NEXT_LEVEL(level)));
registerOfflineTag(ElementTag.class, "calculate_xp", (attribute, object) -> {
int level = object.getLevel();
return new ElementTag(ExperienceCommand.TOTAL_XP_FOR_LEVEL(level) + (object.getExp() * ExperienceCommand.XP_FOR_NEXT_LEVEL(level)));
});

// <--[tag]
// @attribute <PlayerTag.xp_level>
// @returns ElementTag(Number)
// @description
// Returns the number of XP levels the player has.
// Works with offline players.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp_level", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getLevel());
registerOfflineTag(ElementTag.class, "xp_level", (attribute, object) -> {
return new ElementTag(object.getLevel());
});

// <--[tag]
// @attribute <PlayerTag.xp_to_next_level>
// @returns ElementTag(Number)
// @description
// Returns the amount of XP the player needs to get to the next level.
// Works with offline players.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp_to_next_level", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getExpToLevel());
registerOfflineTag(ElementTag.class, "xp_to_next_level", (attribute, object) -> {
return new ElementTag(ExperienceCommand.XP_FOR_NEXT_LEVEL(object.getLevel()));
});

// <--[tag]
Expand All @@ -2164,9 +2212,10 @@ else if (foodLevel / maxHunger < 1) {
// Returns the total amount of experience points the player has.
// This is how much XP the player has ever received, not a current value.
// To get the current total, use <@link tag PlayerTag.calculate_xp>.
// Works with offline players.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp_total", (attribute, object) -> {
return new ElementTag(object.getPlayerEntity().getTotalExperience());
registerOfflineTag(ElementTag.class, "xp_total", (attribute, object) -> {
return new ElementTag(object.getTotalExperience());
});

// <--[tag]
Expand All @@ -2175,23 +2224,23 @@ else if (foodLevel / maxHunger < 1) {
// @description
// Returns the percentage of experience points to the next level.
// -->
registerOnlineOnlyTag(ElementTag.class, "xp", (attribute, object) -> {
registerOfflineTag(ElementTag.class, "xp", (attribute, object) -> {
if (attribute.startsWith("level", 2)) {
BukkitImplDeprecations.playerXpTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getLevel());
return new ElementTag(object.getLevel());
}
if (attribute.startsWith("to_next_level", 2)) {
BukkitImplDeprecations.playerXpTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getExpToLevel());
return new ElementTag(ExperienceCommand.XP_FOR_NEXT_LEVEL(object.getLevel()));
}
if (attribute.startsWith("total", 2)) {
BukkitImplDeprecations.playerXpTags.warn(attribute.context);
attribute.fulfill(1);
return new ElementTag(object.getPlayerEntity().getTotalExperience());
return new ElementTag(object.getTotalExperience());
}
return new ElementTag(object.getPlayerEntity().getExp() * 100);
return new ElementTag(object.getExp() * 100);
});

// <--[tag]
Expand Down
@@ -1,36 +1,37 @@
package com.denizenscript.denizen.scripts.commands.player;

import com.denizenscript.denizen.objects.PlayerTag;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsException;
import com.denizenscript.denizencore.objects.Argument;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException;
import com.denizenscript.denizencore.scripts.commands.generator.ArgLinear;
import com.denizenscript.denizencore.scripts.commands.generator.ArgName;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.AbstractCommand;
import org.bukkit.entity.Player;

public class ExperienceCommand extends AbstractCommand {

public ExperienceCommand() {
setName("experience");
setSyntax("experience [{set}/give/take] (level) [<#>]");
setSyntax("experience [set/give/take] (level) [<#>]");
setRequiredArguments(2, 3);
isProcedural = false;
autoCompile();
}

// <--[command]
// @Name Experience
// @Syntax experience [{set}/give/take] (level) [<#>]
// @Syntax experience [set/give/take] (level) [<#>]
// @Required 2
// @Maximum 3
// @Short Gives or takes experience points to the player.
// @Group player
//
// @Description
// This command allows modification of a players experience points.
//
// Experience can be modified in terms of XP points, or by levels.
// Note that the "set" command does not affect levels, but xp bar fullness.
// (E.g. setting experience to 0 will not change a players level, but will
// set the players experience bar to 0)
//
// This command works with offline players, but using it on online players is safer.
//
// @Tags
// <PlayerTag.xp>
Expand All @@ -39,23 +40,23 @@ public ExperienceCommand() {
// <PlayerTag.xp_level>
//
// @Usage
// Use to set a player's experience bar to 0.
// Use to set a player's total experience to 0.
// - experience set 0
//
// @Usage
// Use give give a player 1 level.
// Use to give a player 1 level.
// - experience give level 1
//
// @Usage
// Use to take 1 level from a player.
//
// - experience take level 1
//
// @Usage
// Use to give a player with the name steve 10 experience points.
// - experience give 10 player:<[someplayer]>
// -->

private enum Type {SET, GIVE, TAKE}
public enum Type {SET, GIVE, TAKE}

public static int XP_FOR_NEXT_LEVEL(int level) {
return level >= 30 ? 112 + (level - 30) * 9 : (level >= 15 ? 37 + (level - 15) * 5 : 7 + level * 2);
Expand All @@ -69,71 +70,57 @@ public static long TOTAL_XP_FOR_LEVEL(int level) {
return count;
}

public static void setTotalExperience(Player player, int exp) {
public static void setTotalExperience(PlayerTag player, int exp) {
player.setTotalExperience(0);
player.setLevel(0);
player.setExp(0);
player.giveExp(exp);
giveExperiencePoints(player, exp);
}

public static void giveExperiencePoints(PlayerTag player, int amount) {
if (player.isOnline()) {
player.getPlayerEntity().giveExp(amount);
return;
}
int level = player.getLevel();
float xp = player.getExp() + (float)amount / (float)XP_FOR_NEXT_LEVEL(level);
while(xp >= 1.0F) {
xp = (xp - 1.0F) * (float)XP_FOR_NEXT_LEVEL(level);
level++;
xp /= (float)XP_FOR_NEXT_LEVEL(level);
}
player.setTotalExperience(Math.min(player.getTotalExperience() + amount, Integer.MAX_VALUE));
player.setExp(xp);
player.setLevel(level);
}

public static void takeExperience(Player player, int toTake) {
int pastLevelStart = (int) (player.getExp() * player.getExpToLevel());
public static void takeExperience(PlayerTag player, int toTake) {
int pastLevelStart = (int) (player.getExp() * XP_FOR_NEXT_LEVEL(player.getLevel()));
while (toTake >= pastLevelStart) {
toTake -= pastLevelStart;
player.setExp(0);
if (player.getLevel() == 0) {
return;
}
player.setLevel(player.getLevel() - 1);
pastLevelStart = player.getExpToLevel();
pastLevelStart = XP_FOR_NEXT_LEVEL(player.getLevel());
}
int newAmount = pastLevelStart - toTake;
player.setExp(newAmount / (float) player.getExpToLevel());
}

@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {
int amount = 0;
Type type = Type.SET;
boolean level = false;
boolean silent = false;
for (Argument arg : scriptEntry) {
if (arg.matchesInteger()) {
amount = arg.asElement().asInt();
}
else if (arg.matches("set", "give", "take")) {
type = Type.valueOf(arg.asElement().asString().toUpperCase());
}
else if (arg.matches("level")) {
level = true;
}
else if (arg.matches("silent")) {
silent = true;
}
else {
arg.reportUnhandled();
}
}
scriptEntry.addObject("quantity", amount)
.addObject("type", type)
.addObject("level", level)
.addObject("silent", silent);
player.setExp(newAmount / (float) XP_FOR_NEXT_LEVEL(player.getLevel()));
}

@Override
public void execute(ScriptEntry scriptEntry) {
Type type = (Type) scriptEntry.getObject("type");
int quantity = (int) scriptEntry.getObject("quantity");
Boolean level = (Boolean) scriptEntry.getObject("level");
//Boolean silent = (Boolean) scriptEntry.getObject("silent");
if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, name, db("type", type.toString()), db("quantity", level ? quantity + " levels" : quantity), db("player", Utilities.getEntryPlayer(scriptEntry)));
public static void autoExecute(ScriptEntry scriptEntry,
@ArgName("type") Type type,
@ArgName("level") boolean level,
@ArgLinear @ArgName("quantity") int quantity) {
PlayerTag player = Utilities.getEntryPlayer(scriptEntry);
if (player == null) {
throw new InvalidArgumentsRuntimeException("The Experience command requires a linked player.");
}
Player player = Utilities.getEntryPlayer(scriptEntry).getPlayerEntity();
switch (type) {
case SET:
if (level) {
Utilities.getEntryPlayer(scriptEntry).setLevel(quantity);
player.setLevel(quantity);
}
else {
setTotalExperience(player, quantity);
Expand All @@ -144,7 +131,7 @@ public void execute(ScriptEntry scriptEntry) {
player.setLevel(player.getLevel() + quantity);
}
else {
player.giveExp(quantity);
giveExperiencePoints(player, quantity);
}
break;
case TAKE:
Expand Down

0 comments on commit 8a3181a

Please sign in to comment.