Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fail mode for knockout #201

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions app/dance/rcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,22 @@ func (controller *ReplayController) SetBeatMap(beatMap *beatmap.BeatMap) {

loadFrames(control, replay.ReplayData)

// Check if the replay ends earlier than expected with 100ms of leniency
totalTime := int64(0)
for _, f := range replay.ReplayData {
// Ignore mania seed frame
if f.Time != -12345 {
totalTime += f.Time
}
}
replayEndDiff := totalTime - int64(beatMap.HitObjects[len(beatMap.HitObjects)-1].GetEndTime()+3000)
endsEarly := replayEndDiff < -100
extraText := ""
if endsEarly {
extraText = fmt.Sprintf(" (by %.3fs)", -float64(replayEndDiff)/1000.0)
}
log.Println(fmt.Sprintf("\tEnds early: %t%s", endsEarly, extraText))

mxCombo := replay.MaxCombo

control.newHandling = replay.OsuVersion >= 20190506 // This was when slider scoring was changed, so *I think* replay handling as well: https://osu.ppy.sh/home/changelog/cuttingedge/20190506
Expand Down Expand Up @@ -484,6 +500,10 @@ func (controller *ReplayController) updateMain(nTime float64) {

controller.cursors[i].IsReplayFrame = false
}

if c.replayIndex == len(c.frames)-1 {
controller.ruleset.SetCanHardFail(controller.cursors[i], true)
}
} else {
controller.cursors[i].LeftKey = false
controller.cursors[i].RightKey = false
Expand Down
4 changes: 2 additions & 2 deletions app/rulesets/osu/healthprocessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (
MaxHp = 200.0
)

type FailListener func()
type FailListener func() FailResult

type drain struct {
start, end int64
Expand Down Expand Up @@ -302,4 +302,4 @@ func (hp *HealthProcessor) Update(time int64) {

func (hp *HealthProcessor) AddFailListener(listener FailListener) {
hp.failListeners = append(hp.failListeners, listener)
}
}
75 changes: 59 additions & 16 deletions app/rulesets/osu/ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ const (

var GradesText = []string{"D", "C", "B", "A", "S", "SH", "SS", "SSH", "None"}

type FailResult int64

const (
IgnoreFail = FailResult(iota)
SoftFail
HardFail
)

type ClickAction int64

const (
Expand Down Expand Up @@ -111,7 +119,9 @@ type subSet struct {
katuCount int64
recoveries int
scoreProcessor scoreProcessor
failed bool
canHardFail bool
softFailed bool
hardFailed bool
}

type MapTo struct {
Expand All @@ -125,7 +135,9 @@ type hitListener func(cursor *graphics.Cursor, time int64, number int64, positio

type endListener func(time int64, number int64)

type failListener func(cursor *graphics.Cursor)
type failListener func(cursor *graphics.Cursor, failResult FailResult)

type recoveryListener func(cursor *graphics.Cursor)

type OsuRuleSet struct {
beatMap *beatmap.BeatMap
Expand All @@ -136,11 +148,12 @@ type OsuRuleSet struct {
mapStats []*MapTo
oppDiffs map[difficulty.Modifier][]performance.Stars

queue []HitObject
processed []HitObject
hitListener hitListener
endListener endListener
failListener failListener
queue []HitObject
processed []HitObject
hitListener hitListener
endListener endListener
failListener failListener
recoveryListener recoveryListener

experimentalPP bool
}
Expand Down Expand Up @@ -230,8 +243,8 @@ func NewOsuRuleset(beatMap *beatmap.BeatMap, cursors []*graphics.Cursor, mods []
recoveries = 2
}

hp.AddFailListener(func() {
ruleset.failInternal(player)
hp.AddFailListener(func() FailResult {
return ruleset.failInternal(player)
})

var sc scoreProcessor
Expand Down Expand Up @@ -311,8 +324,14 @@ func (set *OsuRuleSet) Update(time int64) {
}
}

for _, subSet := range set.cursors {
for cursor, subSet := range set.cursors {
subSet.hp.Update(time)
if subSet.softFailed && !subSet.hardFailed && subSet.hp.Health >= 190 {
subSet.softFailed = false
if set.recoveryListener != nil {
set.recoveryListener(cursor)
}
}
}

if len(set.queue) == 0 && len(set.processed) == 0 && !set.ended {
Expand Down Expand Up @@ -608,27 +627,37 @@ func (set *OsuRuleSet) CanBeHit(time int64, object HitObject, player *difficulty
return Click
}

func (set *OsuRuleSet) failInternal(player *difficultyPlayer) {
func (set *OsuRuleSet) failInternal(player *difficultyPlayer) FailResult {
subSet := set.cursors[player.cursor]

if player.diff.CheckModActive(difficulty.NoFail | difficulty.Relax | difficulty.Relax2) {
return
return IgnoreFail
}

// EZ mod gives 2 additional lives
if subSet.recoveries > 0 {
subSet.hp.Increase(160, false)
subSet.recoveries--

return
return IgnoreFail
}

failResult := SoftFail
if subSet.canHardFail {
failResult = HardFail
}

// actual fail
if set.failListener != nil && !subSet.failed {
set.failListener(player.cursor)
if set.failListener != nil && (!subSet.softFailed && !subSet.hardFailed) {
set.failListener(player.cursor, failResult)
}

subSet.failed = true
if subSet.canHardFail {
subSet.hardFailed = true
} else {
subSet.softFailed = true
}
return failResult
}

func (set *OsuRuleSet) SetListener(listener hitListener) {
Expand All @@ -643,6 +672,10 @@ func (set *OsuRuleSet) SetFailListener(listener failListener) {
set.failListener = listener
}

func (set *OsuRuleSet) SetRecoveryListener(listener recoveryListener) {
set.recoveryListener = listener
}

func (set *OsuRuleSet) GetResults(cursor *graphics.Cursor) (float64, int64, int64, Grade) {
subSet := set.cursors[cursor]
return subSet.accuracy, subSet.maxCombo, subSet.scoreProcessor.GetScore(), subSet.grade
Expand All @@ -668,6 +701,16 @@ func (set *OsuRuleSet) IsPerfect(cursor *graphics.Cursor) bool {
return subSet.maxCombo == int64(set.mapStats[subSet.numObjects-1].maxCombo)
}

func (set *OsuRuleSet) GetFailState(cursor *graphics.Cursor) (bool, bool, bool) {
subSet := set.cursors[cursor]
return subSet.canHardFail, subSet.softFailed, subSet.hardFailed
}

func (set* OsuRuleSet) SetCanHardFail(cursor *graphics.Cursor, canHardFail bool) {
subSet := set.cursors[cursor]
subSet.canHardFail = canHardFail
}

func (set *OsuRuleSet) GetPlayer(cursor *graphics.Cursor) *difficultyPlayer {
subSet := set.cursors[cursor]
return subSet.player
Expand Down
6 changes: 6 additions & 0 deletions app/settings/knockout.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,10 @@ const (

//Other result than 300 will knock the player out
SSOrQuit

// Players get knocked out if they fail
Fail

// Same as Fail, but allows players to get revived if they get above 95% HP (for multi replays)
FailWithRecovery
)
Loading