diff --git a/documentation/DocumentationTest.DignityShopPriceDocumentation.approved.md b/documentation/DocumentationTest.DignityShopPriceDocumentation.approved.md
new file mode 100644
index 0000000..8f576d6
--- /dev/null
+++ b/documentation/DocumentationTest.DignityShopPriceDocumentation.approved.md
@@ -0,0 +1,7 @@
+# Dignity Shop Price Table
+- Default - Price: x1
+- Dubious - Price: x1
+- Dreadful - Price: x1.1
+- Unqualified - Price: x1.2
+- Useless - Price: x1.5
+- Failed - Price: x1.5
diff --git a/documentation/DocumentationTest.ExperienceShareDocumentation.approved.md b/documentation/DocumentationTest.ExperienceShareDocumentation.approved.md
new file mode 100644
index 0000000..d1084ab
--- /dev/null
+++ b/documentation/DocumentationTest.ExperienceShareDocumentation.approved.md
@@ -0,0 +1,4 @@
+# Group Experience Share Table
+- 1 member(s) - XP: 100.00 % Job XP: 100.00 %
+- 2 member(s) - XP: 57.50 % Job XP: 62.50 %
+- 3 member(s) - XP: 43.33 % Job XP: 50.00 %
diff --git a/documentation/DocumentationTest.LevelPenaltyDocumentation.approved.md b/documentation/DocumentationTest.LevelPenaltyDocumentation.approved.md
new file mode 100644
index 0000000..4711e00
--- /dev/null
+++ b/documentation/DocumentationTest.LevelPenaltyDocumentation.approved.md
@@ -0,0 +1,42 @@
+# Level Penalty Table
+- Player -5 level(s) above the monster - XP: x1 Gold: x1
+- Player -4 level(s) above the monster - XP: x1 Gold: x1
+- Player -3 level(s) above the monster - XP: x1 Gold: x1
+- Player -2 level(s) above the monster - XP: x1 Gold: x1
+- Player -1 level(s) above the monster - XP: x1 Gold: x1
+- Player 0 level(s) above the monster - XP: x1 Gold: x1
+- Player 1 level(s) above the monster - XP: x1 Gold: x1
+- Player 2 level(s) above the monster - XP: x1 Gold: x1
+- Player 3 level(s) above the monster - XP: x1 Gold: x1
+- Player 4 level(s) above the monster - XP: x1 Gold: x1
+- Player 5 level(s) above the monster - XP: x1 Gold: x0.9
+- Player 6 level(s) above the monster - XP: x0.9 Gold: x0.7
+- Player 7 level(s) above the monster - XP: x0.7 Gold: x0.5
+- Player 8 level(s) above the monster - XP: x0.5 Gold: x0.3
+- Player 9 level(s) above the monster - XP: x0.3 Gold: x0.2
+- Player 10 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 11 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 12 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 13 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 14 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 15 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 16 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 17 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 18 level(s) above the monster - XP: x0.1 Gold: x0.1
+- Player 19 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 20 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 21 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 22 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 23 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 24 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 25 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 26 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 27 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 28 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 29 level(s) above the monster - XP: x0.1 Gold: x0.05
+- Player 30 level(s) above the monster - XP: x0.1 Gold: x0
+- Player 31 level(s) above the monster - XP: x0.1 Gold: x0
+- Player 32 level(s) above the monster - XP: x0.1 Gold: x0
+- Player 33 level(s) above the monster - XP: x0.1 Gold: x0
+- Player 34 level(s) above the monster - XP: x0.1 Gold: x0
+- Player 35 level(s) above the monster - XP: x0.1 Gold: x0
diff --git a/documentation/DocumentationTest.RarityPointDocumentation.approved.md b/documentation/DocumentationTest.RarityPointDocumentation.approved.md
new file mode 100644
index 0000000..9a174b7
--- /dev/null
+++ b/documentation/DocumentationTest.RarityPointDocumentation.approved.md
@@ -0,0 +1,242 @@
+# Rarity Point Table
+## Rarity -2
+- Item level 0- 4 - Points: -4
+- Item level 5- 9 - Points: -8
+- Item level 10-14 - Points: -12
+- Item level 15-19 - Points: -16
+- Item level 20-24 - Points: -20
+- Item level 25-29 - Points: -24
+- Item level 30-34 - Points: -28
+- Item level 35-39 - Points: -32
+- Item level 40-44 - Points: -36
+- Item level 45-49 - Points: -40
+- Item level 50-54 - Points: -44
+- Item level 55-59 - Points: -48
+- Item level 60-64 - Points: -52
+- Item level 65-69 - Points: -56
+- Item level 70-74 - Points: -60
+- Item level 75-79 - Points: -64
+- Item level 80-84 - Points: -68
+- Item level 85-89 - Points: -72
+- Item level 90-94 - Points: -76
+- Item level 95-99 - Points: -80
+
+## Rarity -1
+- Item level 0- 4 - Points: -2
+- Item level 5- 9 - Points: -4
+- Item level 10-14 - Points: -6
+- Item level 15-19 - Points: -8
+- Item level 20-24 - Points: -10
+- Item level 25-29 - Points: -12
+- Item level 30-34 - Points: -14
+- Item level 35-39 - Points: -16
+- Item level 40-44 - Points: -18
+- Item level 45-49 - Points: -20
+- Item level 50-54 - Points: -22
+- Item level 55-59 - Points: -24
+- Item level 60-64 - Points: -26
+- Item level 65-69 - Points: -28
+- Item level 70-74 - Points: -30
+- Item level 75-79 - Points: -32
+- Item level 80-84 - Points: -34
+- Item level 85-89 - Points: -36
+- Item level 90-94 - Points: -38
+- Item level 95-99 - Points: -40
+
+## Rarity 0
+- Item level 0- 4 - Points: 0
+- Item level 5- 9 - Points: 0
+- Item level 10-14 - Points: 0
+- Item level 15-19 - Points: 0
+- Item level 20-24 - Points: 0
+- Item level 25-29 - Points: 0
+- Item level 30-34 - Points: 0
+- Item level 35-39 - Points: 0
+- Item level 40-44 - Points: 0
+- Item level 45-49 - Points: 0
+- Item level 50-54 - Points: 0
+- Item level 55-59 - Points: 0
+- Item level 60-64 - Points: 0
+- Item level 65-69 - Points: 0
+- Item level 70-74 - Points: 0
+- Item level 75-79 - Points: 0
+- Item level 80-84 - Points: 0
+- Item level 85-89 - Points: 0
+- Item level 90-94 - Points: 0
+- Item level 95-99 - Points: 0
+
+## Rarity 1
+- Item level 0- 4 - Points: 1
+- Item level 5- 9 - Points: 2
+- Item level 10-14 - Points: 3
+- Item level 15-19 - Points: 4
+- Item level 20-24 - Points: 5
+- Item level 25-29 - Points: 6
+- Item level 30-34 - Points: 7
+- Item level 35-39 - Points: 8
+- Item level 40-44 - Points: 9
+- Item level 45-49 - Points: 10
+- Item level 50-54 - Points: 11
+- Item level 55-59 - Points: 12
+- Item level 60-64 - Points: 13
+- Item level 65-69 - Points: 14
+- Item level 70-74 - Points: 15
+- Item level 75-79 - Points: 16
+- Item level 80-84 - Points: 17
+- Item level 85-89 - Points: 18
+- Item level 90-94 - Points: 19
+- Item level 95-99 - Points: 20
+
+## Rarity 2
+- Item level 0- 4 - Points: 2
+- Item level 5- 9 - Points: 4
+- Item level 10-14 - Points: 6
+- Item level 15-19 - Points: 8
+- Item level 20-24 - Points: 10
+- Item level 25-29 - Points: 12
+- Item level 30-34 - Points: 14
+- Item level 35-39 - Points: 16
+- Item level 40-44 - Points: 18
+- Item level 45-49 - Points: 20
+- Item level 50-54 - Points: 22
+- Item level 55-59 - Points: 24
+- Item level 60-64 - Points: 26
+- Item level 65-69 - Points: 28
+- Item level 70-74 - Points: 30
+- Item level 75-79 - Points: 32
+- Item level 80-84 - Points: 34
+- Item level 85-89 - Points: 36
+- Item level 90-94 - Points: 38
+- Item level 95-99 - Points: 40
+
+## Rarity 3
+- Item level 0- 4 - Points: 3
+- Item level 5- 9 - Points: 6
+- Item level 10-14 - Points: 9
+- Item level 15-19 - Points: 12
+- Item level 20-24 - Points: 15
+- Item level 25-29 - Points: 18
+- Item level 30-34 - Points: 21
+- Item level 35-39 - Points: 24
+- Item level 40-44 - Points: 27
+- Item level 45-49 - Points: 30
+- Item level 50-54 - Points: 33
+- Item level 55-59 - Points: 36
+- Item level 60-64 - Points: 39
+- Item level 65-69 - Points: 42
+- Item level 70-74 - Points: 45
+- Item level 75-79 - Points: 48
+- Item level 80-84 - Points: 51
+- Item level 85-89 - Points: 54
+- Item level 90-94 - Points: 57
+- Item level 95-99 - Points: 60
+
+## Rarity 4
+- Item level 0- 4 - Points: 4
+- Item level 5- 9 - Points: 8
+- Item level 10-14 - Points: 12
+- Item level 15-19 - Points: 16
+- Item level 20-24 - Points: 20
+- Item level 25-29 - Points: 24
+- Item level 30-34 - Points: 28
+- Item level 35-39 - Points: 32
+- Item level 40-44 - Points: 36
+- Item level 45-49 - Points: 40
+- Item level 50-54 - Points: 44
+- Item level 55-59 - Points: 48
+- Item level 60-64 - Points: 52
+- Item level 65-69 - Points: 56
+- Item level 70-74 - Points: 60
+- Item level 75-79 - Points: 64
+- Item level 80-84 - Points: 68
+- Item level 85-89 - Points: 72
+- Item level 90-94 - Points: 76
+- Item level 95-99 - Points: 80
+
+## Rarity 5
+- Item level 0- 4 - Points: 5
+- Item level 5- 9 - Points: 10
+- Item level 10-14 - Points: 15
+- Item level 15-19 - Points: 20
+- Item level 20-24 - Points: 25
+- Item level 25-29 - Points: 30
+- Item level 30-34 - Points: 35
+- Item level 35-39 - Points: 40
+- Item level 40-44 - Points: 45
+- Item level 45-49 - Points: 50
+- Item level 50-54 - Points: 55
+- Item level 55-59 - Points: 60
+- Item level 60-64 - Points: 65
+- Item level 65-69 - Points: 70
+- Item level 70-74 - Points: 75
+- Item level 75-79 - Points: 80
+- Item level 80-84 - Points: 85
+- Item level 85-89 - Points: 90
+- Item level 90-94 - Points: 95
+- Item level 95-99 - Points: 100
+
+## Rarity 6
+- Item level 0- 4 - Points: 7
+- Item level 5- 9 - Points: 14
+- Item level 10-14 - Points: 21
+- Item level 15-19 - Points: 28
+- Item level 20-24 - Points: 35
+- Item level 25-29 - Points: 42
+- Item level 30-34 - Points: 49
+- Item level 35-39 - Points: 56
+- Item level 40-44 - Points: 63
+- Item level 45-49 - Points: 70
+- Item level 50-54 - Points: 77
+- Item level 55-59 - Points: 84
+- Item level 60-64 - Points: 91
+- Item level 65-69 - Points: 98
+- Item level 70-74 - Points: 105
+- Item level 75-79 - Points: 112
+- Item level 80-84 - Points: 119
+- Item level 85-89 - Points: 126
+- Item level 90-94 - Points: 133
+- Item level 95-99 - Points: 140
+
+## Rarity 7
+- Item level 0- 4 - Points: 10
+- Item level 5- 9 - Points: 20
+- Item level 10-14 - Points: 30
+- Item level 15-19 - Points: 40
+- Item level 20-24 - Points: 50
+- Item level 25-29 - Points: 60
+- Item level 30-34 - Points: 70
+- Item level 35-39 - Points: 80
+- Item level 40-44 - Points: 90
+- Item level 45-49 - Points: 100
+- Item level 50-54 - Points: 110
+- Item level 55-59 - Points: 120
+- Item level 60-64 - Points: 130
+- Item level 65-69 - Points: 140
+- Item level 70-74 - Points: 150
+- Item level 75-79 - Points: 160
+- Item level 80-84 - Points: 170
+- Item level 85-89 - Points: 180
+- Item level 90-94 - Points: 190
+- Item level 95-99 - Points: 200
+
+## Rarity 8
+- Item level 0- 4 - Points: 15
+- Item level 5- 9 - Points: 30
+- Item level 10-14 - Points: 45
+- Item level 15-19 - Points: 60
+- Item level 20-24 - Points: 75
+- Item level 25-29 - Points: 90
+- Item level 30-34 - Points: 105
+- Item level 35-39 - Points: 120
+- Item level 40-44 - Points: 135
+- Item level 45-49 - Points: 150
+- Item level 50-54 - Points: 165
+- Item level 55-59 - Points: 180
+- Item level 60-64 - Points: 195
+- Item level 65-69 - Points: 210
+- Item level 70-74 - Points: 225
+- Item level 75-79 - Points: 240
+- Item level 80-84 - Points: 255
+- Item level 85-89 - Points: 270
+- Item level 90-94 - Points: 285
+- Item level 95-99 - Points: 300
diff --git a/documentation/DocumentationTest.SpecialistPointDocumentation.approved.md b/documentation/DocumentationTest.SpecialistPointDocumentation.approved.md
new file mode 100644
index 0000000..585894e
--- /dev/null
+++ b/documentation/DocumentationTest.SpecialistPointDocumentation.approved.md
@@ -0,0 +1,204 @@
+# Specialist Point Table
+## Points by level (+0)
+- Level 1 - Points: 0
+- Level 2 - Points: 0
+- Level 3 - Points: 0
+- Level 4 - Points: 0
+- Level 5 - Points: 0
+- Level 6 - Points: 0
+- Level 7 - Points: 0
+- Level 8 - Points: 0
+- Level 9 - Points: 0
+- Level 10 - Points: 0
+- Level 11 - Points: 0
+- Level 12 - Points: 0
+- Level 13 - Points: 0
+- Level 14 - Points: 0
+- Level 15 - Points: 0
+- Level 16 - Points: 0
+- Level 17 - Points: 0
+- Level 18 - Points: 0
+- Level 19 - Points: 0
+- Level 20 - Points: 0
+- Level 21 - Points: 3
+- Level 22 - Points: 6
+- Level 23 - Points: 9
+- Level 24 - Points: 12
+- Level 25 - Points: 15
+- Level 26 - Points: 18
+- Level 27 - Points: 21
+- Level 28 - Points: 24
+- Level 29 - Points: 27
+- Level 30 - Points: 30
+- Level 31 - Points: 33
+- Level 32 - Points: 36
+- Level 33 - Points: 39
+- Level 34 - Points: 42
+- Level 35 - Points: 45
+- Level 36 - Points: 48
+- Level 37 - Points: 51
+- Level 38 - Points: 54
+- Level 39 - Points: 57
+- Level 40 - Points: 60
+- Level 41 - Points: 63
+- Level 42 - Points: 66
+- Level 43 - Points: 69
+- Level 44 - Points: 72
+- Level 45 - Points: 75
+- Level 46 - Points: 78
+- Level 47 - Points: 81
+- Level 48 - Points: 84
+- Level 49 - Points: 87
+- Level 50 - Points: 90
+- Level 51 - Points: 93
+- Level 52 - Points: 96
+- Level 53 - Points: 99
+- Level 54 - Points: 102
+- Level 55 - Points: 105
+- Level 56 - Points: 108
+- Level 57 - Points: 111
+- Level 58 - Points: 114
+- Level 59 - Points: 117
+- Level 60 - Points: 120
+- Level 61 - Points: 123
+- Level 62 - Points: 126
+- Level 63 - Points: 129
+- Level 64 - Points: 132
+- Level 65 - Points: 135
+- Level 66 - Points: 138
+- Level 67 - Points: 141
+- Level 68 - Points: 144
+- Level 69 - Points: 147
+- Level 70 - Points: 150
+- Level 71 - Points: 153
+- Level 72 - Points: 156
+- Level 73 - Points: 159
+- Level 74 - Points: 162
+- Level 75 - Points: 165
+- Level 76 - Points: 168
+- Level 77 - Points: 171
+- Level 78 - Points: 174
+- Level 79 - Points: 177
+- Level 80 - Points: 180
+- Level 81 - Points: 183
+- Level 82 - Points: 186
+- Level 83 - Points: 189
+- Level 84 - Points: 192
+- Level 85 - Points: 195
+- Level 86 - Points: 198
+- Level 87 - Points: 201
+- Level 88 - Points: 204
+- Level 89 - Points: 207
+- Level 90 - Points: 210
+- Level 91 - Points: 213
+- Level 92 - Points: 216
+- Level 93 - Points: 219
+- Level 94 - Points: 222
+- Level 95 - Points: 225
+- Level 96 - Points: 228
+- Level 97 - Points: 231
+- Level 98 - Points: 234
+- Level 99 - Points: 237
+
+## Points at level 99 by upgrade
+- +0 - Points: 237
+- +1 - Points: 242
+- +2 - Points: 247
+- +3 - Points: 252
+- +4 - Points: 257
+- +5 - Points: 265
+- +6 - Points: 273
+- +7 - Points: 283
+- +8 - Points: 293
+- +9 - Points: 305
+- +10 - Points: 317
+- +11 - Points: 332
+- +12 - Points: 347
+- +13 - Points: 365
+- +14 - Points: 385
+- +15 - Points: 410
+
+## Stat level by points spent
+- 0 points - Attack: 0 Defence: 0 Element: 0 HP/MP: 0
+- 5 points - Attack: 5 Defence: 5 Element: 5 HP/MP: 5
+- 10 points - Attack: 10 Defence: 10 Element: 10 HP/MP: 10
+- 15 points - Attack: 12 Defence: 12 Element: 15 HP/MP: 12
+- 20 points - Attack: 15 Defence: 15 Element: 20 HP/MP: 15
+- 25 points - Attack: 17 Defence: 17 Element: 22 HP/MP: 17
+- 30 points - Attack: 19 Defence: 20 Element: 25 HP/MP: 20
+- 35 points - Attack: 21 Defence: 22 Element: 27 HP/MP: 22
+- 40 points - Attack: 23 Defence: 25 Element: 30 HP/MP: 25
+- 45 points - Attack: 24 Defence: 27 Element: 31 HP/MP: 27
+- 50 points - Attack: 26 Defence: 29 Element: 33 HP/MP: 30
+- 55 points - Attack: 28 Defence: 31 Element: 35 HP/MP: 31
+- 60 points - Attack: 29 Defence: 33 Element: 36 HP/MP: 33
+- 65 points - Attack: 31 Defence: 34 Element: 38 HP/MP: 35
+- 70 points - Attack: 33 Defence: 36 Element: 40 HP/MP: 36
+- 75 points - Attack: 34 Defence: 38 Element: 41 HP/MP: 38
+- 80 points - Attack: 36 Defence: 39 Element: 42 HP/MP: 40
+- 85 points - Attack: 38 Defence: 41 Element: 43 HP/MP: 41
+- 90 points - Attack: 39 Defence: 42 Element: 45 HP/MP: 43
+- 95 points - Attack: 40 Defence: 43 Element: 46 HP/MP: 45
+- 100 points - Attack: 42 Defence: 44 Element: 47 HP/MP: 46
+- 105 points - Attack: 43 Defence: 46 Element: 48 HP/MP: 48
+- 110 points - Attack: 44 Defence: 47 Element: 50 HP/MP: 50
+- 115 points - Attack: 45 Defence: 48 Element: 51 HP/MP: 51
+- 120 points - Attack: 47 Defence: 49 Element: 52 HP/MP: 52
+- 125 points - Attack: 48 Defence: 51 Element: 53 HP/MP: 53
+- 130 points - Attack: 49 Defence: 52 Element: 54 HP/MP: 55
+- 135 points - Attack: 50 Defence: 53 Element: 55 HP/MP: 56
+- 140 points - Attack: 52 Defence: 54 Element: 56 HP/MP: 57
+- 145 points - Attack: 53 Defence: 56 Element: 57 HP/MP: 58
+- 150 points - Attack: 54 Defence: 57 Element: 58 HP/MP: 60
+- 155 points - Attack: 55 Defence: 58 Element: 59 HP/MP: 61
+- 160 points - Attack: 57 Defence: 59 Element: 60 HP/MP: 62
+- 165 points - Attack: 58 Defence: 60 Element: 61 HP/MP: 63
+- 170 points - Attack: 59 Defence: 61 Element: 62 HP/MP: 64
+- 175 points - Attack: 60 Defence: 62 Element: 63 HP/MP: 65
+- 180 points - Attack: 61 Defence: 63 Element: 64 HP/MP: 66
+- 185 points - Attack: 62 Defence: 64 Element: 65 HP/MP: 67
+- 190 points - Attack: 63 Defence: 65 Element: 66 HP/MP: 68
+- 195 points - Attack: 64 Defence: 66 Element: 67 HP/MP: 69
+- 200 points - Attack: 65 Defence: 67 Element: 68 HP/MP: 70
+- 205 points - Attack: 66 Defence: 68 Element: 69 HP/MP: 70
+- 210 points - Attack: 67 Defence: 69 Element: 70 HP/MP: 71
+- 215 points - Attack: 68 Defence: 70 Element: 70 HP/MP: 72
+- 220 points - Attack: 69 Defence: 71 Element: 71 HP/MP: 73
+- 225 points - Attack: 70 Defence: 72 Element: 72 HP/MP: 74
+- 230 points - Attack: 71 Defence: 73 Element: 73 HP/MP: 75
+- 235 points - Attack: 72 Defence: 74 Element: 74 HP/MP: 75
+- 240 points - Attack: 73 Defence: 75 Element: 75 HP/MP: 76
+- 245 points - Attack: 74 Defence: 76 Element: 75 HP/MP: 77
+- 250 points - Attack: 75 Defence: 77 Element: 76 HP/MP: 78
+- 255 points - Attack: 76 Defence: 78 Element: 77 HP/MP: 79
+- 260 points - Attack: 77 Defence: 79 Element: 78 HP/MP: 80
+- 265 points - Attack: 78 Defence: 79 Element: 79 HP/MP: 80
+- 270 points - Attack: 79 Defence: 80 Element: 80 HP/MP: 81
+- 275 points - Attack: 80 Defence: 81 Element: 80 HP/MP: 82
+- 280 points - Attack: 81 Defence: 82 Element: 81 HP/MP: 82
+- 285 points - Attack: 81 Defence: 83 Element: 82 HP/MP: 83
+- 290 points - Attack: 82 Defence: 84 Element: 82 HP/MP: 84
+- 295 points - Attack: 83 Defence: 84 Element: 83 HP/MP: 85
+- 300 points - Attack: 84 Defence: 85 Element: 84 HP/MP: 85
+- 305 points - Attack: 85 Defence: 86 Element: 85 HP/MP: 86
+- 310 points - Attack: 86 Defence: 86 Element: 85 HP/MP: 87
+- 315 points - Attack: 86 Defence: 87 Element: 86 HP/MP: 87
+- 320 points - Attack: 87 Defence: 88 Element: 87 HP/MP: 88
+- 325 points - Attack: 88 Defence: 89 Element: 87 HP/MP: 89
+- 330 points - Attack: 89 Defence: 89 Element: 88 HP/MP: 90
+- 335 points - Attack: 90 Defence: 90 Element: 89 HP/MP: 90
+- 340 points - Attack: 90 Defence: 91 Element: 90 HP/MP: 91
+- 345 points - Attack: 91 Defence: 91 Element: 90 HP/MP: 91
+- 350 points - Attack: 92 Defence: 92 Element: 91 HP/MP: 92
+- 355 points - Attack: 93 Defence: 93 Element: 92 HP/MP: 93
+- 360 points - Attack: 93 Defence: 94 Element: 92 HP/MP: 93
+- 365 points - Attack: 94 Defence: 94 Element: 93 HP/MP: 94
+- 370 points - Attack: 95 Defence: 95 Element: 94 HP/MP: 95
+- 375 points - Attack: 95 Defence: 95 Element: 95 HP/MP: 95
+- 380 points - Attack: 96 Defence: 96 Element: 95 HP/MP: 96
+- 385 points - Attack: 97 Defence: 97 Element: 96 HP/MP: 96
+- 390 points - Attack: 97 Defence: 97 Element: 97 HP/MP: 97
+- 395 points - Attack: 98 Defence: 98 Element: 97 HP/MP: 98
+- 400 points - Attack: 99 Defence: 99 Element: 98 HP/MP: 98
+- 405 points - Attack: 99 Defence: 99 Element: 99 HP/MP: 99
+- 410 points - Attack: 100 Defence: 100 Element: 100 HP/MP: 100
diff --git a/src/NosCore.Algorithm/Constants.cs b/src/NosCore.Algorithm/Constants.cs
index a1abcd4..1d90315 100644
--- a/src/NosCore.Algorithm/Constants.cs
+++ b/src/NosCore.Algorithm/Constants.cs
@@ -11,6 +11,7 @@ internal class Constants
internal const byte MaxHeroLevel = 60;
internal const byte MaxMateLevel = 99;
internal const byte MaxFamilyLevel = 30;
+ internal const byte MaxGroupSize = 3;
internal static readonly int ClassCount = Enum.GetNames(typeof(CharacterClassType)).Length;
}
}
diff --git a/src/NosCore.Algorithm/DignityService/DignityService.cs b/src/NosCore.Algorithm/DignityService/DignityService.cs
index a3cf03f..f3e02b5 100644
--- a/src/NosCore.Algorithm/DignityService/DignityService.cs
+++ b/src/NosCore.Algorithm/DignityService/DignityService.cs
@@ -58,5 +58,21 @@ public DignityType GetLevelFromDignity(short dignity)
{
return (level == DignityType.Default ? (short)200 : (short)(_dignityData[level - 1] - 1), _dignityData[level]);
}
+
+ ///
+ /// Gets the multiplier applied to NPC shop prices for a dignity level
+ ///
+ /// The buyer's dignity level type
+ /// The price multiplier
+ public double GetShopPriceMultiplier(DignityType level)
+ {
+ return level switch
+ {
+ DignityType.Dreadful => 1.1,
+ DignityType.Unqualified => 1.2,
+ DignityType.Useless or DignityType.Failed => 1.5,
+ _ => 1
+ };
+ }
}
}
diff --git a/src/NosCore.Algorithm/DignityService/IDignityService.cs b/src/NosCore.Algorithm/DignityService/IDignityService.cs
index 47c36d3..8d89494 100644
--- a/src/NosCore.Algorithm/DignityService/IDignityService.cs
+++ b/src/NosCore.Algorithm/DignityService/IDignityService.cs
@@ -26,5 +26,12 @@ public interface IDignityService
/// The dignity level type
/// A tuple containing the maximum and minimum dignity values for the level
(short, short) GetDignity(DignityType level);
+
+ ///
+ /// Gets the multiplier applied to NPC shop prices for a dignity level
+ ///
+ /// The buyer's dignity level type
+ /// The price multiplier
+ double GetShopPriceMultiplier(DignityType level);
}
}
\ No newline at end of file
diff --git a/src/NosCore.Algorithm/ExperienceShareService/ExperienceShareService.cs b/src/NosCore.Algorithm/ExperienceShareService/ExperienceShareService.cs
new file mode 100644
index 0000000..b0bda96
--- /dev/null
+++ b/src/NosCore.Algorithm/ExperienceShareService/ExperienceShareService.cs
@@ -0,0 +1,39 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+namespace NosCore.Algorithm.ExperienceShareService
+{
+ ///
+ /// Provides the experience split of a group
+ ///
+ ///
+ /// Each extra member adds 15% experience and 25% job experience to the kill, and the total
+ /// is divided equally: 100%, 57.5% and 43.33% each for experience, 100%, 62.5% and 50% each
+ /// for job experience.
+ ///
+ public class ExperienceShareService : IExperienceShareService
+ {
+ private const double ExperienceBonusPerMember = 0.15;
+ private const double JobExperienceBonusPerMember = 0.25;
+
+ ///
+ public double GetExperienceShare(byte memberCount) => Share(memberCount, ExperienceBonusPerMember);
+
+ ///
+ public double GetJobExperienceShare(byte memberCount) => Share(memberCount, JobExperienceBonusPerMember);
+
+ private static double Share(byte memberCount, double bonusPerMember)
+ {
+ var members = memberCount switch
+ {
+ 0 => 1,
+ > Constants.MaxGroupSize => Constants.MaxGroupSize,
+ _ => memberCount
+ };
+ return (1 + bonusPerMember * (members - 1)) / members;
+ }
+ }
+}
diff --git a/src/NosCore.Algorithm/ExperienceShareService/IExperienceShareService.cs b/src/NosCore.Algorithm/ExperienceShareService/IExperienceShareService.cs
new file mode 100644
index 0000000..7860c09
--- /dev/null
+++ b/src/NosCore.Algorithm/ExperienceShareService/IExperienceShareService.cs
@@ -0,0 +1,28 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+namespace NosCore.Algorithm.ExperienceShareService
+{
+ ///
+ /// Service for splitting monster experience between the members of a group
+ ///
+ public interface IExperienceShareService
+ {
+ ///
+ /// Gets the share of a monster's experience each member receives
+ ///
+ /// The number of group members sharing the kill
+ /// The fraction of the monster's experience given to each member
+ double GetExperienceShare(byte memberCount);
+
+ ///
+ /// Gets the share of a monster's job experience each member receives
+ ///
+ /// The number of group members sharing the kill
+ /// The fraction of the monster's job experience given to each member
+ double GetJobExperienceShare(byte memberCount);
+ }
+}
diff --git a/src/NosCore.Algorithm/LevelPenaltyService/ILevelPenaltyService.cs b/src/NosCore.Algorithm/LevelPenaltyService/ILevelPenaltyService.cs
new file mode 100644
index 0000000..8700306
--- /dev/null
+++ b/src/NosCore.Algorithm/LevelPenaltyService/ILevelPenaltyService.cs
@@ -0,0 +1,30 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+namespace NosCore.Algorithm.LevelPenaltyService
+{
+ ///
+ /// Service for reducing the rewards of monsters far below the player's level
+ ///
+ public interface ILevelPenaltyService
+ {
+ ///
+ /// Gets the multiplier applied to the experience of a monster
+ ///
+ /// The level the experience is for (level, job level or hero level)
+ /// The monster's level
+ /// A multiplier between 0 and 1
+ double GetExperiencePenalty(byte playerLevel, byte monsterLevel);
+
+ ///
+ /// Gets the multiplier applied to the chance of a monster dropping gold
+ ///
+ /// The player's level
+ /// The monster's level
+ /// A multiplier between 0 and 1
+ double GetGoldPenalty(byte playerLevel, byte monsterLevel);
+ }
+}
diff --git a/src/NosCore.Algorithm/LevelPenaltyService/LevelPenaltyService.cs b/src/NosCore.Algorithm/LevelPenaltyService/LevelPenaltyService.cs
new file mode 100644
index 0000000..08f9b00
--- /dev/null
+++ b/src/NosCore.Algorithm/LevelPenaltyService/LevelPenaltyService.cs
@@ -0,0 +1,45 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+namespace NosCore.Algorithm.LevelPenaltyService
+{
+ ///
+ /// Provides the reward multipliers for killing a monster below the player's level
+ ///
+ public class LevelPenaltyService : ILevelPenaltyService
+ {
+ ///
+ public double GetExperiencePenalty(byte playerLevel, byte monsterLevel)
+ {
+ return (playerLevel - monsterLevel) switch
+ {
+ <= 5 => 1,
+ 6 => 0.9,
+ 7 => 0.7,
+ 8 => 0.5,
+ 9 => 0.3,
+ _ => 0.1
+ };
+ }
+
+ ///
+ public double GetGoldPenalty(byte playerLevel, byte monsterLevel)
+ {
+ return (playerLevel - monsterLevel) switch
+ {
+ <= 4 => 1,
+ 5 => 0.9,
+ 6 => 0.7,
+ 7 => 0.5,
+ 8 => 0.3,
+ 9 => 0.2,
+ <= 18 => 0.1,
+ <= 29 => 0.05,
+ _ => 0
+ };
+ }
+ }
+}
diff --git a/src/NosCore.Algorithm/RarityPointService/IRarityPointService.cs b/src/NosCore.Algorithm/RarityPointService/IRarityPointService.cs
new file mode 100644
index 0000000..49d72a2
--- /dev/null
+++ b/src/NosCore.Algorithm/RarityPointService/IRarityPointService.cs
@@ -0,0 +1,22 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+namespace NosCore.Algorithm.RarityPointService
+{
+ ///
+ /// Service for the stat points an equipment's rarity adds
+ ///
+ public interface IRarityPointService
+ {
+ ///
+ /// Gets the points an item of a given rarity and level adds to its stats
+ ///
+ /// The item's rarity
+ /// The item's level
+ /// The rarity points
+ int GetRarityPoint(sbyte rarity, byte itemLevel);
+ }
+}
diff --git a/src/NosCore.Algorithm/RarityPointService/RarityPointService.cs b/src/NosCore.Algorithm/RarityPointService/RarityPointService.cs
new file mode 100644
index 0000000..813bac0
--- /dev/null
+++ b/src/NosCore.Algorithm/RarityPointService/RarityPointService.cs
@@ -0,0 +1,31 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+namespace NosCore.Algorithm.RarityPointService
+{
+ ///
+ /// Provides the rarity points of equipment
+ ///
+ ///
+ /// Each rarity has a base value that is multiplied by one plus a fifth of the item level.
+ ///
+ public class RarityPointService : IRarityPointService
+ {
+ ///
+ public int GetRarityPoint(sbyte rarity, byte itemLevel)
+ {
+ var points = rarity switch
+ {
+ >= 0 and <= 5 => rarity,
+ 6 => 7,
+ 7 => 10,
+ 8 => 15,
+ _ => rarity * 2
+ };
+ return points * (itemLevel / 5 + 1);
+ }
+ }
+}
diff --git a/src/NosCore.Algorithm/SpecialistPointService/ISpecialistPointService.cs b/src/NosCore.Algorithm/SpecialistPointService/ISpecialistPointService.cs
new file mode 100644
index 0000000..bd2d245
--- /dev/null
+++ b/src/NosCore.Algorithm/SpecialistPointService/ISpecialistPointService.cs
@@ -0,0 +1,50 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+namespace NosCore.Algorithm.SpecialistPointService
+{
+ ///
+ /// Service for the skill points of a specialist card and the stats they buy
+ ///
+ public interface ISpecialistPointService
+ {
+ ///
+ /// Gets the skill points a specialist card has to spend
+ ///
+ /// The card's level
+ /// The card's upgrade (+0 to +15)
+ /// The points available
+ int GetSpecialistPoints(byte specialistLevel, byte upgrade);
+
+ ///
+ /// Gets the attack level bought with the points spent on attack
+ ///
+ /// The points spent
+ /// The attack level
+ int GetAttackLevel(short points);
+
+ ///
+ /// Gets the defence level bought with the points spent on defence
+ ///
+ /// The points spent
+ /// The defence level
+ int GetDefenceLevel(short points);
+
+ ///
+ /// Gets the element level bought with the points spent on element
+ ///
+ /// The points spent
+ /// The element level
+ int GetElementLevel(short points);
+
+ ///
+ /// Gets the HP/MP level bought with the points spent on HP/MP
+ ///
+ /// The points spent
+ /// The HP/MP level
+ int GetHpMpLevel(short points);
+ }
+}
diff --git a/src/NosCore.Algorithm/SpecialistPointService/SpecialistPointService.cs b/src/NosCore.Algorithm/SpecialistPointService/SpecialistPointService.cs
new file mode 100644
index 0000000..c8d841c
--- /dev/null
+++ b/src/NosCore.Algorithm/SpecialistPointService/SpecialistPointService.cs
@@ -0,0 +1,74 @@
+// __ _ __ __ ___ __ ___ ___
+// | \| |/__\ /' _/ / _//__\| _ \ __|
+// | | ' | \/ |`._`.| \_| \/ | v / _|
+// |_|\__|\__/ |___/ \__/\__/|_|_\___|
+// -----------------------------------
+
+using System;
+
+namespace NosCore.Algorithm.SpecialistPointService
+{
+ ///
+ /// Provides specialist card skill points and the stat levels they buy
+ ///
+ ///
+ /// A card earns 3 points per level above 20, plus a bonus for its upgrade. Each stat is
+ /// bought in bands: the first points buy one level each, later bands cost 2, 3, ... points
+ /// per level, and the stat stops at the level reached with all the points a card can earn.
+ ///
+ public class SpecialistPointService : ISpecialistPointService
+ {
+ private static readonly int[] UpgradeBonus = [0, 5, 10, 15, 20, 28, 36, 46, 56, 68, 80, 95, 110, 128, 148, 173];
+
+ private static readonly (short UpTo, int Cost)[] AttackBands =
+ [(10, 1), (28, 2), (88, 3), (168, 4), (268, 5), (334, 6), (383, 7), (391, 8), (400, 9), (410, 10)];
+
+ // A 360-400 band that starts at level 97 instead of 94 is sometimes seen; it would make
+ // 400 points worth more than 410, so the band is taken to continue from 94 like the others.
+ private static readonly (short UpTo, int Cost)[] DefenceBands =
+ [(10, 1), (48, 2), (81, 3), (161, 4), (236, 5), (290, 6), (360, 7), (400, 8), (410, 10)];
+
+ private static readonly (short UpTo, int Cost)[] ElementBands =
+ [(20, 1), (40, 2), (70, 3), (110, 4), (210, 5), (270, 6), (410, 7)];
+
+ private static readonly (short UpTo, int Cost)[] HpMpBands =
+ [(10, 1), (50, 2), (110, 3), (150, 4), (200, 5), (260, 6), (330, 7), (410, 8)];
+
+ ///
+ public int GetSpecialistPoints(byte specialistLevel, byte upgrade)
+ {
+ var points = specialistLevel > 20 ? (specialistLevel - 20) * 3 : 0;
+ return points + (upgrade < UpgradeBonus.Length ? UpgradeBonus[upgrade] : UpgradeBonus[^1]);
+ }
+
+ ///
+ public int GetAttackLevel(short points) => Level(AttackBands, points);
+
+ ///
+ public int GetDefenceLevel(short points) => Level(DefenceBands, points);
+
+ ///
+ public int GetElementLevel(short points) => Level(ElementBands, points);
+
+ ///
+ public int GetHpMpLevel(short points) => Level(HpMpBands, points);
+
+ private static int Level((short UpTo, int Cost)[] bands, short points)
+ {
+ var level = 0;
+ short from = 0;
+ foreach (var (upTo, cost) in bands)
+ {
+ if (points <= upTo)
+ {
+ return level + Math.Max(0, points - from) / cost;
+ }
+
+ level += (upTo - from) / cost;
+ from = upTo;
+ }
+
+ return level;
+ }
+ }
+}
diff --git a/test/NosCore.Algorithm.Tests/DocumentationTest.cs b/test/NosCore.Algorithm.Tests/DocumentationTest.cs
index 33431ed..c32bc15 100644
--- a/test/NosCore.Algorithm.Tests/DocumentationTest.cs
+++ b/test/NosCore.Algorithm.Tests/DocumentationTest.cs
@@ -439,5 +439,112 @@ public void FamilyExperienceDocumentation()
Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
}
+
+ [TestMethod]
+ public void DignityShopPriceDocumentation()
+ {
+ var dignityService = new DignityService.DignityService();
+
+ var resultBuilder = new StringBuilder("# Dignity Shop Price Table");
+ resultBuilder.AppendLine();
+ foreach (var dignity in Enum.GetValues(typeof(DignityType)).Cast())
+ {
+ resultBuilder.AppendLine($"- {dignity,-11} - Price: x{dignityService.GetShopPriceMultiplier(dignity)}");
+ }
+
+ Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
+ }
+
+ [TestMethod]
+ public void ExperienceShareDocumentation()
+ {
+ var experienceShareService = new ExperienceShareService.ExperienceShareService();
+
+ var resultBuilder = new StringBuilder("# Group Experience Share Table");
+ resultBuilder.AppendLine();
+ for (byte members = 1; members <= 3; members++)
+ {
+ resultBuilder.AppendLine(
+ $"- {members} member(s) - XP: {experienceShareService.GetExperienceShare(members):P2} Job XP: {experienceShareService.GetJobExperienceShare(members):P2}");
+ }
+
+ Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
+ }
+
+ [TestMethod]
+ public void LevelPenaltyDocumentation()
+ {
+ var levelPenaltyService = new LevelPenaltyService.LevelPenaltyService();
+
+ var resultBuilder = new StringBuilder("# Level Penalty Table");
+ resultBuilder.AppendLine();
+ for (var difference = -5; difference <= 35; difference++)
+ {
+ const byte playerLevel = 50;
+ var monsterLevel = (byte)(playerLevel - difference);
+ resultBuilder.AppendLine(
+ $"- Player {difference,3} level(s) above the monster - XP: x{levelPenaltyService.GetExperiencePenalty(playerLevel, monsterLevel)} Gold: x{levelPenaltyService.GetGoldPenalty(playerLevel, monsterLevel)}");
+ }
+
+ Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
+ }
+
+ [TestMethod]
+ public void RarityPointDocumentation()
+ {
+ var rarityPointService = new RarityPointService.RarityPointService();
+
+ var resultBuilder = new StringBuilder("# Rarity Point Table");
+ for (sbyte rarity = -2; rarity <= 8; rarity++)
+ {
+ resultBuilder.AppendLine();
+ resultBuilder.AppendLine($"## Rarity {rarity}");
+ for (byte level = 0; level < 100; level += 5)
+ {
+ resultBuilder.AppendLine($"- Item level {level,2}-{level + 4,2} - Points: {rarityPointService.GetRarityPoint(rarity, level)}");
+ }
+ }
+
+ Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
+ }
+
+ [TestMethod]
+ public void SpecialistPointDocumentation()
+ {
+ var specialistPointService = new SpecialistPointService.SpecialistPointService();
+
+ var resultBuilder = new StringBuilder("# Specialist Point Table");
+ resultBuilder.AppendLine();
+ resultBuilder.AppendLine("## Points by level (+0)");
+ for (byte level = 1; level < 100; level++)
+ {
+ resultBuilder.AppendLine($"- Level {level,2} - Points: {specialistPointService.GetSpecialistPoints(level, 0)}");
+ }
+
+ resultBuilder.AppendLine();
+ resultBuilder.AppendLine("## Points at level 99 by upgrade");
+ for (byte upgrade = 0; upgrade <= 15; upgrade++)
+ {
+ resultBuilder.AppendLine($"- +{upgrade,-2} - Points: {specialistPointService.GetSpecialistPoints(99, upgrade)}");
+ }
+
+ resultBuilder.AppendLine();
+ resultBuilder.AppendLine("## Stat level by points spent");
+ for (short points = 0; points <= 410; points += 5)
+ {
+ resultBuilder.AppendLine(
+ $"- {points,3} points - Attack: {specialistPointService.GetAttackLevel(points)} Defence: {specialistPointService.GetDefenceLevel(points)} Element: {specialistPointService.GetElementLevel(points)} HP/MP: {specialistPointService.GetHpMpLevel(points)}");
+ }
+
+ for (short points = 1; points <= 420; points++)
+ {
+ Assert.IsTrue(specialistPointService.GetAttackLevel(points) >= specialistPointService.GetAttackLevel((short)(points - 1)));
+ Assert.IsTrue(specialistPointService.GetDefenceLevel(points) >= specialistPointService.GetDefenceLevel((short)(points - 1)));
+ Assert.IsTrue(specialistPointService.GetElementLevel(points) >= specialistPointService.GetElementLevel((short)(points - 1)));
+ Assert.IsTrue(specialistPointService.GetHpMpLevel(points) >= specialistPointService.GetHpMpLevel((short)(points - 1)));
+ }
+
+ Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
+ }
}
}