Compute XP thresholds from the client formula instead of the LevelToExp table

Client ArcCharacter_ExpForLevelUp (0x4715D0): XP to reach level L is
(L-1)^3 * max(1, 1 + (L-40) * 0.0512f) * class * race rune_exp_req_to_level,
rounded half up. getLevel steps levels with it up to LEVELCAP. Both methods
now take the PlayerCharacter so the factors come from its runes; the CSR
promotions 2901+ have no rune and use the base class factor.

Same values: every player race is 10 and every class rune 15, and the formula
equals the removed table for all 76 levels. Levels above the table no longer
use the old approximate fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MagicBotandClaude Opus 5.5 committed 2026-10-23 11:42:52 -04:00
1 parent db67e56302
commit 0c7b6f6c46
2 files changed
+55 -135

No files matched your search

+14 -14
View File
@@ -1267,7 +1267,7 @@ public class PlayerCharacter extends AbstractCharacter {
player.endLoc = Vector3fImmutable.ZERO;
//get level based on experience
player.level = (short) Experience.getLevel(player.exp);
player.level = (short) Experience.getLevel(player, player.exp);
player.setHealth(999999f);
player.mana.set(999999f);
@@ -2828,7 +2828,7 @@ public class PlayerCharacter extends AbstractCharacter {
}
public short getPCLevel() {
short level = (short) Experience.getLevel(this.exp);
short level = (short) Experience.getLevel(this, this.exp);
if (this.promotionClass == null && level >= 10)
return (short) 10;
@@ -2873,8 +2873,8 @@ public class PlayerCharacter extends AbstractCharacter {
public synchronized void grantXP(int xp) {
// Stop players from getting experience past the cap
if (this.exp + xp >= Experience.getBaseExperience(MBServerStatics.LEVELCAP))
xp = Experience.getBaseExperience(MBServerStatics.LEVELCAP) - this.exp + 1;
if (this.exp + xp >= Experience.getBaseExperience(this, MBServerStatics.LEVELCAP))
xp = Experience.getBaseExperience(this, MBServerStatics.LEVELCAP) - this.exp + 1;
if (xp == 0)
xp = 1;
@@ -2890,7 +2890,7 @@ public class PlayerCharacter extends AbstractCharacter {
//not promoted at level 10, start checking for negative EXP
if (this.promotionClass == null && this.getLevel() == 10) {
if (this.getExp() == Experience.getBaseExperience(11)) {
if (this.getExp() == Experience.getBaseExperience(this, 11)) {
if (this.overFlowEXP == 110000)
return;
@@ -2913,10 +2913,10 @@ public class PlayerCharacter extends AbstractCharacter {
} else {
//Player exp begins negative exp, add remaing exp after level 11 to overflow
if (this.getExp() + remainingXP >= Experience.getBaseExperience(11)) {
if (this.getExp() + remainingXP >= Experience.getBaseExperience(this, 11)) {
this.overFlowEXP = remainingXP - (Experience.getBaseExperience(11) - this.getExp());
this.exp = Experience.getBaseExperience(11);
this.overFlowEXP = remainingXP - (Experience.getBaseExperience(this, 11) - this.getExp());
this.exp = Experience.getBaseExperience(this, 11);
GrantExperienceMsg grantExperienceMsg = new GrantExperienceMsg(this, remainingXP);
Dispatch dispatch = Dispatch.borrow(this, grantExperienceMsg);
@@ -2948,7 +2948,7 @@ public class PlayerCharacter extends AbstractCharacter {
else
nextLevel = level + 2;
int nextLevelEXP = Experience.getBaseExperience(nextLevel);
int nextLevelEXP = Experience.getBaseExperience(this, nextLevel);
// if overflow > 0, u have level 11 experience + overflow, but level is still 10 due to just promoting.
//Use level + 2 experience for next level.
@@ -2971,8 +2971,8 @@ public class PlayerCharacter extends AbstractCharacter {
checkGuildStatus();
this.addDatabaseJob("EXP", MBServerStatics.FIVE_MINUTES);
// double overflow exp used up, remaining overflow will just add to level + 1.
} else if (this.getExp() + this.overFlowEXP >= Experience.getBaseExperience(level + 1)) {
int nextExperience = Experience.getBaseExperience(level + 1) + this.overFlowEXP;
} else if (this.getExp() + this.overFlowEXP >= Experience.getBaseExperience(this, level + 1)) {
int nextExperience = Experience.getBaseExperience(this, level + 1) + this.overFlowEXP;
this.exp = nextExperience;
this.level++;
charReloadRequired = true;
@@ -2988,10 +2988,10 @@ public class PlayerCharacter extends AbstractCharacter {
} else {
// Hand out each Level one at a time.
isNewLevel = Experience.getLevel(exp + remainingXP) > this.getLevel();
isNewLevel = Experience.getLevel(this, exp + remainingXP) > this.getLevel();
if (isNewLevel) {
neededXP = Experience.getBaseExperience(this.getLevel() + 1) - this.exp;
neededXP = Experience.getBaseExperience(this, this.getLevel() + 1) - this.exp;
charReloadRequired = true;
this.exp += neededXP;
@@ -4088,7 +4088,7 @@ public class PlayerCharacter extends AbstractCharacter {
tmpLevel = (short) Math.min(tmpLevel, 75);
while (this.level < tmpLevel) {
grantXP(Experience.getBaseExperience(tmpLevel) - this.exp);
grantXP(Experience.getBaseExperience(this, tmpLevel) - this.exp);
}
}