diff --git a/README.md b/README.md index 0d30e89..bcd3504 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,33 @@ Tell Level which BentoBox game modes it should connect to. - **Sum Team Deaths** – Choose whether to track team deaths or just the leader's. - **Reset on Island Reset / Team Join** – Wipe the death count when teams change or islands are reset. +### 📐 Level Calculation Formula + +The `level-calc` setting in `config.yml` controls how island levels are computed. It supports the following variables: + +| Variable | Description | +|---|---| +| `blocks` | The total block value points for the island, minus any death penalty | +| `level_cost` | The value of one island level (see `levelcost` setting) | +| `island_members` | The number of members currently on the island team | + +The formula can use `+`, `-`, `*`, `/`, `^`, `sqrt`, `sin`, `cos`, `tan`, and `log` (natural log). The result is rounded to the nearest whole number. + +**Default formula:** `blocks / level_cost` + +**Handicap (fairness) example:** To divide the island level equally per member so solo islands remain competitive with larger teams, use: + +```yaml +level-calc: "blocks / level_cost / island_members" +``` + +With this formula and the default `level_cost` of `100`, a block worth 100 points would contribute the following to the **island level**: +- **0.25 levels** per block on an island with 4 members (100 / 100 / 4 = 0.25) +- **0.33 levels** per block on an island with 3 members (100 / 100 / 3 ≈ 0.33) +- **1 level** per block on a solo island (100 / 100 / 1 = 1) + +This makes competition fairer between solo players and large teams. + ### 🚫 Block Limits Cap the number of specific blocks that count toward level (e.g., only 200 DIAMOND_BLOCKs count). diff --git a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java index a7425eb..cbb35c1 100644 --- a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java +++ b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java @@ -136,8 +136,11 @@ private long calculateLevel(final long rawPoints) { long modifiedPoints = rawPoints - (addon.getSettings().isZeroNewIslandLevels() ? results.initialCount.get() : 0); // Paste in the values to the formula - String withValues = calcString.replace("blocks", String.valueOf(modifiedPoints)).replace("level_cost", - String.valueOf(this.addon.getSettings().getLevelCost())); + // Use Math.max(1, ...) to prevent division by zero if island_members is used in the formula + int memberCount = Math.max(1, this.island.getMemberSet().size()); + String withValues = calcString.replace("island_members", String.valueOf(memberCount)) + .replace("blocks", String.valueOf(modifiedPoints)) + .replace("level_cost", String.valueOf(this.addon.getSettings().getLevelCost())); // Try and evaluate it try { return (long) EquationEvaluator.eval(withValues); @@ -252,6 +255,7 @@ private List getReport() { reportLines.add("Total block value count = " + String.format("%,d", results.rawBlockCount.get())); reportLines.add("Formula to calculate island level: " + addon.getSettings().getLevelCalc()); reportLines.add("Level cost = " + addon.getSettings().getLevelCost()); + reportLines.add("Island members = " + island.getMemberSet().size()); reportLines.add("Deaths handicap = " + results.deathHandicap.get()); /* if (addon.getSettings().isZeroNewIslandLevels()) { diff --git a/src/main/java/world/bentobox/level/config/ConfigSettings.java b/src/main/java/world/bentobox/level/config/ConfigSettings.java index f5b16b3..f7879a3 100644 --- a/src/main/java/world/bentobox/level/config/ConfigSettings.java +++ b/src/main/java/world/bentobox/level/config/ConfigSettings.java @@ -98,8 +98,10 @@ public class ConfigSettings implements ConfigObject { @ConfigComment("Island level calculation formula") @ConfigComment("blocks - the sum total of all block values, less any death penalty") @ConfigComment("level_cost - in a linear equation, the value of one level") + @ConfigComment("island_members - the number of members on the island team (useful for handicap/fairness systems)") @ConfigComment("This formula can include +,=,*,/,sqrt,^,sin,cos,tan,log (natural log). Result will always be rounded to a long integer") @ConfigComment("for example, an alternative non-linear option could be: 3 * sqrt(blocks / level_cost)") + @ConfigComment("To implement a handicap by team size: blocks / level_cost / island_members") @ConfigEntry(path = "level-calc") private String levelCalc = "blocks / level_cost";