Skip to content

Commit 0e52858

Browse files
add mines
1 parent 151ae54 commit 0e52858

File tree

6 files changed

+117
-14
lines changed

6 files changed

+117
-14
lines changed

Quaver.API/Enums/HitObjectType.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Quaver.API.Enums
2+
{
3+
/// <summary>
4+
/// </summary>
5+
public enum HitObjectType
6+
{
7+
Normal,
8+
Mine
9+
}
10+
}

Quaver.API/Maps/Processors/Scoring/ScoreProcessorKeys.cs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Quaver.API.Maps.Processors.Scoring.Data;
1515
using Quaver.API.Maps.Processors.Scoring.Multiplayer;
1616
using Quaver.API.Replays;
17+
using HitObjectType = Quaver.API.Enums.HitObjectType;
1718

1819
namespace Quaver.API.Maps.Processors.Scoring
1920
{
@@ -364,17 +365,7 @@ protected override void InitializeHealthWeighting()
364365
/// <returns></returns>
365366
public int GetTotalJudgementCount()
366367
{
367-
var judgements = 0;
368-
369-
foreach (var o in Map.HitObjects)
370-
{
371-
if (o.IsLongNote)
372-
judgements += 2;
373-
else
374-
judgements++;
375-
}
376-
377-
return judgements;
368+
return Map.HitObjects.Sum(o => o.JudgementCount);
378369
}
379370

380371
/// <summary>

Quaver.API/Maps/Qua.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,8 @@ static HitObjectInfo SerializableHitObject(HitObjectInfo obj) =>
359359
.Select(x => new KeySoundInfo { Sample = x.Sample, Volume = x.Volume == 100 ? 0 : x.Volume })
360360
.ToList(),
361361
Lane = obj.Lane, StartTime = obj.StartTime,
362-
TimingGroup = obj.TimingGroup == DefaultScrollGroupId ? null : obj.TimingGroup
362+
TimingGroup = obj.TimingGroup == DefaultScrollGroupId ? null : obj.TimingGroup,
363+
Type = obj.Type
363364
};
364365

365366
static SoundEffectInfo SerializableSoundEffect(SoundEffectInfo x) =>
@@ -1110,8 +1111,15 @@ public HitObjectInfo GetHitObjectAtJudgementIndex(int index)
11101111

11111112
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
11121113
foreach (var h in HitObjects)
1113-
if (total++ == index || (h.IsLongNote && total++ == index))
1114+
{
1115+
var judgementCount = h.JudgementCount;
1116+
if (total <= index && index < total + judgementCount)
1117+
{
11141118
return h;
1119+
}
1120+
1121+
total += judgementCount;
1122+
}
11151123

11161124
return null;
11171125
}

Quaver.API/Maps/Structures/HitObjectInfo.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ public HitSounds HitSound
6464
set;
6565
}
6666

67+
/// <summary>
68+
/// The hit object could be a normal note or a mine
69+
/// </summary>
70+
public HitObjectType Type { get; [MoonSharpVisible(false)] set; }
71+
6772
/// <summary>
6873
/// Key sounds to play when this object is hit.
6974
/// </summary>
@@ -95,6 +100,11 @@ public string TimingGroup
95100
[YamlIgnore]
96101
public bool IsLongNote => EndTime > 0;
97102

