Skip to content

Commit 1cce607

Browse files
denislauri1999claudeerwan-joly
authored
feat: mate and family experience services (#129)
* feat: mate and family experience services Two curves that were living in NosCore and belong here. MateExperienceService is the published curve divided by 20 for a pet and by 5 for a partner. Those divisors come from the XpLoad field of sc_p and sc_n in a packet capture: eleven observations between level 1 and level 88 match to the unit, including 29 312 950 and 39 495 200. Without them a pet needs twenty times the experience it should, which raises nothing and simply reads as slow progress. FamilyExperienceService is the published table as-is. A ginfo line from the same capture puts a level 7 family's bar at 640 000 where the table says 1 900 000, so at least that row is wrong — but one observation cannot rebuild the other eighteen, so the published numbers stand and the disagreement is noted where somebody will find it. Both come with approval-test tables under documentation/. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore: drop the committed swap files and trim the provenance remarks Two Vim .swp files were checked in alongside the approved documentation, and the two new approved files carried a BOM the generator does not emit - both are artefacts of hand-editing them. Ignoring *.swp so they cannot come back. Remarks cut back to the load-bearing facts, in line with the summary-only style of the services already here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: erwan-joly <erwan.joly+pro@gmail.com>
1 parent b0e8bfe commit 1cce607

9 files changed

Lines changed: 339 additions & 1 deletion

File tree

‎.gitignore‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,4 +501,7 @@ fabric.properties
501501
/documentation/*.received.md
502502
/documentation/*.received.txt
503503
/documentation/*.approved.txt
504-
build_output.txt
504+
build_output.txt
505+
# Vim swap files
506+
*.swp
507+
*.swo
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Family Experience Table
2+
- Level 1 - XP: 100000
3+
- Level 2 - XP: 250000
4+
- Level 3 - XP: 370000
5+
- Level 4 - XP: 560000
6+
- Level 5 - XP: 840000
7+
- Level 6 - XP: 1260000
8+
- Level 7 - XP: 1900000
9+
- Level 8 - XP: 2850000
10+
- Level 9 - XP: 3570000
11+
- Level 10 - XP: 3830000
12+
- Level 11 - XP: 4150000
13+
- Level 12 - XP: 4750000
14+
- Level 13 - XP: 5500000
15+
- Level 14 - XP: 6500000
16+
- Level 15 - XP: 7000000
17+
- Level 16 - XP: 8500000
18+
- Level 17 - XP: 9500000
19+
- Level 18 - XP: 10000000
20+
- Level 19 - XP: 17000000
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Mate Experience Table
2+
- Level 1 - Pet: 15 - Partner: 60
3+
- Level 2 - Pet: 42 - Partner: 168
4+
- Level 3 - Pet: 90 - Partner: 360
5+
- Level 4 - Pet: 165 - Partner: 660
6+
- Level 5 - Pet: 273 - Partner: 1092
7+
- Level 6 - Pet: 420 - Partner: 1680
8+
- Level 7 - Pet: 612 - Partner: 2448
9+
- Level 8 - Pet: 855 - Partner: 3420
10+
- Level 9 - Pet: 1155 - Partner: 4620
11+
- Level 10 - Pet: 1518 - Partner: 6072
12+
- Level 11 - Pet: 1950 - Partner: 7800
13+
- Level 12 - Pet: 2457 - Partner: 9828
14+
- Level 13 - Pet: 3045 - Partner: 12180
15+
- Level 14 - Pet: 3720 - Partner: 14880
16+
- Level 15 - Pet: 5256 - Partner: 21024
17+
- Level 16 - Pet: 6990 - Partner: 27960
18+
- Level 17 - Pet: 8934 - Partner: 35736
19+
- Level 18 - Pet: 11100 - Partner: 44400
20+
- Level 19 - Pet: 13500 - Partner: 54000
21+
- Level 20 - Pet: 16146 - Partner: 64584
22+
- Level 21 - Pet: 19050 - Partner: 76200
23+
- Level 22 - Pet: 22224 - Partner: 88896
24+
- Level 23 - Pet: 25680 - Partner: 102720
25+
- Level 24 - Pet: 29430 - Partner: 117720
26+
- Level 25 - Pet: 33486 - Partner: 133944
27+
- Level 26 - Pet: 37860 - Partner: 151440
28+
- Level 27 - Pet: 42564 - Partner: 170256
29+
- Level 28 - Pet: 47610 - Partner: 190440
30+
- Level 29 - Pet: 53010 - Partner: 212040
31+
- Level 30 - Pet: 58776 - Partner: 235104
32+
- Level 31 - Pet: 64920 - Partner: 259680
33+
- Level 32 - Pet: 71454 - Partner: 285816
34+
- Level 33 - Pet: 78390 - Partner: 313560
35+
- Level 34 - Pet: 85740 - Partner: 342960
36+
- Level 35 - Pet: 93516 - Partner: 374064
37+
- Level 36 - Pet: 101730 - Partner: 406920
38+
- Level 37 - Pet: 110394 - Partner: 441576
39+
- Level 38 - Pet: 119520 - Partner: 478080
40+
- Level 39 - Pet: 129120 - Partner: 516480
41+
- Level 40 - Pet: 161059 - Partner: 644236
42+
- Level 41 - Pet: 194575 - Partner: 778300
43+
- Level 42 - Pet: 229706 - Partner: 918824
44+
- Level 43 - Pet: 266490 - Partner: 1065960
45+
- Level 44 - Pet: 304965 - Partner: 1219860
46+
- Level 45 - Pet: 345169 - Partner: 1380676
47+
- Level 46 - Pet: 387140 - Partner: 1548560
48+
- Level 47 - Pet: 430916 - Partner: 1723664
49+
- Level 48 - Pet: 476535 - Partner: 1906140
50+
- Level 49 - Pet: 524035 - Partner: 2096140
51+
- Level 50 - Pet: 573454 - Partner: 2293816
52+
- Level 51 - Pet: 624830 - Partner: 2499320
53+
- Level 52 - Pet: 678201 - Partner: 2712804
54+
- Level 53 - Pet: 733605 - Partner: 2934420
55+
- Level 54 - Pet: 791080 - Partner: 3164320
56+
- Level 55 - Pet: 850664 - Partner: 3402656
57+
- Level 56 - Pet: 912395 - Partner: 3649580
58+
- Level 57 - Pet: 976311 - Partner: 3905244
59+
- Level 58 - Pet: 1042450 - Partner: 4169800
60+
- Level 59 - Pet: 1110850 - Partner: 4443400
61+
- Level 60 - Pet: 1371320 - Partner: 5485280
62+
- Level 61 - Pet: 1640400 - Partner: 6561600
63+
- Level 62 - Pet: 1918230 - Partner: 7672920
64+
- Level 63 - Pet: 2204950 - Partner: 8819800
65+
- Level 64 - Pet: 2500700 - Partner: 10002800
66+
- Level 65 - Pet: 2805620 - Partner: 11222480
67+
- Level 66 - Pet: 3119850 - Partner: 12479400
68+
- Level 67 - Pet: 3443530 - Partner: 13774120
69+
- Level 68 - Pet: 3776800 - Partner: 15107200
70+
- Level 69 - Pet: 4119800 - Partner: 16479200
71+
- Level 70 - Pet: 4472670 - Partner: 17890680
72+
- Level 71 - Pet: 4835550 - Partner: 19342200
73+
- Level 72 - Pet: 5208580 - Partner: 20834320
74+
- Level 73 - Pet: 5591900 - Partner: 22367600
75+
- Level 74 - Pet: 5985650 - Partner: 23942600
76+
- Level 75 - Pet: 6389970 - Partner: 25559880
77+
- Level 76 - Pet: 6805000 - Partner: 27220000
78+
- Level 77 - Pet: 7230880 - Partner: 28923520
79+
- Level 78 - Pet: 7667750 - Partner: 30671000
80+
- Level 79 - Pet: 8115750 - Partner: 32463000
81+
- Level 80 - Pet: 9756000 - Partner: 39024000
82+
- Level 81 - Pet: 11437000 - Partner: 45748000
83+
- Level 82 - Pet: 13159250 - Partner: 52637000
84+
- Level 83 - Pet: 16334450 - Partner: 65337800
85+
- Level 84 - Pet: 19585700 - Partner: 78342800
86+
- Level 85 - Pet: 24393100 - Partner: 97572400
87+
- Level 86 - Pet: 29312950 - Partner: 117251800
88+
- Level 87 - Pet: 34346550 - Partner: 137386200
89+
- Level 88 - Pet: 39495200 - Partner: 157980800
90+
- Level 89 - Pet: 44760200 - Partner: 179040800
91+
- Level 90 - Pet: 50142850 - Partner: 200571400
92+
- Level 91 - Pet: 55644450 - Partner: 222577800
93+
- Level 92 - Pet: 61266300 - Partner: 245065200
94+
- Level 93 - Pet: 67009700 - Partner: 268038800
95+
- Level 94 - Pet: 72875950 - Partner: 291503800
96+
- Level 95 - Pet: 78866350 - Partner: 315465400
97+
- Level 96 - Pet: 84982200 - Partner: 339928800
98+
- Level 97 - Pet: 91224800 - Partner: 364899200
99+
- Level 98 - Pet: 97595450 - Partner: 390381800
100+
- Level 99 - Pet: 104095450 - Partner: 416381800

‎src/NosCore.Algorithm/Constants.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ internal class Constants
99
internal const byte MaxFairyLevel = 80;
1010
internal const byte MaxJobLevel = 80;
1111
internal const byte MaxHeroLevel = 60;
12+
internal const byte MaxMateLevel = 99;
1213
internal static readonly int ClassCount = Enum.GetNames(typeof(CharacterClassType)).Length;
1314
}
1415
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
namespace NosCore.Algorithm.FamilyExperienceService
8+
{
9+
/// <summary>
10+
/// Provides family experience requirement calculations for different levels
11+
/// </summary>
12+
/// <remarks>
13+
/// A ginfo line puts a level 7 family's bar at 640 000 against the 1 900 000 here, so at
14+
/// least that row is suspect. One observation is not enough to rebuild the curve, so the
15+
/// table stands until more levels can be checked.
16+
/// </remarks>
17+
public class FamilyExperienceService : IFamilyExperienceService
18+
{
19+
private static readonly uint[] FamilyXpData =
20+
[
21+
100_000, 250_000, 370_000, 560_000, 840_000,
22+
1_260_000, 1_900_000, 2_850_000, 3_570_000, 3_830_000,
23+
4_150_000, 4_750_000, 5_500_000, 6_500_000, 7_000_000,
24+
8_500_000, 9_500_000, 10_000_000, 17_000_000
25+
];
26+
27+
/// <summary>
28+
/// Gets the experience a family needs to leave a specific level
29+
/// </summary>
30+
/// <param name="level">The family level</param>
31+
/// <returns>The experience required, or uint.MaxValue past the last known level</returns>
32+
public uint GetFamilyExperience(byte level)
33+
{
34+
return level >= 1 && level <= FamilyXpData.Length ? FamilyXpData[level - 1] : uint.MaxValue;
35+
}
36+
}
37+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
namespace NosCore.Algorithm.FamilyExperienceService
8+
{
9+
/// <summary>
10+
/// Service for calculating family experience requirements
11+
/// </summary>
12+
public interface IFamilyExperienceService
13+
{
14+
/// <summary>
15+
/// Gets the experience a family needs to leave a specific level
16+
/// </summary>
17+
/// <param name="level">The family level</param>
18+
/// <returns>The experience required</returns>
19+
uint GetFamilyExperience(byte level);
20+
}
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
namespace NosCore.Algorithm.MateExperienceService
8+
{
9+
/// <summary>
10+
/// Service for calculating pet and partner experience requirements
11+
/// </summary>
12+
public interface IMateExperienceService
13+
{
14+
/// <summary>
15+
/// Gets the experience a pet needs to leave a specific level
16+
/// </summary>
17+
/// <param name="level">The pet level</param>
18+
/// <returns>The experience required</returns>
19+
long GetPetExperience(byte level);
20+
21+
/// <summary>
22+
/// Gets the experience a partner needs to leave a specific level
23+
/// </summary>
24+
/// <param name="level">The partner level</param>
25+
/// <returns>The experience required</returns>
26+
long GetPartnerExperience(byte level);
27+
}
28+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// __ _ __ __ ___ __ ___ ___
2+
// | \| |/__\ /' _/ / _//__\| _ \ __|
3+
// | | ' | \/ |`._`.| \_| \/ | v / _|
4+
// |_|\__|\__/ |___/ \__/\__/|_|_\___|
5+
// -----------------------------------
6+
7+
namespace NosCore.Algorithm.MateExperienceService
8+
{
9+
/// <summary>
10+
/// Provides pet and partner experience requirement calculations for different levels
11+
/// </summary>
12+
/// <remarks>
13+
/// A pet needs a twentieth of the curve and a partner a fifth. Both divisors come from the
14+
/// XpLoad field of sc_p and sc_n, which match to the unit across eleven levels between 1
15+
/// and 88.
16+
/// </remarks>
17+
public class MateExperienceService : IMateExperienceService
18+
{
19+
private const int PetDivisor = 20;
20+
private const int PartnerDivisor = 5;
21+
22+
private readonly long[] _mateXpData = new long[Constants.MaxMateLevel + 1];
23+
24+
/// <summary>
25+
/// Initializes a new instance of the MateExperienceService and pre-calculates experience
26+
/// requirements for all mate levels
27+
/// </summary>
28+
public MateExperienceService()
29+
{
30+
var step = new double[_mateXpData.Length];
31+
step[0] = 540;
32+
step[1] = 960;
33+
for (var i = 2; i < step.Length; i++)
34+
{
35+
step[i] = step[i - 1] + 420 + 120 * (i - 1);
36+
}
37+
38+
var factor = 1d;
39+
_mateXpData[0] = 300;
40+
for (var i = 1; i < _mateXpData.Length; i++)
41+
{
42+
if (i < 79)
43+
{
44+
factor = i switch
45+
{
46+
14 => 6 / 3d,
47+
39 => 19 / 3d,
48+
59 => 70 / 3d,
49+
_ => factor
50+
};
51+
52+
_mateXpData[i] = (long)(_mateXpData[i - 1] + factor * step[i - 1]);
53+
continue;
54+
}
55+
56+
factor = i switch
57+
{
58+
79 => 5000,
59+
82 => 9000,
60+
84 => 13000,
61+
_ => factor
62+
};
63+
64+
_mateXpData[i] = (long)(_mateXpData[i - 1] + factor * (i + 2) * (i + 2));
65+
}
66+
}
67+
68+
/// <summary>
69+
/// Gets the experience a pet needs to leave a specific level
70+
/// </summary>
71+
/// <param name="level">The pet level</param>
72+
/// <returns>The experience required</returns>
73+
public long GetPetExperience(byte level)
74+
{
75+
return At(level) / PetDivisor;
76+
}
77+
78+
/// <summary>
79+
/// Gets the experience a partner needs to leave a specific level
80+
/// </summary>
81+
/// <param name="level">The partner level</param>
82+
/// <returns>The experience required</returns>
83+
public long GetPartnerExperience(byte level)
84+
{
85+
return At(level) / PartnerDivisor;
86+
}
87+
88+
private long At(byte level)
89+
{
90+
var index = level < 1 ? 0 : level - 1;
91+
return _mateXpData[index >= _mateXpData.Length ? _mateXpData.Length - 1 : index];
92+
}
93+
}
94+
}

‎test/NosCore.Algorithm.Tests/DocumentationTest.cs‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,5 +405,39 @@ public void SumDocumentation()
405405

406406
Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
407407
}
408+
409+
[TestMethod]
410+
public void MateExperienceDocumentation()
411+
{
412+
var mateExperienceService = new MateExperienceService.MateExperienceService();
413+
414+
var resultBuilder = new StringBuilder("# Mate Experience Table");
415+
resultBuilder.AppendLine();
416+
417+
for (byte level = 1; level < 100; level++)
418+
{
419+
resultBuilder.AppendLine(
420+
$"- Level {level,2} - Pet: {mateExperienceService.GetPetExperience(level)} - Partner: {mateExperienceService.GetPartnerExperience(level)}");
421+
}
422+
423+
Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
424+
}
425+
426+
[TestMethod]
427+
public void FamilyExperienceDocumentation()
428+
{
429+
var familyExperienceService = new FamilyExperienceService.FamilyExperienceService();
430+
431+
var resultBuilder = new StringBuilder("# Family Experience Table");
432+
resultBuilder.AppendLine();
433+
434+
for (byte level = 1; level < 20; level++)
435+
{
436+
resultBuilder.AppendLine(
437+
$"- Level {level,2} - XP: {familyExperienceService.GetFamilyExperience(level)}");
438+
}
439+
440+
Approvals.Verify(WriterFactory.CreateTextWriter(resultBuilder.ToString(), "md"));
441+
}
408442
}
409443
}

0 commit comments

Comments
 (0)