Merge pull request #26083 from smoogipoo/try-improve-hp-drain

Replace recently-added HP drain density calculation with combo-end bonus
This commit is contained in:
Dean Herbert 2023-12-24 01:30:49 +09:00 committed by GitHub
commit d72ec81684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 42 deletions

View File

@ -1,10 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
@ -12,14 +13,68 @@ namespace osu.Game.Rulesets.Osu.Scoring
{
public partial class OsuHealthProcessor : DrainingHealthProcessor
{
private ComboResult currentComboResult = ComboResult.Perfect;
public OsuHealthProcessor(double drainStartTime, double drainLenience = 0)
: base(drainStartTime, drainLenience)
{
}
protected override int? GetDensityGroup(HitObject hitObject) => (hitObject as IHasComboInformation)?.ComboIndex;
protected override double GetHealthIncreaseFor(JudgementResult result)
{
if (IsSimulating)
return getHealthIncreaseFor(result);
if (result.HitObject is not IHasComboInformation combo)
return getHealthIncreaseFor(result);
if (combo.NewCombo)
currentComboResult = ComboResult.Perfect;
switch (result.Type)
{
case HitResult.LargeTickMiss:
case HitResult.Ok:
setComboResult(ComboResult.Good);
break;
case HitResult.Meh:
case HitResult.Miss:
setComboResult(ComboResult.None);
break;
}
// The slider tail has a special judgement that can't accurately be described above.
if (result.HitObject is SliderTailCircle && !result.IsHit)
setComboResult(ComboResult.Good);
if (combo.LastInCombo && result.Type.IsHit())
{
switch (currentComboResult)
{
case ComboResult.Perfect:
return getHealthIncreaseFor(result) + 0.07;
case ComboResult.Good:
return getHealthIncreaseFor(result) + 0.05;
default:
return getHealthIncreaseFor(result) + 0.03;
}
}
return getHealthIncreaseFor(result);
void setComboResult(ComboResult comboResult) => currentComboResult = (ComboResult)Math.Min((int)currentComboResult, (int)comboResult);
}
protected override void Reset(bool storeResults)
{
base.Reset(storeResults);
currentComboResult = ComboResult.Perfect;
}
private double getHealthIncreaseFor(JudgementResult result)
{
switch (result.Type)
{

View File

@ -62,7 +62,6 @@ namespace osu.Game.Rulesets.Scoring
protected readonly double DrainLenience;
private readonly List<HealthIncrease> healthIncreases = new List<HealthIncrease>();
private readonly Dictionary<int, double> densityMultiplierByGroup = new Dictionary<int, double>();
private double gameplayEndTime;
private double targetMinimumHealth;
@ -139,29 +138,14 @@ namespace osu.Game.Rulesets.Scoring
{
healthIncreases.Add(new HealthIncrease(
result.HitObject.GetEndTime() + result.TimeOffset,
GetHealthIncreaseFor(result),
GetDensityGroup(result.HitObject)));
GetHealthIncreaseFor(result)));
}
}
protected override double GetHealthIncreaseFor(JudgementResult result) => base.GetHealthIncreaseFor(result) * getDensityMultiplier(GetDensityGroup(result.HitObject));
private double getDensityMultiplier(int? group)
{
if (group == null)
return 1;
return densityMultiplierByGroup.TryGetValue(group.Value, out double multiplier) ? multiplier : 1;
}
protected virtual int? GetDensityGroup(HitObject hitObject) => null;
protected override void Reset(bool storeResults)
{
base.Reset(storeResults);
densityMultiplierByGroup.Clear();
if (storeResults)
DrainRate = ComputeDrainRate();
@ -173,24 +157,6 @@ namespace osu.Game.Rulesets.Scoring
if (healthIncreases.Count <= 1)
return 0;
// Normalise the health gain during sections with higher densities.
(int group, double avgIncrease)[] avgIncreasesByGroup = healthIncreases
.Where(i => i.Group != null)
.GroupBy(i => i.Group)
.Select(g => ((int)g.Key!, g.Sum(i => i.Amount) / (g.Max(i => i.Time) - g.Min(i => i.Time) + 1)))
.ToArray();
if (avgIncreasesByGroup.Length > 1)
{
double overallAverageIncrease = avgIncreasesByGroup.Average(g => g.avgIncrease);
foreach ((int group, double avgIncrease) in avgIncreasesByGroup)
{
// Reduce the health increase for groups that return more health than average.
densityMultiplierByGroup[group] = Math.Min(1, overallAverageIncrease / avgIncrease);
}
}
int adjustment = 1;
double result = 1;
@ -216,12 +182,10 @@ namespace osu.Game.Rulesets.Scoring
currentBreak++;
}
double multiplier = getDensityMultiplier(healthIncreases[i].Group);
// Apply health adjustments
currentHealth -= (currentTime - lastTime) * result;
lowestHealth = Math.Min(lowestHealth, currentHealth);
currentHealth = Math.Min(1, currentHealth + healthIncreases[i].Amount * multiplier);
currentHealth = Math.Min(1, currentHealth + healthIncreases[i].Amount);
// Common scenario for when the drain rate is definitely too harsh
if (lowestHealth < 0)
@ -240,6 +204,6 @@ namespace osu.Game.Rulesets.Scoring
return result;
}
private record struct HealthIncrease(double Time, double Amount, int? Group);
private record struct HealthIncrease(double Time, double Amount);
}
}