103+
/// <summary>
104+
/// The number of judgements generated by this object
105+
/// </summary>
106+
[YamlIgnore] public int JudgementCount => IsLongNote && Type != HitObjectType.Mine ? 2 : 1;
107+
98108
/// <summary>
99109
/// Returns if the object is allowed to be edited in lua scripts
100110
/// </summary>
@@ -175,6 +185,7 @@ public bool Equals(HitObjectInfo x, HitObjectInfo y)
175185
x.Lane == y.Lane &&
176186
x.EndTime == y.EndTime &&
177187
x.HitSound == y.HitSound &&
188+
x.Type == y.Type &&
178189
x.KeySounds.SequenceEqual(y.KeySounds, KeySoundInfo.ByValueComparer) &&
179190
x.EditorLayer == y.EditorLayer;
180191
}
@@ -186,6 +197,7 @@ public int GetHashCode(HitObjectInfo obj)
186197
var hashCode = obj.StartTime;
187198
hashCode = (hashCode * 397) ^ obj.Lane;
188199
hashCode = (hashCode * 397) ^ obj.EndTime;
200+
hashCode = (hashCode * 397) ^ (int)obj.Type;
189201
hashCode = (hashCode * 397) ^ (int)obj.HitSound;
190202

191203
foreach (var keySound in obj.KeySounds)

Quaver.API/Replays/Replay.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ public static Replay GeneratePerfectReplayKeys(Replay replay, Qua map)
332332

