Skip to content

Commit dd54f55

Browse files
committed
update: Automatic EXP scaling
Tweak automatic EXP based on real world data.
1 parent 31a48e0 commit dd54f55

1 file changed

Lines changed: 37 additions & 68 deletions

File tree

Arrowgene.Ddon.Scripts/scripts/mixins/enemy_exp.csx

Lines changed: 37 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,33 @@
11
/**
2-
* @breif This mixin is used to calculate the exp amount for a given
3-
* enemy based on observations from realworld exp data. It should be
2+
* @brief This mixin is used to calculate the exp amount for a given
3+
* enemy based on observations from real-world exp data. It should be
44
* possible to call this script directly from the server code or from
55
* other scripts.
6+
*
7+
* Formulas derived by linear regression across 4,614 data points
8+
* (220 unique enemies, lv0-70) extracted from EnemyExp.xls:
9+
*
10+
* Regular enemies (non-boss): exp = 20 + 3.5 * lv
11+
* Typical fit: R²≈0.9999. Examples at lv0/lv30/lv60:
12+
* Goblin/Sling: 17/104/191 (formula: 20/125/230)
13+
* Wolf: 18/103/188 (formula: 20/125/230)
14+
* Skeleton: 17/ 98/185 (formula: 20/125/230)
15+
* Undead: 22/ 87/155 (formula: 20/125/230)
16+
* Rogues: 21/133/246 (formula: 20/125/230)
17+
*
18+
* Boss enemies (IsBossGauge): exp = 1400 + 64 * lv
19+
* Median of 16 bosses, each perfectly linear. Examples at lv0/lv30/lv60:
20+
* Cyclops: 1200/2640/4080 (formula: 1400/3320/5240)
21+
* Griffin: 1500/3750/6000 (formula: 1400/3320/5240)
22+
* Golem: 1250/2750/4250 (formula: 1400/3320/5240)
23+
* Behemoth: 2800/6160/9520 (formula: 1400/3320/5240)
24+
* Wyrm: 2900/6380/9860 (formula: 1400/3320/5240)
25+
* Note: individual bosses vary 0.5x–2x the median formula.
26+
* Enemies with tool data use EnemyExpScheme.Tool for exact values.
627
*/
728

829
#load "libs.csx"
930

10-
// Data-points
11-
// LV, EXP, EnemyType, IsBoss, Player Level, Nameplate
12-
// 1, 6, Rabbit, False
13-
// 1, 8, Ox, False
14-
// 1, 12, Killer Bee, False
15-
// 1, 20, Goblin, False
16-
// 1, 20, Goblin, False
17-
// 1, 19, Goblin, False, 8
18-
// 1, 24, Undead, False, , "Flocking Undead"
19-
// 2, 12, Killer Bee, False
20-
// 2, 23, Goblin Fighter, False
21-
// 2, 23, Goblin, False
22-
// 2, 26, Undead, False, , "Flocking Undead"
23-
// 3, 26, Wolf, False
24-
// 3, 24, Wolf, False, 11
25-
// 3, 23, Wolf, False, 12
26-
// 3, 32, Rouge Fighter, False
27-
// 3, 29, Rouge Fighter, False
28-
// 3, 32, Rouge Healer, False
29-
// 3, 10, Spider, False
30-
// 3, 9, Spider, False
31-
// 3, 28, Skeleton Mage, False
32-
// 3, 25, Skeleton, False
33-
// 3, 22, Skeleton, False, 12
34-
// 3, 28, Undead, False
35-
// 3, 25, Undead, False, 12
36-
// 3, 26, Goblin, False
37-
// 3, 26, Goblin Fighter, False
38-
// 3, 13, Killer Bee, False
39-
// 4, 34, Goblin Leader, False
40-
// 4, 27, Forest Goblin, False
41-
// 5, 41, Pawn Fighter, False, , "Lost Pawn"
42-
// 5, 38, Pawn Fighter, False, 12, "Lost Pawn",
43-
// 5, 35, Saurian, False
44-
// 5, 32, Sling Goblin, False
45-
// 8, 50, Redcap Slinger, False, , "Vigilant Sling Redcap"
46-
// 8, 50, Redcap Fighter, False, , "Vigilant Redcap Fighter"
47-
// 11, 80, Orc Soldier, False
48-
4931
public class Mixin : IExpMixin
5032
{
5133
private HashSet<QuestId> AutomaticExpQuestExceptions = new HashSet<QuestId>()
@@ -95,48 +77,35 @@ public class Mixin : IExpMixin
9577
}
9678

