diff --git a/src/main/kotlin/network/warzone/mars/Mars.kt b/src/main/kotlin/network/warzone/mars/Mars.kt index 3d1ee43..de4914d 100644 --- a/src/main/kotlin/network/warzone/mars/Mars.kt +++ b/src/main/kotlin/network/warzone/mars/Mars.kt @@ -25,6 +25,7 @@ import network.warzone.mars.player.PlayerManager import network.warzone.mars.player.achievements.AchievementManager import network.warzone.mars.player.decoration.PrefixDecorationProvider import network.warzone.mars.player.feature.PlayerService +import network.warzone.mars.player.models.PlayerStats import network.warzone.mars.player.tablist.overrideTabManager import org.bukkit.Bukkit import org.bukkit.event.Listener @@ -72,6 +73,8 @@ class Mars : JavaPlugin() { ApiClient.loadHttp(apiConfigurationSection) ApiClient.loadSocket(serverId, apiConfigurationSection) + PlayerStats.useExponentialExp(config.getBoolean("server.exponential-exp", false)) + MatchManager.init() BukkitIntake(this@Mars, commandGraph).register() diff --git a/src/main/kotlin/network/warzone/mars/player/commands/StatCommands.kt b/src/main/kotlin/network/warzone/mars/player/commands/StatCommands.kt index cd9f566..2d07375 100644 --- a/src/main/kotlin/network/warzone/mars/player/commands/StatCommands.kt +++ b/src/main/kotlin/network/warzone/mars/player/commands/StatCommands.kt @@ -13,6 +13,8 @@ import network.warzone.mars.match.tracker.KillstreakTracker import network.warzone.mars.player.feature.LevelColorService import network.warzone.mars.player.feature.PlayerFeature import network.warzone.mars.player.models.PlayerProfile +import network.warzone.mars.player.models.PlayerStats +import network.warzone.mars.utils.getLevelAsComponent import network.warzone.mars.utils.matchPlayer import network.warzone.mars.utils.strategy.multiLine import org.bukkit.Bukkit @@ -20,6 +22,7 @@ import org.bukkit.ChatColor import org.bukkit.entity.Player import tc.oc.pgm.api.player.MatchPlayer import javax.annotation.Nullable +import kotlin.math.roundToInt class StatCommands { @@ -80,7 +83,7 @@ class StatCommands { LevelColorService.chatColorFromLevel(stats.level) ) } - .appendMultiLine { createLabelledStat("XP", stats.xp, StatType.NEUTRAL) } + .appendMultiLine { createLabelledStat("XP", formatXPProgress(stats.xp), StatType.NEUTRAL) } .appendMultiLine { empty() } .appendMultiLine { createLabelledStat("Kills", stats.kills, StatType.POSITIVE) } .appendMultiLine { createLabelledStat("First Bloods", stats.firstBloods, StatType.POSITIVE) } @@ -103,6 +106,13 @@ class StatCommands { NEUTRAL(NamedTextColor.AQUA) } + private fun formatXPProgress(xp: Int) : String { + val level = PlayerStats.EXP_FORMULA.getLevelFromExp(xp.toDouble()) + val nextLevel = level + 1 + val nextLevelExpRequirement = PlayerStats.EXP_FORMULA.getExpRequiredForLevel(nextLevel) + return "${xp}/${nextLevelExpRequirement.roundToInt()}" + } + private fun createLabelledStat(label: String, value: Any, type: StatType): Component { return text() .append { space() } diff --git a/src/main/kotlin/network/warzone/mars/player/models/PlayerProfile.kt b/src/main/kotlin/network/warzone/mars/player/models/PlayerProfile.kt index 951cf38..f530eeb 100644 --- a/src/main/kotlin/network/warzone/mars/player/models/PlayerProfile.kt +++ b/src/main/kotlin/network/warzone/mars/player/models/PlayerProfile.kt @@ -14,6 +14,7 @@ import tc.oc.pgm.api.map.Gamemode import java.text.NumberFormat import java.util.* import kotlin.math.floor +import kotlin.math.pow data class PlayerProfile( @@ -93,8 +94,49 @@ data class PlayerStats( val killstreaks: MutableMap = mutableMapOf(5 to 0, 10 to 0, 25 to 0, 50 to 0, 100 to 0), val achievements: MutableMap = mutableMapOf() ) { + + companion object { + interface ExpFormula { + fun getLevelFromExp(exp: Double) : Int + fun getExpRequiredForLevel(level: Int) : Double + } + + class PowerExpFormula( + private val linearFactor: Double, + private val growthFactor: Double + ) : ExpFormula { + override fun getLevelFromExp(exp: Double): Int = + floor(linearFactor * exp.pow(growthFactor)).toInt() + 1 + + override fun getExpRequiredForLevel(level: Int) : Double { + if (level <= 1) return 0.0 + return (((level - 1).toDouble())/(linearFactor)).pow(1.0/growthFactor) + } + } + + class LinearExpFormula( + private val step: Int + ) : ExpFormula { + override fun getLevelFromExp(exp: Double): Int = + floor(((exp + step) / step).toDouble()).toInt() + + override fun getExpRequiredForLevel(level: Int) : Double { + if (level <= 1) return 0.0 + return ((level * step) - step).toDouble() + } + } + + private val LINEAR_FORMULA = LinearExpFormula(5000) + private val EXPONENTIAL_FORMULA = PowerExpFormula(0.0056, 0.715) + var EXP_FORMULA : ExpFormula = LINEAR_FORMULA + private set + + fun useExponentialExp(use: Boolean) { + EXP_FORMULA = if (use) EXPONENTIAL_FORMULA else LINEAR_FORMULA + } + } val level: Int - get() = floor(((xp + 5000) / 5000).toDouble()).toInt() + get() = EXP_FORMULA.getLevelFromExp(xp.toDouble()) val winPercentage: String get() { @@ -149,4 +191,4 @@ data class PlayerObjectiveStatistics( var controlPointCaptures: Int = 0 ) -data class PlayerMessages(var staff: Int = 0, var global: Int = 0, var team: Int = 0) \ No newline at end of file +data class PlayerMessages(var staff: Int = 0, var global: Int = 0, var team: Int = 0)