-
Notifications
You must be signed in to change notification settings - Fork 0
Wife3 Scoring System.hx
HScript-based scoring system that implements Etterna's Wife3 accuracy calculation into Psych Engine.
Features:
- Complete Wife3 Algorithm: Full Etterna-based accuracy calculation
- Timing Feedback: Color-coded timing display shows hit accuracy
- Judge Presets: 9 difficulty presets (J1-J9) plus custom scaling
- 20+ API Functions: Comprehensive API for custom UI development
Wife3 (Wife version 3) is Etterna's timing-based accuracy algorithm. This script provides 20 global callback functions accessible from any Lua or HScript.
- Configuration Functions
- Data Getter Functions
- Utility Functions
- Built-in Features
- Judge Presets
- Grading System
- UI Examples
Enable or disable Wife3 calculations. Does not replace Psych Engine's calculations. See wife3_setReplaceScoreText for replacing score text.
wife3_setEnabled(true) -- Enable (default)
wife3_setEnabled(false) -- DisableSet difficulty preset (1-9). See Judge Presets for details.
wife3_setJudgePreset(4) -- J4 = Standard difficulty
wife3_setJudgePreset(9) -- J9 = JUSTICE (hardest)Manually set judge scale value (advanced users).
wife3_setJudgeScale(1.0) -- Same as J4
wife3_setJudgeScale(0.4) -- Same as J9Note: Scale range is 0.009 to 0.090. Values outside this range are clamped.
Reset all Wife3 counters to zero. Useful for practice mode or custom restart mechanics.
wife3_resetAccuracy()Enable or disable Wife3 score text replacement (replaces Psych Engine's default score display text).
wife3_setReplaceScoreText(true) -- Replace Psych Engine's default score text
wife3_setReplaceScoreText(false) -- Use Psych Engine's default score textEnable or disable the built-in timing feedback display.
wife3_setShowTimingDisplay(true) -- Show timing feedback (default)
wife3_setShowTimingDisplay(false) -- Hide timing feedbackReturns current accuracy percentage (0-100) based on notes hit so far.
local accuracy = wife3_getAccuracy()
-- Example: 98.45Returns current song score (Wife3 calculated).
local score = wife3_getScore()
-- Example: 987654Returns letter grade for a given percentage value.
local currentGrade = wife3_getGrade(wife3_getAccuracy())
-- Returns: 'AAAAA', 'AAAA', 'AAA', 'AA', 'A', 'B', 'C', 'D', or 'F'
local hypotheticalGrade = wife3_getGrade(97.5)
-- Calculate grade for any percentageReturns the current judge scale value.
local scale = wife3_getJudgeScale()
-- Example: 1.0 (J4)Returns the current judge preset as a number (can be fractional for custom scales).
local preset = wife3_getJudgePreset()
-- Returns: 4.0 for J4, 7.25 for custom scale between J7 and J8, etc.Returns whether Wife3 score text replacement is currently enabled.
local isReplacing = wife3_getReplaceScoreText()
-- Returns: true if Wife3 is replacing score text, false otherwiseReturns whether the timing feedback display is currently enabled.
local showTiming = wife3_getShowTimingDisplay()
-- Returns: true if timing display is enabled, false otherwiseGet the number of hits in each timing window:
Returns number of Marvelous hits (≤ 22ms × judge scale).
Returns number of Perfect hits (≤ 45ms × judge scale).
Returns number of Great hits (≤ 90ms × judge scale).
Returns number of Good hits (≤ 135ms × judge scale).
Returns number of Bad hits (≤ 180ms × judge scale).
Get a timing window (in ms) based on current judge scale.
local marvelousWindow = wife3_getTimingWindow('marvelous') -- ~22ms * scale
local perfectWindow = wife3_getTimingWindow('perfect') -- ~45ms * scale
local greatWindow = wife3_getTimingWindow('great') -- ~90ms * scale
local goodWindow = wife3_getTimingWindow('good') -- ~135ms * scale
local badWindow = wife3_getTimingWindow('bad') -- ~180ms * scaleValid window types: 'marvelous', 'perfect', 'great', 'good', 'bad'
Format a number to 2 decimal places.
local formatted = wife3_formatPercent(98.456789)
-- Returns: '98.45'Manually update the score text display. Called automatically when Wife3 score text replacement is enabled.
wife3_updateScoreText()
-- Updates score text with current Wife3 dataThe Wife3 Scoring System includes several built-in features that work out of the box:
By default, Wife3 replaces Psych Engine's score text while keeping Psych Engines style.
-
Default Format:
Score: 987654 | Misses: 3 | Rating: 98.45% (AAA) - Enabled by default: Score text replacement is automatically active
- Score Bop Animation: Maintains Psych Engine's score bounce animation
- Respects Settings: Honors client preferences for score zoom
-- Control score text replacement
wife3_setReplaceScoreText(true) -- Enable Wife3 score text (default)
wife3_setReplaceScoreText(false) -- Use Psych Engine's default score text
-- Check current state
local isReplacing = wife3_getReplaceScoreText()Built-in visual timing feedback shows hit accuracy in real-time:
- Location: Center of the playfield between notes
- Color-Coded: Different colors for different timing windows
- Animation: Smooth fade-in/fade-out with upward movement
-
Format:
+12.34msor-5.67ms
- White: Marvelous (≤22ms × judge scale)
- Yellow: Perfect (≤45ms × judge scale)
- Green: Great (≤90ms × judge scale)
- Cyan: Good (≤135ms × judge scale)
- Magenta: Bad (≤180ms × judge scale)
- Red: Way off (>180ms × judge scale)
-- Control timing display
wife3_setShowTimingDisplay(true) -- Show timing feedback (default)
wife3_setShowTimingDisplay(false) -- Hide timing feedback
-- Check current state
local showTiming = wife3_getShowTimingDisplay()Judge presets control the timing window difficulty. Lower numbers are easier (wider timing windows), higher numbers are harder (tighter timing windows).
| Preset | Judge | Scale Value | Description | Typical Use Case |
|---|---|---|---|---|
| 1 | J1 | 4.0 | Easiest | Casual play, story mode |
| 2 | J2 | 3.0 | Very Easy | Beginner friendly |
| 3 | J3 | 2.0 | Easy | Learning new charts |
| 4 | J4 | 1.0 | Standard | Default/Competitive baseline |
| 5 | J5 | 0.9 | Slightly Hard | Intermediate challenge |
| 6 | J6 | 0.75 | Hard | Advanced players |
| 7 | J7 | 0.6 | Very Hard | Expert challenge |
| 8 | J8 | 0.5 | Extremely Hard | Mastery testing |
| 9 | J9 | 0.4 | JUSTICE | Hardest possible |
wife3_setJudgePreset(4) -- Standard (default)
wife3_setJudgePreset(9) -- JUSTICE (hardest)For fine-tuned control, use wife3_setJudgeScale():
wife3_setJudgeScale(1.0) -- J4 equivalent
wife3_setJudgeScale(0.6) -- J7 equivalent
wife3_setJudgeScale(0.85) -- Custom (between J5 and J6)Wife3 uses Etterna's letter grade system based on accuracy percentage:
| Grade | Min % | Description | Tier |
|---|---|---|---|
| AAAAA | 99.70% | Quadstar | Nearly perfect |
| AAAA | 99.50% | Quad | Exceptional |
| AAA | 99.00% | Triple | Excellent |
| AA | 98.00% | Double | Very Good |
| A | 96.50% | Single | Good |
| B | 93.00% | B Tier | Above Average |
| C | 90.00% | C Tier | Average |
| D | 80.00% | D Tier | Below Average |
| F | < 80.00% | Failed | Needs Improvement |
Grades are calculated using the wife3_getGrade(percent) function:
local currentGrade = wife3_getGrade(wife3_getAccuracy())
-- Returns current grade based on accuracy
local hypotheticalGrade = wife3_getGrade(97.5)
-- Calculate grade for any percentageThe Wife3 Scoring System is designed to be UI-agnostic, providing only the calculation backend. Here are complete UI implementation examples for both Lua and HScript.
For a simpler implementation, here's a minimal Lua example:
-- Simple Wife3 Display (Lua)
function onCreatePost()
makeLuaText('wife3Display', '', 0, 0, getProperty('scoreTxt.y') + 25)
setTextSize('wife3Display', 18)
setTextFont('wife3Display', 'vcr.ttf')
setTextBorder('wife3Display', 1, '000000')
setTextAlignment('wife3Display', 'center')
setObjectCamera('wife3Display', 'hud')
addLuaText('wife3Display')
end
function updateWife3()
local acc = wife3_formatPercent(wife3_getAccuracy())
local grade = wife3_getGrade(wife3_getAccuracy())
local score = wife3_getScore()
setTextString('wife3Display', 'Wife3: ' .. score .. ' | ' .. acc .. '% (' .. grade .. ')')
end
function goodNoteHit(id, data, type, sustain)
if not sustain then updateWife3() end
end
function noteMiss()
updateWife3()
endThis script provides the following 20 global callback functions:
Configuration:
wife3_setEnabled(enabled: Bool)wife3_setJudgePreset(judgeNum: Int)wife3_setJudgeScale(scale: Float)wife3_resetAccuracy()wife3_setReplaceScoreText(replace: Bool)wife3_setShowTimingDisplay(show: Bool)
Data Getters:
wife3_getAccuracy(): Floatwife3_getScore(): Intwife3_getGrade(percent: Float): Stringwife3_getJudgeScale(): Floatwife3_getJudgePreset(): Floatwife3_getReplaceScoreText(): Boolwife3_getShowTimingDisplay(): Bool
Judgement Counters:
wife3_getMarvelousHits(): Intwife3_getPerfectHits(): Intwife3_getGreatHits(): Intwife3_getGoodHits(): Intwife3_getBadHits(): Int
Utilities:
wife3_getTimingWindow(windowType: String): Floatwife3_formatPercent(value: Float): Stringwife3_updateScoreText()