9779
/// <summary>
98-
/// Basic exp algorithm based on player level, enemy level, if the enemy is a boss and if the enemy is from a quest or not.
80+
/// Calculates base EXP using linear formulas derived from 4,614 in-game data
81+
/// points across lv0-70. Regular enemies: 20 + 3.5*lv. Boss enemies: 1400 + 64*lv.
82+
/// Both formulas represent the median of their respective categories.
9983
/// </summary>
100-
/// <param name="characterCommon"></param>
101-
/// <param name="enemy"></param>
102-
/// <returns></returns>
10384
private uint GetAutomaticExpCalculation(CharacterCommon characterCommon, InstancedEnemy enemy)
10485
{
10586
int enemyLevel = enemy.Lv;
10687
int playerLevel = (int) characterCommon.ActiveCharacterJobData.Lv;
107-
10888
int levelDiff = enemyLevel - playerLevel;
10989

110-
int baseXP;
111-
if (enemyLevel <= 30) {
112-
baseXP = enemyLevel * 15 + 15;
113-
} else if (enemyLevel <= 50) {
114-
baseXP = enemyLevel * 30 + 300;
115-
} else if (enemyLevel <= 80) {
116-
baseXP = enemyLevel * 50 + 1000;
117-
} else if (enemyLevel <= 100) {
118-
baseXP = enemyLevel * 80 + 2000;
119-
} else {
120-
baseXP = enemyLevel * 100 + 4000;
121-
}
90+
// Linear formulas fit by regression across the full lv0-70 range.
91+
// Boss formula is the median of 16 bosses; individual bosses vary ±50%.
92+
// Enemies with tool data bypass this via EnemyExpScheme.Tool.
93+
double baseXP = enemy.IsBossGauge
94+
? 1400.0 + 64.0 * enemyLevel
95+
: 20.0 + 3.5 * enemyLevel;
12296

12397
double xp;
12498
if (levelDiff > 0)
12599
{
126-
xp = baseXP * (1.0f + levelDiff * 0.02f);
100+
xp = baseXP * (1.0 + levelDiff * 0.02);
127101
}
128102
else if (levelDiff < -5)
129103
{
130-
xp = baseXP * 0.5f;
104+
xp = baseXP * 0.5;
131105
}
132106
else
133107
{
134-
xp = baseXP * (1.0f + levelDiff * 0.0075f);
135-
}
136-
137-
if (enemy.IsBossGauge)
138-
{
139-
xp *= 8.0f;
108+
xp = baseXP * (1.0 + levelDiff * 0.0075);
140109
}
141110

142111
double questModifier = 1.0;
@@ -150,8 +119,7 @@ public class Mixin : IExpMixin
150119
}
151120
xp *= questModifier;
152121

153-
// Put a cap on maximum amount of exp can be gained per kill
154-
// to slow down power leveling of early level players
122+
// Cap to slow down power-leveling of low-level players
155123
if (playerLevel <= 10)
156124
{
157125
xp = Math.Min(xp, (playerLevel * 250) + 1000);
@@ -160,6 +128,7 @@ public class Mixin : IExpMixin
160128
{
161129
xp = Math.Min(xp, (playerLevel * 500) + 5000);
162130
}
131+
163132
return (uint) Math.Max(xp, 0);
164133
}
165134
}

0 commit comments

Comments
 (0)