Skip to content

Commit 5b10715

Browse files
committed
Management of last played level
1 parent 95027a8 commit 5b10715

File tree

2 files changed

+82
-3
lines changed

2 files changed

+82
-3
lines changed

PSDX.Tests/PsdxTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,4 +491,40 @@ public void TestSetPolarTrickStatus(bool performed)
491491

492492
Assert.Equal(performed, cb2.GetPolarTrickStatus());
493493
}
494+
495+
[Fact]
496+
public void GetLastPlayedLevelReturns1()
497+
{
498+
using var fs = new FileStream("cb2.mcs", FileMode.Open);
499+
var cb2 = new CrashBandicoot2SaveData(fs);
500+
501+
int level = cb2.GetLastPlayedLevel();
502+
503+
Assert.Equal(1, level);
504+
}
505+
506+
[Theory]
507+
[InlineData(-1), InlineData(0), InlineData(33)]
508+
public void SetLastPlayedLevelThrowsAoReWithWrongNumber(int level)
509+
{
510+
using var fs = new FileStream("cb2.mcs", FileMode.Open);
511+
var cb2 = new CrashBandicoot2SaveData(fs);
512+
513+
void SetLastPlayedLevel() => cb2.SetLastPlayedLevel(level);
514+
515+
_ = Assert.Throws<ArgumentOutOfRangeException>(SetLastPlayedLevel);
516+
}
517+
518+
[Fact]
519+
public void TestSetLastPlayedLevel()
520+
{
521+
using var fs = new FileStream("cb2.mcs", FileMode.Open);
522+
var cb2 = new CrashBandicoot2SaveData(fs);
523+
524+
for (int level = 1; level < 33; level++)
525+
{
526+
cb2.SetLastPlayedLevel(level);
527+
Assert.Equal(level, cb2.GetLastPlayedLevel());
528+
}
529+
}
494530
}

PSDX/PsxSaveData.cs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ public class CrashBandicoot2SaveData : PsxSaveData
9393

9494
private const int _secretsOffset = 0x1B8;
9595

96+
private const int _lastPlayedLevelOffset = 0x188;
97+
9698
private const byte _polarTrickFlag = 0x20;
9799

98100
/// <summary>
@@ -133,10 +135,17 @@ public class CrashBandicoot2SaveData : PsxSaveData
133135
/// Checks whether the specified <paramref name="level"/> number exists, and throws an exception if not.
134136
/// </summary>
135137
/// <param name="level">The number of the level to check for.</param>
136-
/// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="level"/> number is less than one or greater than twenty-seven.</exception>
137-
private static void CheckLevelNumber(int level)
138+
/// <param name="includeBossLevels">
139+
/// Determines whether to extend the range of allowed values for <paramref name="level"/> by including the boss levels.
140+
/// </param>
141+
/// <exception cref="ArgumentOutOfRangeException">
142+
/// The specified <paramref name="level"/> number is less than one or greater than either twenty-seven
143+
/// or thirty-two, depending on the value of <paramref name="includeBossLevels"/>.
144+
/// </exception>
145+
private static void CheckLevelNumber(int level, bool includeBossLevels = false)
138146
{
139-
if (level < 1 || level > _maxLevelNumber)
147+
int maxLevelNumber = includeBossLevels ? _maxLevelNumber + _maxBossNumber : _maxLevelNumber;
148+
if (level < 1 || level > maxLevelNumber)
140149
{
141150
throw new ArgumentOutOfRangeException(nameof(level), level, "The specified level does not exist.");
142151
}
@@ -560,4 +569,38 @@ public void SetBossStatus(int bossNumber, bool defeated)
560569
/// </summary>
561570
/// <param name="performed">Determines whether the trick has been performed.</param>
562571
public void SetPolarTrickStatus(bool performed) => SetFlag(_secretsOffset, _polarTrickFlag, performed);
572+
573+
/// <summary>
574+
/// Gets the last played level number currently stored in the save data file.
575+
/// </summary>
576+
/// <returns>
577+
/// A number in the range [1, 32], where the values in the range [28, 32] represent
578+
/// the five boss levels. This is how the game maps them internally.
579+
/// </returns>
580+
public int GetLastPlayedLevel()
581+
{
582+
byte[] bytes = new byte[sizeof(int)];
583+
Stream.Position = _lastPlayedLevelOffset;
584+
Stream.ReadExactly(bytes);
585+
return BitConverter.ToInt32(bytes);
586+
}
587+
588+
/// <summary>
589+
/// Sets the last played level number to store in the save data file.
590+
/// </summary>
591+
/// <param name="level">
592+
/// The number of the level to be set as the last played.<br/>Values in the range [28, 32] are
593+
/// allowed and represent the five boss levels. This is how the game maps them internally.
594+
/// </param>
595+
/// <exception cref="ArgumentOutOfRangeException">
596+
/// The specified <paramref name="level"/> number is less than one or greater than thirty-two.
597+
/// </exception>
598+
public void SetLastPlayedLevel(int level)
599+
{
600+
CheckLevelNumber(level, true);
601+
602+
Stream.Position = _lastPlayedLevelOffset;
603+
byte[] bytes = BitConverter.GetBytes(level);
604+
Stream.Write(bytes);
605+
}
563606
}

0 commit comments

Comments
 (0)