333333
foreach (var hitObject in map.HitObjects)
334334
{
335+
if (hitObject.Type is HitObjectType.Mine)
336+
continue;
337+
335338
// Add key press frame
336339
nonCombined.Add(new ReplayAutoplayFrame(hitObject, ReplayAutoplayFrameType.Press, hitObject.StartTime, KeyLaneToPressState(hitObject.Lane)));
337340

Quaver.API/Replays/Virtual/VirtualReplayPlayer.cs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ public class VirtualReplayPlayer
3232
/// The score processor for the virtual replay.
3333
/// </summary>
3434
public ScoreProcessorKeys ScoreProcessor { get; }
35+
36+
37+
/// <summary>
38+
/// All of the mines that are currently active and available.
39+
/// </summary>
40+
public List<HitObjectInfo> ActiveMines { get; }
41+
42+
43+
/// <summary>
44+
/// The list of active mines that are scheduled for removal.
45+
/// </summary>
46+
public List<HitObjectInfo> ActiveMinesToRemove { get; set; }
3547

3648
/// <summary>
3749
/// All of the HitObjects that are currently active and available.
@@ -95,8 +107,22 @@ public VirtualReplayPlayer(Replay replay, Qua map, JudgementWindows windows = nu
95107

96108
ActiveHitObjects = new List<HitObjectInfo>();
97109
ActiveHeldLongNotes = new List<HitObjectInfo>();
110+
ActiveMines = new List<HitObjectInfo>();
98111

99-
map.HitObjects.ForEach(x => ActiveHitObjects.Add(x));
112+
map.HitObjects.ForEach(x =>
113+
{
114+
switch (x.Type)
115+
{
116+
case HitObjectType.Normal:
117+
ActiveHitObjects.Add(x);
118+
break;
119+
case HitObjectType.Mine:
120+
ActiveMines.Add(x);
121+
break;
122+
default:
123+
throw new ArgumentOutOfRangeException();
124+
}
125+
});
100126

101127
// Add virtual key bindings based on the game mode of the replay.
102128
switch (Map.Mode)
@@ -171,6 +197,7 @@ public void PlayNextFrame()
171197
// Store the objects that need to be removed from the list of active objects.
172198
ActiveHitObjectsToRemove = new List<HitObjectInfo>();
173199
ActiveHeldLongNotesToRemove = new List<HitObjectInfo>();
200+
ActiveMinesToRemove = new List<HitObjectInfo>();
174201

175202
if (CurrentFrame < Replay.Frames.Count)
176203
{
@@ -207,6 +234,8 @@ private void HandleKeyPressesInFrame()
207234
// Retrieve a list of the key press states in integer form.
208235
var currentFramePressed = Replay.KeyPressStateToLanes(Replay.Frames[CurrentFrame].Keys);
209236
var previousFramePressed = CurrentFrame > 0 ? Replay.KeyPressStateToLanes(Replay.Frames[CurrentFrame - 1].Keys) : new List<int>();
237+
238+
var previousFrameTime = CurrentFrame > 0 ? Replay.Frames[CurrentFrame - 1].Time : Time;
210239

211240
// Update the key press state in the store.
212241
for (var i = 0; i < InputKeyStore.Count; i++)
@@ -217,6 +246,33 @@ private void HandleKeyPressesInFrame()
217246
.Concat(previousFramePressed.Except(currentFramePressed))
218247
.ToList();
219248

249+
foreach (var lane in previousFramePressed)
250+
{
251+
foreach (var mine in ActiveMines)
252+
{
253+
var endTime = mine.IsLongNote ? mine.EndTime : mine.StartTime;
254+
if (mine.Lane == lane + 1
255+
&& endTime + ScoreProcessor.JudgementWindow[Judgement.Marv] > previousFrameTime
256+
&& Time >= mine.StartTime - ScoreProcessor.JudgementWindow[Judgement.Marv])
257+
{
258+
// Calculate the hit difference.
259+
var hitDifference =
260+
mine.StartTime - ScoreProcessor.JudgementWindow[Judgement.Marv] > previousFrameTime
261+
? (int)ScoreProcessor.JudgementWindow[Judgement.Marv]
262+
: mine.StartTime - previousFrameTime;
263+
264+
// Add a new hit stat to the score processor.
265+
var stat = new HitStat(HitStatType.Miss, KeyPressType.Press, mine, Time, Judgement.Miss, hitDifference,
266+
ScoreProcessor.Accuracy, ScoreProcessor.Health);
267+
268+
ScoreProcessor.Stats.Add(stat);
269+
270+
// Object needs to be removed from ActiveObjects.
271+
ActiveMinesToRemove.Add(mine);
272+
}
273+
}
274+
}
275+
220276
// Go through each frame and handle key presses/releases.
221277
foreach (var key in keyDifferences)
222278
{
@@ -323,6 +379,7 @@ private void HandleKeyPressesInFrame()
323379
// Remove all active objects after handling key presses/releases.
324380
ActiveHitObjectsToRemove.ForEach(x => ActiveHitObjects.Remove(x));
325381
ActiveHeldLongNotesToRemove.ForEach(x => ActiveHeldLongNotes.Remove(x));
382+
ActiveMinesToRemove.ForEach(x => ActiveMines.Remove(x));
326383
}
327384

328385
/// <summary>
@@ -390,10 +447,32 @@ private void HandleMissedHitObjects()
390447
break;
391448
}
392449
}
450+
// Handle missed mines.
451+
foreach (var hitObject in ActiveMines)
452+
{
453+
var endTime = hitObject.IsLongNote ? hitObject.EndTime : hitObject.StartTime;
454+
if (Time > endTime + ScoreProcessor.JudgementWindow[Judgement.Marv])
455+
{
456+
// Add a miss to the score.
457+
ScoreProcessor.CalculateScore(Judgement.Marv);
458+
459+
// Create a new HitStat to add to the ScoreProcessor.
460+
var stat = new HitStat(HitStatType.Hit, KeyPressType.None, hitObject, hitObject.StartTime, Judgement.Marv, 0,
461+
ScoreProcessor.Accuracy, ScoreProcessor.Health);
462+
463+
ScoreProcessor.Stats.Add(stat);
464+
ActiveMinesToRemove.Add(hitObject);
465+
}
466+
else if (Time < hitObject.StartTime - ScoreProcessor.JudgementWindow[Judgement.Marv])
467+
{
468+
break;
469+
}
470+
}
393471

394472
// Remove all objects
395473
ActiveHitObjectsToRemove.ForEach(x => ActiveHitObjects.Remove(x));
396474
ActiveHeldLongNotesToRemove.ForEach(x => ActiveHeldLongNotes.Remove(x));
475+
ActiveMinesToRemove.ForEach(x => ActiveMines.Remove(x));
397476
}
398477

399478
/// <summary>

0 commit comments

Comments
 (0)