From e59955fa806211dbd8578da3778099c78076db17 Mon Sep 17 00:00:00 2001 From: Flameshadowxeroshin Date: Sun, 6 May 2012 00:45:47 -0500 Subject: [PATCH] ScoringEngine2 --- Themes/_fallback/Scripts/04 Scoring.lua | 1220 +++++------------ .../Scripts/05 NewScoringFrontend.lua | 170 +++ .../_fallback/Scripts/05 ScoringEngine2.lua | 118 ++ .../ScreenEvaluation decorations/default.lua | 4 + .../ScreenGameplay decorations/default.lua | 3 +- .../default.lua | 6 + 6 files changed, 654 insertions(+), 867 deletions(-) create mode 100644 Themes/_fallback/Scripts/05 NewScoringFrontend.lua create mode 100644 Themes/_fallback/Scripts/05 ScoringEngine2.lua diff --git a/Themes/_fallback/Scripts/04 Scoring.lua b/Themes/_fallback/Scripts/04 Scoring.lua index d3cf7fd46b..bc84d85ce7 100644 --- a/Themes/_fallback/Scripts/04 Scoring.lua +++ b/Themes/_fallback/Scripts/04 Scoring.lua @@ -1,865 +1,355 @@ ---internals table -local Shared = {}; ---Special Scoring types. -local r = {}; -local DisabledScoringModes = { '[SSC] Radar Master' }; ---the following metatable makes any missing value in a table 0 instead of nil. -local ZeroIfNotFound = { __index = function() return 0 end; }; - --- Retrieve the amount of taps/holds/rolls involved. Used for some formulas. -function GetTotalItems(radars) - local total = radars:GetValue('RadarCategory_TapsAndHolds') - total = total + radars:GetValue('RadarCategory_Holds') - total = total + radars:GetValue('RadarCategory_Rolls') - -- [ja] Liftを加えると一部二重加算になるため除外する。 - -- total = total + radars:GetValue('RadarCategory_Lifts') - - -- [en] prevent divide by 0 - -- [ja] 0除算対策(しなくても動作するけど満点になっちゃうんで) - return math.max(1,total); -end; - --- Determine whether marvelous timing is to be considered. -function IsW1Allowed(tapScore) - return tapScore == 'TapNoteScore_W2' - and (PREFSMAN:GetPreference("AllowW1") ~= 'AllowW1_Never' - or not (GAMESTATE:IsCourseMode() and - PREFSMAN:GetPreference("AllowW1") == 'AllowW1_CoursesOnly')); -end; - --- Get the radar values directly. The individual steps aren't used much. -function GetDirectRadar(player) - return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player); -end; - ------------------------------------------------------------ --- StepMania 3.9 (Plus) Scorings by @803832 --- 3.9 MAX2 --- 3.9 5TH --- 3.9Plus HYBRID --- 3.9Plus SN --- 3.9Plus SN2 --- note: 3.9Plus PIU Scoring cannot be implemented due to no NumTapsInRow --- in JudgmentMessage. This is fixed in hanubeki-modified-sm-ssc revision 6c7184e7df9a: --- http://code.google.com/r/hanubeki-modified-sm-ssc/source/detail?r=6c7184e7df9a3694649f965c2976859bb9e45963 ------------------------------------------------------------ -local function isW2OrAbove(tns) - if tns == 'TapNoteScore_W1' or tns == 'TapNoteScore_W2' then - return true; - end; - return false; -end -local sm3_Steps = {0,0}; -local sm3_Score = {0,0}; -local sm3_CurMaxScore = {0,0}; -local sm3_Combo = {0,0}; -local sm3_CurMaxCombo = {0,0}; -local sm3_GradePoints = {0,0}; -local sm3_Bonus = {0,0}; -local sm3_MaxBonus = {0,0}; - -r["3.9 MAX2"] = function(params, pss) - local multLookup = - { - ['TapNoteScore_W1'] = 10, - ['TapNoteScore_W2'] = GAMESTATE:ShowW1() and 9 or 10, - ['TapNoteScore_W3'] = 5 - }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - -- 1+2+3+...+totalItems value/の値 - local sTotal = (totalItems+1)*totalItems/2; - local steps = GAMESTATE:GetCurrentSteps(params.Player); - local meter = steps:GetMeter(); - meter = clamp(meter,1,10); - - -- [ja] 満点を求める - local length = 1; - if (GAMESTATE:GetCurrentSong():IsMarathon()) then - length = 3; - elseif (GAMESTATE:GetCurrentSong():IsLong()) then - length = 2; - end; - local baseScore = meter * 10000000 * length; - - local sOne = baseScore/sTotal; - - local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; - - -- [ja] スコアが0の時に初期化 - if pss:GetScore()==0 then - sm3_Steps[p] = 0; - end; - - -- [ja] 現在のステップ数 - -- [ja] 地雷とHoldCheckpointsの場合は加算しない - if params.TapNoteScore ~= "TapNoteScore_HitMine" and - params.TapNoteScore ~= "TapNoteScore_AvoidMine" and - params.TapNoteScore ~= "TapNoteScore_CheckpointHit" and - params.TapNoteScore ~= "TapNoteScore_CheckpointMiss" - then - sm3_Steps[p]=sm3_Steps[p]+1; - end; - - -- [en] current score - -- [ja] 今回加算するスコア(W1の時) - local vScore = sOne*sm3_Steps[p]; - pss:SetCurMaxScore(pss:GetCurMaxScore()+math.floor(vScore)); - -- [ja] 判定によって加算量を変更 - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - vScore = vScore; - else - if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then - vScore = 0; - else - vScore = vScore*multLookup[params.TapNoteScore]/10; - end; - end; - - -- [ja] 落ちていた場合は入るスコアが減る - if (pss:GetFailed()) then - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - -- [ja] O.K.判定時は10点 - sm3_Score[p] = sm3_Score[p]+10; - elseif (params.HoldNoteScore ~= 'HoldNoteScore_LetGo') then - -- [ja] O.K.でもN.G.でもない場合のスコア: - -- W1 (Marvelous): 10 - -- W2 (Perfect): 9 - -- W3 (Great): 5 - sm3_Score[p] = sm3_Score[p]+multLookup[params.TapNoteScore]; - end; - - -- [ja] 5点単位の処理がなぜかここでされる - if multLookup[params.TapNoteScore] > 0 then - sm3_Score[p] = math.floor((sm3_Score[p] + 2) / 5) * 5; - end; - else - pss:SetScore(pss:GetScore()+math.floor(vScore)); - end; - - if (sm3_Steps[p] == totalItems and not pss:GetFailed()) then - -- [ja] 最後の1ステップがW2以上の場合、端数を加算する - -- [ja] 端数は設定上の満点と最終ステップ時点での満点の差から求める - if (isW2OrAbove(params.TapNoteScore) or params.HoldNoteScore == 'HoldNoteScore_Held') then - pss:SetScore(pss:GetScore()+(baseScore-pss:GetCurMaxScore())); - pss:SetCurMaxScore(pss:GetCurMaxScore()+(baseScore-pss:GetCurMaxScore())); - end; - end; -end; - --- TODO: Don't add combo bonus if autoplay -r["3.9 5TH"] = function(params, pss) - local multLookup = - { - ['TapNoteScore_W1'] = 10, - ['TapNoteScore_W2'] = GAMESTATE:ShowW1() and 9 or 10, - ['TapNoteScore_W3'] = 5 - }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - -- 1+2+3+...+totalItems value/の値 - local sTotal = (totalItems+1)*totalItems/2; - local steps = GAMESTATE:GetCurrentSteps(params.Player); - local meter = steps:GetMeter(); - meter = clamp(meter,1,10); - - -- [ja] 満点を求める - local length = 1; - if (GAMESTATE:GetCurrentSong():IsMarathon()) then - length = 3; - elseif (GAMESTATE:GetCurrentSong():IsLong()) then - length = 2; - end; - local baseScore = (meter * length + 1) * 5000000; - - local sOne = baseScore/sTotal; - - local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; - - -- [ja] スコアが0の時に初期化 - if pss:GetScore()==0 then - sm3_Steps[p] = 0; - sm3_Score[p] = 0; - sm3_CurMaxScore[p] = 0; - sm3_Combo[p] = 0; - sm3_CurMaxCombo[p] = 0; - sm3_GradePoints[p] = 0; - sm3_Bonus[p] = 0; - sm3_MaxBonus[p] = 0; - end; - - -- [ja] 現在のステップ数 - -- [ja] 地雷とHoldCheckpointsの場合は加算しない - if params.TapNoteScore ~= "TapNoteScore_HitMine" and - params.TapNoteScore ~= "TapNoteScore_AvoidMine" and - params.TapNoteScore ~= "TapNoteScore_CheckpointHit" and - params.TapNoteScore ~= "TapNoteScore_CheckpointMiss" - then - sm3_Steps[p]=sm3_Steps[p]+1; - end; - - -- [en] current score - -- [ja] 今回加算するスコア(W1の時) - local vScore = sOne*sm3_Steps[p]; - sm3_CurMaxScore[p] = sm3_CurMaxScore[p]+math.floor(vScore); - - -- [ja] グレードの計算は5THではなくMAX2方式 - local gradeWeightTable = { - ['TapNoteScore_W1'] = 2, - ['TapNoteScore_W2'] = 2, - ['TapNoteScore_W3'] = 1, - ['TapNoteScore_W5'] = -4, - ['TapNoteScore_Miss'] = -8, - }; - setmetatable(gradeWeightTable, ZeroIfNotFound); - - -- [ja] 判定によって加算量を変更 - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - vScore = vScore; - sm3_GradePoints[p] = sm3_GradePoints[p] + 6; - else - if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then - vScore = 0; - else - vScore = vScore*multLookup[params.TapNoteScore]/10; - sm3_GradePoints[p] = sm3_GradePoints[p] + gradeWeightTable[params.TapNoteScore]; - end; - end; - - -- [ja] コンボは自前で処理する - if not params.HoldNoteScore then - if params.TapNoteScore == 'TapNoteScore_W1' or - params.TapNoteScore == 'TapNoteScore_W2' or - ( - GAMESTATE:GetPlayMode() ~= 'PlayMode_Oni' and - params.TapNoteScore == 'TapNoteScore_W3' - ) - then - sm3_Combo[p] = sm3_Combo[p] + 1; - -- [ja] 地雷とHoldCheckpointsの場合はリセットしない - elseif params.TapNoteScore ~= "TapNoteScore_HitMine" and - params.TapNoteScore ~= "TapNoteScore_AvoidMine" and - params.TapNoteScore ~= "TapNoteScore_CheckpointHit" and - params.TapNoteScore ~= "TapNoteScore_CheckpointMiss" - then - sm3_Combo[p] = 0; - end; - sm3_CurMaxCombo[p] = sm3_CurMaxCombo[p] + 1; - end; - - local bonusTable = - { - ['TapNoteScore_W1'] = 55, - ['TapNoteScore_W2'] = 55, - ['TapNoteScore_W3'] = 33 - }; - setmetatable(bonusTable, ZeroIfNotFound); - - -- [ja] 落ちていた場合は入るスコアが減る - if (pss:GetFailed()) then - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - -- [ja] O.K.判定時は10点 - sm3_Score[p] = sm3_Score[p]+10; - elseif (params.HoldNoteScore ~= 'HoldNoteScore_LetGo') then - -- [ja] O.K.でもN.G.でもない場合のスコア: - -- W1 (Marvelous): 10 - -- W2 (Perfect): 9 - -- W3 (Great): 5 - sm3_Score[p] = sm3_Score[p]+multLookup[params.TapNoteScore]; - end; - - -- [ja] 5点単位の処理がなぜかここでされる - if multLookup[params.TapNoteScore] > 0 then - sm3_Score[p] = math.floor((sm3_Score[p] + 2) / 5) * 5; - end; - else - sm3_Score[p] = sm3_Score[p]+math.floor(vScore); - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - sm3_Bonus[p] = sm3_Bonus[p]+55*sm3_Combo[p]; - elseif (params.HoldNoteScore ~= 'HoldNoteScore_LetGo') then - sm3_Bonus[p] = sm3_Bonus[p]+bonusTable[params.TapNoteScore]*sm3_Combo[p]; - end; - sm3_MaxBonus[p] = sm3_MaxBonus[p]+55*sm3_CurMaxCombo[p]; - end; - - if (sm3_Steps[p] == totalItems and not pss:GetFailed()) then - -- [ja] 最後の1ステップがW2以上の場合、端数を加算する - -- [ja] 端数は設定上の満点と最終ステップ時点での満点の差から求める - if (isW2OrAbove(params.TapNoteScore) or params.HoldNoteScore == 'HoldNoteScore_Held') then - sm3_Score[p] = sm3_Score[p]+(baseScore-sm3_CurMaxScore[p]); - sm3_CurMaxScore[p] = sm3_CurMaxScore[p]+(baseScore-sm3_CurMaxScore[p]); - end; - end; - - -- [ja] 5点単位の処理は5TH方式のみでされる - pss:SetScore(sm3_Score[p] - sm3_Score[p] % 5); - pss:SetCurMaxScore(sm3_CurMaxScore[p] - sm3_CurMaxScore[p] % 5); - - if (sm3_Steps[p] == totalItems and not pss:GetFailed()) then - -- [ja] コンボボーナスとグレードボーナスを加算 - -- [ja] 本当はリザルト画面でやりたいんだけどね - local totalTaps = radarValues:GetValue('RadarCategory_TapsAndHolds'); - local totalHolds = radarValues:GetValue('RadarCategory_Holds') + radarValues:GetValue('RadarCategory_Rolls'); - - local gradeBonusTable = { - -- Threshold: sm3_GradePoints[p] / (totalTaps * 2 + totalHolds * 6) * 100 - { Threshold = 100, Bonus = 10000000 }, - { Threshold = 93, Bonus = 1000000 }, - { Threshold = 80, Bonus = 100000 }, - { Threshold = 65, Bonus = 10000 }, - { Threshold = 45, Bonus = 1000 }, - -- [ja] 45%に達していない場合は100点とする - }; - - local gradeBonus = 100; - - for i = 1,#gradeBonusTable do - if (sm3_GradePoints[p] / (totalTaps * 2 + totalHolds * 6) * 100 >= gradeBonusTable[i].Threshold) then - gradeBonus = gradeBonusTable[i].Bonus; - break; - end; - end; - - if pss:GetFailed() then - gradeBonus = 0; - end; - - pss:SetScore(pss:GetScore()+sm3_Bonus[p]+gradeBonus); - pss:SetCurMaxScore(pss:GetCurMaxScore()+sm3_MaxBonus[p]+10000000); - end; -end; - -r["3.9Plus HYBRID"] = function(params, pss) - local multLookup = - { - ['TapNoteScore_W1'] = 10, - ['TapNoteScore_W2'] = GAMESTATE:ShowW1() and 9 or 10, - ['TapNoteScore_W3'] = 5 - }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - -- 1+2+3+...+totalItems value/の値 - local sTotal = (totalItems+1)*totalItems/2; - local steps = GAMESTATE:GetCurrentSteps(params.Player); - local meter = steps:GetMeter(); - meter = clamp(meter,1,10); - - -- [ja] 満点を求める - local length = 1; - if (GAMESTATE:GetCurrentSong():IsMarathon()) then - length = 3; - elseif (GAMESTATE:GetCurrentSong():IsLong()) then - length = 2; - end; - local baseScore = 100000000 * length; - - local sOne = baseScore/sTotal; - - local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; - - -- [ja] スコアが0の時に初期化 - if pss:GetScore()==0 then - sm3_Steps[p] = 0; - end; - - -- [ja] 現在のステップ数 - -- [ja] 地雷とHoldCheckpointsの場合は加算しない - if params.TapNoteScore ~= "TapNoteScore_HitMine" and - params.TapNoteScore ~= "TapNoteScore_AvoidMine" and - params.TapNoteScore ~= "TapNoteScore_CheckpointHit" and - params.TapNoteScore ~= "TapNoteScore_CheckpointMiss" - then - sm3_Steps[p]=sm3_Steps[p]+1; - end; - - -- [en] current score - -- [ja] 今回加算するスコア(W1の時) - local vScore = sOne*sm3_Steps[p]; - pss:SetCurMaxScore(pss:GetCurMaxScore()+math.floor(vScore)); - -- [ja] 判定によって加算量を変更 - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - vScore = vScore; - else - if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then - vScore = 0; - else - vScore = vScore*multLookup[params.TapNoteScore]/10; - end; - end; - - -- [ja] 落ちていた場合は入るスコアが減る - if (pss:GetFailed()) then - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - -- [ja] O.K.判定時は10点 - pss:SetScore(pss:GetScore()+10); - elseif (params.HoldNoteScore ~= 'HoldNoteScore_LetGo') then - -- [ja] O.K.でもN.G.でもない場合のスコア: - -- W1 (Marvelous): 10 - -- W2 (Perfect): 9 - -- W3 (Great): 5 - pss:SetScore(pss:GetScore()+multLookup[params.TapNoteScore]); - end; - - -- [ja] 5点単位の処理がなぜかここでされる - if multLookup[params.TapNoteScore] > 0 then - pss:SetScore(math.floor((pss:GetScore() + 2) / 5) * 5); - end; - else - pss:SetScore(pss:GetScore()+math.floor(vScore)); - end; - - if (sm3_Steps[p] == totalItems and not pss:GetFailed()) then - -- [ja] 最後の1ステップがW2以上の場合、端数を加算する - -- [ja] 端数は設定上の満点と最終ステップ時点での満点の差から求める - if (isW2OrAbove(params.TapNoteScore) or params.HoldNoteScore == 'HoldNoteScore_Held') then - pss:SetScore(pss:GetScore()+(baseScore-pss:GetCurMaxScore())); - pss:SetCurMaxScore(pss:GetCurMaxScore()+(baseScore-pss:GetCurMaxScore())); - end; - end; -end; - -r["3.9Plus SN"] = function(params, pss) - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - - -- [ja] 満点を求める - local length = 1; - if (GAMESTATE:GetCurrentSong():IsMarathon()) then - length = 3; - elseif (GAMESTATE:GetCurrentSong():IsLong()) then - length = 2; - end; - local baseScore = 10000000 * length; - - -- [en] current score - -- [ja] 今回加算するスコア - local multLookup = - { - ['TapNoteScore_W1'] = math.floor(baseScore / totalItems), - ['TapNoteScore_W2'] = math.floor(baseScore / totalItems), - ['TapNoteScore_W3'] = math.floor(math.floor(baseScore / 2) / totalItems) - }; - setmetatable(multLookup, ZeroIfNotFound); - local vScore = multLookup[params.TapNoteScore]; - pss:SetCurMaxScore(pss:GetCurMaxScore()+multLookup['TapNoteScore_W1']); - - -- [ja] 判定によって加算量を変更 - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - vScore = multLookup['TapNoteScore_W1']; - elseif (params.HoldNoteScore == 'HoldNoteScore_LetGo') then - vScore = 0; - end; - - -- [ja] 落ちていた場合は入るスコアが減る - if (not pss:GetFailed()) then - pss:SetScore(pss:GetScore()+math.floor(vScore)); - end; - - -- [ja] 端数の処理はされていないようだ -end; - -r["3.9Plus SN2"] = function(params, pss) - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - - -- [ja] 満点を求める - local length = 1; - if (GAMESTATE:GetCurrentSong():IsMarathon()) then - length = 3; - elseif (GAMESTATE:GetCurrentSong():IsLong()) then - length = 2; - end; - local baseScore = 1000000 * length; - - -- [en] current score - -- [ja] 今回加算するスコア - local multLookup = - { - ['TapNoteScore_W1'] = math.floor(baseScore / totalItems), - ['TapNoteScore_W2'] = math.floor(baseScore / totalItems) - 10, - ['TapNoteScore_W3'] = math.floor(math.floor(baseScore / 2) / totalItems) - 10 - }; - setmetatable(multLookup, ZeroIfNotFound); - local vScore = multLookup[params.TapNoteScore]; - pss:SetCurMaxScore(pss:GetCurMaxScore()+multLookup['TapNoteScore_W1']); - - -- [ja] 判定によって加算量を変更 - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - vScore = multLookup['TapNoteScore_W1']; - elseif (params.HoldNoteScore == 'HoldNoteScore_LetGo') then - vScore = 0; - end; - - -- [ja] 落ちていた場合は入るスコアが減る - if (not pss:GetFailed()) then - pss:SetScore(pss:GetScore()+math.floor(vScore)); - end; - - -- [ja] 端数の処理はされていないようだ -end; - ------------------------------------------------------------ --- Oldschool scoring, best described as a modified 4th mix --- scheme with a little 1st mix influence ------------------------------------------------------------ -r['Oldschool'] = function(params, pss) - local bestPoints = 999 - local scoreLookupTable = - { - ['TapNoteScore_W1']=999, - ['TapNoteScore_W2']=IsW1Allowed('TapNoteScore_W2') and 888 or 999, - ['TapNoteScore_W3']=777, - ['TapNoteScore_W4']=555, - ['TapNoteScore_W5']=111, - }; - setmetatable(scoreLookupTable, ZeroIfNotFound); - local comboBonusForThisStep = (pss:GetCurrentCombo()*111)^1.1; - local capScore = 1000000000; - pss:SetCurMaxScore(capScore); --i don't really care about weird scoring modes -fsx - local pointsGot = comboBonusForThisStep + scoreLookupTable[params.TapNoteScore] + (params.HoldNoteScore == 'HoldNoteScore_Held' and 777 or 0); - pss:SetScore(clamp(pss:GetScore()+pointsGot,0,capScore)); -end; - ------------------------------------------------------------ --- DDR MAX2/Extreme(-esque) Scoring by @sakuraponila ------------------------------------------------------------ -local ext_Steps = {0,0}; -r['DDR Extreme'] = function(params, pss) - local multLookup = - { - ['TapNoteScore_W1'] = 10, - ['TapNoteScore_W2'] = 9, - ['TapNoteScore_W3'] = 5 - }; - setmetatable(multLookup, ZeroIfNotFound); - local steps = GAMESTATE:GetCurrentSteps(params.Player); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - -- 1 + 2 + 3 + ... + totalItems value/の値 - local sTotal = (totalItems + 1) * totalItems / 2; - local meter = steps:GetMeter(); - if (steps:IsAnEdit()) then - meter = 5; - else - meter = math.min(10,meter); - end; - -- [en] score for one step - -- [ja] 1ステップあたりのスコア - local baseScore = meter * 1000000 - if (GAMESTATE:GetCurrentSong():IsMarathon()) then - baseScore = baseScore * 3; - elseif (GAMESTATE:GetCurrentSong():IsLong()) then - baseScore = baseScore * 2; - end; - local sOne = math.floor(baseScore / sTotal); - -- [en] measures for 5 points of units - -- [ja] 5点単位のための処置 - sOne = sOne - sOne % 5; - -- [en] because fractions are added by the last step, get value - -- [ja] 端数は最後の1ステップで加算するのでその値を取得 - local sLast = baseScore - (sOne * sTotal); - - local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; - -- [en] initialized when score is 0 - -- [ja] スコアが0の時に初期化 - if pss:GetScore() == 0 then - ext_Steps[p] = 0; - end; - -- [en] now step count - -- [ja] 現在のステップ数 - ext_Steps[p] = ext_Steps[p] + 1; - -- [en] current score - -- [ja] 今回加算するスコア(W1の時) - local vScore = sOne * ext_Steps[p]; - pss:SetCurMaxScore(pss:GetCurMaxScore() + vScore); - -- [ja] 判定によって加算量を変更 - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - -- [ja] O.K.判定時は問答無用で満点 - vScore = vScore; - else - -- [ja] N.G.判定時は問答無用で0点 - if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then - vScore = 0; - -- [en] non-long note scoring - -- [ja] それ以外ということは、ロングノート以外の判定である - else - vScore = vScore * multLookup[params.TapNoteScore] / 10 - end; - end; - -- [en] measures for 5 points of units - -- [ja] ここでも5点単位のための処置 - vScore = vScore - vScore % 5 - pss:SetScore(pss:GetScore() + vScore); - -- if one of the last step, add the fractions - -- [ja] 最後の1ステップの場合、端数を加算する - if ((vScore > 0) and (ext_Steps[p] == totalItems)) then - pss:SetScore(pss:GetScore() + sLast); - end; -end; - ------------------------------------------------------------ --- HYBRID Scoring, contributed by @waiei ------------------------------------------------------------ -local hyb_Steps={0,0}; -r['Hybrid'] = function(params, pss) - local multLookup = - { - ['TapNoteScore_W1'] = 10, - ['TapNoteScore_W2'] = 9, - ['TapNoteScore_W3'] = 5 - }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - -- 1+2+3+...+totalItems value/の値 - local sTotal = (totalItems+1)*totalItems/2; - -- [en] Score for one song - -- [ja] 1ステップあたりのスコア - local sOne = math.floor(100000000/sTotal); - -- [ja] 端数は最後の1ステップで加算するのでその値を取得 - local sLast = 100000000-(sOne*sTotal); - - local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; - - -- [ja] スコアが0の時に初期化 - if pss:GetScore()==0 then - hyb_Steps[p]=0; - end; - - -- [ja] 現在のステップ数 - hyb_Steps[p]=hyb_Steps[p]+1; - -- [en] current score - -- [ja] 今回加算するスコア(W1の時) - local vScore = sOne*hyb_Steps[p]; - pss:SetCurMaxScore(pss:GetCurMaxScore()+vScore); - -- [ja] 判定によって加算量を変更 - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - vScore = vScore; - else - if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then - vScore = 0; - else - vScore = vScore*multLookup[params.TapNoteScore]/10; - end; - end; - pss:SetScore(pss:GetScore()+vScore); - - -- [ja] 最後の1ステップの場合、端数を加算する - if ((vScore > 0) and (hyb_Steps[p] == totalItems)) then - pss:SetScore(pss:GetScore()+sLast); - end; -end; - ------------------------------------------------------------ --- DDR SuperNOVA scoring (Use MARVELOUS) by @sakuraponila ------------------------------------------------------------ -local sntmp_Score = {0,0}; -local sntmp_Steps = {0,0}; -r['DDR SuperNOVA'] = function(params, pss) - local multLookup = - { - ['TapNoteScore_W1'] = 3, - ['TapNoteScore_W2'] = 2, - ['TapNoteScore_W3'] = 1 - }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues) - local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; - - -- initialized when score is 0 - -- [ja] スコアが0の時に初期化 - if pss:GetScore() == 0 then - sntmp_Score[p] = 0; - sntmp_Steps[p] = 0; - end; - - -- [ja] 判定によって加算量を変更 - local maxAdd = 0; - -- [ja] O.K.判定時は問答無用で満点 - if params.HoldNoteScore == 'HoldNoteScore_Held' then - maxAdd = 3; - else - -- [ja] N.G.判定時は問答無用で0点 - if params.HoldNoteScore == 'HoldNoteScore_LetGo' then - maxAdd = 0; - -- [ja] それ以外ということは、ロングノート以外の判定である - else - maxAdd = multLookup[params.TapNoteScore]; - end - end; - sntmp_Score[p] = sntmp_Score[p] + maxAdd; - - -- [ja] 踏み踏みしたステップ数 - sntmp_Steps[p] = sntmp_Steps[p] + 1; - -- [ja] 現時点での、All W1判定の時のスコア - pss:SetCurMaxScore(math.floor(10000000 * sntmp_Steps[p] / totalItems / 3)); - -- [ja] 計算して代入 - pss:SetScore(math.floor(10000000 * sntmp_Score[p] / totalItems / 3)); -end; - ------------------------------------------------------------ --- DDR SuperNOVA 2 scoring by @waiei ------------------------------------------------------------ -local sn2tmp_Sub={0,0}; -local sn2tmp_Score={0,0}; -local sn2tmp_Steps={0,0}; -r['DDR SuperNOVA 2'] = function(params, pss) - local multLookup = - { - ['TapNoteScore_W1'] = 10, - ['TapNoteScore_W2'] = 10, - ['TapNoteScore_W3'] = 5 - }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; - - -- [ja] スコアが0の時に初期化 - if pss:GetScore()==0 then - sn2tmp_Sub[p]=0; - sn2tmp_Score[p]=0; - sn2tmp_Steps[p]=0; - end; - - -- [ja] maxAdd は 加算する最高点を 10 とした時の値(つまり、10=100% / 5=50%) - local maxAdd = 0; - -- [ja] O.K.判定時は問答無用で満点 - if params.HoldNoteScore == 'HoldNoteScore_Held' then - maxAdd = 10; - else - -- [ja] N.G.判定時は問答無用で0点 - if params.HoldNoteScore == 'HoldNoteScore_LetGo' then - maxAdd = 0; - -- [ja] それ以外ということは、ロングノート以外の判定である - else - maxAdd = multLookup[params.TapNoteScore]; - if (params.TapNoteScore == 'TapNoteScore_W2') or (params.TapNoteScore=='TapNoteScore_W3') then - -- [ja] W2とW3の数を記録 - sn2tmp_Sub[p]=sn2tmp_Sub[p]+1; - end; - end - end; - sn2tmp_Score[p]=sn2tmp_Score[p]+maxAdd; - -- [ja] 踏み踏みしたステップ数 - sn2tmp_Steps[p]=sn2tmp_Steps[p]+1; - -- [ja] 現時点での、All W1判定の時のスコア - pss:SetCurMaxScore(math.floor(10000*sn2tmp_Steps[p]/totalItems) * 10); - - -- [ja] 計算して代入 - pss:SetScore((math.floor(10000*sn2tmp_Score[p]/totalItems) * 10) - (sn2tmp_Sub[p]*10) ); -end; - ------------------------------------------------------------ --- Radar Master (disabled) --- (todo: get this working with StepMania 5) ------------------------------------------------------------ -r['[SSC] Radar Master'] = function(params, pss) - local masterTable = { - ['RadarCategory_Stream'] = 0, - ['RadarCategory_Voltage'] = 0, - ['RadarCategory_Air'] = 0, - ['RadarCategory_Freeze'] = 0, - ['RadarCategory_Chaos'] = 0 - }; - local totalRadar = 0; - local finalScore = 0; - for k,v in pairs(masterTable) do - local firstRadar = GetDirectRadar(params.Player):GetValue(k); - if firstRadar == 0 then - masterTable[k] = nil; - else - masterTable[k] = firstRadar; - totalRadar = totalRadar + firstRadar; - end; - end; - -- two loops are needed, because we need to calculate totalRadar - -- to actually calculate any part of the score - for k,v in pairs(masterTable) do - local curPortion = pss:GetRadarActual():GetValue(k) / v; - finalScore = finalScore + curPortion*(500000000*(v/totalRadar)); - end; - pss:SetScore(finalScore); -end; - ------------------------------------------------------------- --- Marvelous Incorporated Grading System (or MIGS for short) --- basically like DP scoring with locked DP values ------------------------------------------------------------- -r['MIGS'] = function(params,pss) - local curScore = 0; - local tapScoreTable = - { - ['TapNoteScore_W1'] = 3, - ['TapNoteScore_W2'] = 2, - ['TapNoteScore_W3'] = 1, - ['TapNoteScore_W5'] = -4, - ['TapNoteScore_Miss'] = -8 - }; - for k,v in pairs(tapScoreTable) do - curScore = curScore + ( pss:GetTapNoteScores(k) * v ); - end; - curScore = math.max(0,curScore + ( pss:GetHoldNoteScores('HoldNoteScore_Held') * 6 )); - pss:SetScore(curScore); -end; - --------------------------------------------------------------- --- 1bilDP scoring because I can. --------------------------------------------------------------- -r['Billions DP']= function(params,pss) - local poss = pss:GetPossibleDancePoints() - pss:SetScore(math.floor((pss:GetActualDancePoints()/poss)*1000000000)) - pss:SetCurMaxScore(math.floor((pss:GetCurrentPossibleDancePoints()/poss)*1000000000)) -end - -------------------------------------------------------------------------------- --- Formulas end here. - -for v in ivalues(DisabledScoringModes) do r[v] = nil end -Scoring = r; - -function UserPrefScoringMode() - local baseChoices = {} - for k,v in pairs(Scoring) do table.insert(baseChoices,k) end - if next(baseChoices) == nil then UndocumentedFeature "No scoring modes available" end - local t = { - Name = "UserPrefScoringMode"; - LayoutType = "ShowAllInRow"; - SelectType = "SelectOne"; - OneChoiceForAllPlayers = true; - ExportOnChange = false; - Choices = baseChoices; - LoadSelections = function(self, list, pn) - if ReadPrefFromFile("UserPrefScoringMode") ~= nil then - --Load the saved scoring mode from UserPrefs. - local theValue = ReadPrefFromFile("UserPrefScoringMode"); - local success = false; - - --HACK: Preview 4 took out 1st and 4th scoring. Replace with a close equivalent. - if theValue == "DDR 1stMIX" or theValue == "DDR 4thMIX" then theValue = "Oldschool" end - - --Search the list of scoring modes for the saved scoring mode. - for k,v in ipairs(baseChoices) do - if v == theValue then list[k] = true success = true break end - end; - - --We couldn't find it, pick the first available scoring mode as a sane default. - if success == false then list[1] = true end; - else - WritePrefToFile("UserPrefScoringMode", baseChoices[1]); - list[1] = true; - end; - end; - SaveSelections = function(self, list, pn) - for k,v in ipairs(list) do - if v then WritePrefToFile("UserPrefScoringMode", baseChoices[k]) break end - end; - end; - }; - setmetatable( t, t ); - return t; -end +--[[DO NOT MODIFY THIS FILE. +You can add new scoring modes just by creating a different file and adding them to the +Scoring table. Replacing this file will cause additions to be lost during updates. +It's unnecessary and problematic.]] + +--internals table +local Shared = {}; +--Special Scoring types. +local r = {}; +local DisabledScoringModes = { '[SSC] Radar Master' }; +--the following metatable makes any missing value in a table 0 instead of nil. +local ZeroIfNotFound = { __index = function() return 0 end; }; + +-- Retrieve the amount of taps/holds/rolls involved. Used for some formulas. +function GetTotalItems(radars) + local total = radars:GetValue('RadarCategory_TapsAndHolds') + total = total + radars:GetValue('RadarCategory_Holds') + total = total + radars:GetValue('RadarCategory_Rolls') + -- [ja] Liftを加えると一部二重加算になるため除外する。 + -- total = total + radars:GetValue('RadarCategory_Lifts') + + -- [en] prevent divide by 0 + -- [ja] 0除算対策(しなくても動作するけど満点になっちゃうんで) + return math.max(1,total); +end; + +-- Determine whether marvelous timing is to be considered. +function IsW1Allowed(tapScore) + return tapScore == 'TapNoteScore_W2' + and (PREFSMAN:GetPreference("AllowW1") ~= 'AllowW1_Never' + or not (GAMESTATE:IsCourseMode() and + PREFSMAN:GetPreference("AllowW1") == 'AllowW1_CoursesOnly')); +end; + +-- Get the radar values directly. The individual steps aren't used much. +function GetDirectRadar(player) + return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player); +end; + +----------------------------------------------------------- +--Oldschool scoring, best described as a modified 4th mix scheme +--with a little 1st mix influence +----------------------------------------------------------- +r['Oldschool'] = function(params, pss) + local bestPoints = 999 + local scoreLookupTable = + { + ['TapNoteScore_W1']=999, + ['TapNoteScore_W2']=IsW1Allowed('TapNoteScore_W2') and 888 or 999, + ['TapNoteScore_W3']=777, + ['TapNoteScore_W4']=555, + ['TapNoteScore_W5']=111, + }; + setmetatable(scoreLookupTable, ZeroIfNotFound); + local comboBonusForThisStep = (pss:GetCurrentCombo()*111)^1.1; + local capScore = 1000000000; + pss:SetCurMaxScore(capScore); --i don't really care about weird scoring modes -fsx + local pointsGot = comboBonusForThisStep + scoreLookupTable[params.TapNoteScore] + (params.HoldNoteScore == 'HoldNoteScore_Held' and 777 or 0); + pss:SetScore(clamp(pss:GetScore()+pointsGot,0,capScore)); +end; + +----------------------------------------------------------- +--DDR MAX2/Extreme(-esque) Scoring by @sakuraponila +----------------------------------------------------------- +local ext_Steps = {0,0}; +r['DDR Extreme'] = function(params, pss) + local multLookup = + { + ['TapNoteScore_W1'] = 10, + ['TapNoteScore_W2'] = 9, + ['TapNoteScore_W3'] = 5 + }; + setmetatable(multLookup, ZeroIfNotFound); + local steps = GAMESTATE:GetCurrentSteps(params.Player); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + -- 1 + 2 + 3 + ... + totalItems value/の値 + local sTotal = (totalItems + 1) * totalItems / 2; + local meter = steps:GetMeter(); + if (steps:IsAnEdit()) then + meter = 5; + else + meter = math.min(10,meter); + end; + -- [en] score for one step + -- [ja] 1ステップあたりのスコア + local baseScore = meter * 1000000 + if (GAMESTATE:GetCurrentSong():IsMarathon()) then + baseScore = baseScore * 3; + elseif (GAMESTATE:GetCurrentSong():IsLong()) then + baseScore = baseScore * 2; + end; + local sOne = math.floor(baseScore / sTotal); + -- [en] measures for 5 points of units + -- [ja] 5点単位のための処置 + sOne = sOne - sOne % 5; + -- [en] because fractions are added by the last step, get value + -- [ja] 端数は最後の1ステップで加算するのでその値を取得 + local sLast = baseScore - (sOne * sTotal); + + local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; + -- [en] initialized when score is 0 + -- [ja] スコアが0の時に初期化 + if pss:GetScore() == 0 then + ext_Steps[p] = 0; + end; + -- [en] now step count + -- [ja] 現在のステップ数 + ext_Steps[p] = ext_Steps[p] + 1; + -- [en] current score + -- [ja] 今回加算するスコア(W1の時) + local vScore = sOne * ext_Steps[p]; + pss:SetCurMaxScore(pss:GetCurMaxScore() + vScore); + -- [ja] 判定によって加算量を変更 + if (params.HoldNoteScore == 'HoldNoteScore_Held') then + -- [ja] O.K.判定時は問答無用で満点 + vScore = vScore; + else + -- [ja] N.G.判定時は問答無用で0点 + if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then + vScore = 0; + -- [en] non-long note scoring + -- [ja] それ以外ということは、ロングノート以外の判定である + else + vScore = vScore * multLookup[params.TapNoteScore] / 10 + end; + end; + -- [en] measures for 5 points of units + -- [ja] ここでも5点単位のための処置 + vScore = vScore - vScore % 5 + pss:SetScore(pss:GetScore() + vScore); + -- if one of the last step, add the fractions + -- [ja] 最後の1ステップの場合、端数を加算する + if ((vScore > 0) and (ext_Steps[p] == totalItems)) then + pss:SetScore(pss:GetScore() + sLast); + end; +end; + +----------------------------------------------------------- +--HYBRID Scoring, contributed by @waiei +----------------------------------------------------------- +local hyb_Steps={0,0}; +r['Hybrid'] = function(params, pss) + local multLookup = + { + ['TapNoteScore_W1'] = 10, + ['TapNoteScore_W2'] = 9, + ['TapNoteScore_W3'] = 5 + }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + -- 1+2+3+...+totalItems value/の値 + local sTotal = (totalItems+1)*totalItems/2; + -- [en] Score for one song + -- [ja] 1ステップあたりのスコア + local sOne = math.floor(100000000/sTotal); + -- [ja] 端数は最後の1ステップで加算するのでその値を取得 + local sLast = 100000000-(sOne*sTotal); + + local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; + + -- [ja] スコアが0の時に初期化 + if pss:GetScore()==0 then + hyb_Steps[p]=0; + end; + + -- [ja] 現在のステップ数 + hyb_Steps[p]=hyb_Steps[p]+1; + -- [en] current score + -- [ja] 今回加算するスコア(W1の時) + local vScore = sOne*hyb_Steps[p]; + pss:SetCurMaxScore(pss:GetCurMaxScore()+vScore); + -- [ja] 判定によって加算量を変更 + if (params.HoldNoteScore == 'HoldNoteScore_Held') then + vScore = vScore; + else + if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then + vScore = 0; + else + vScore = vScore*multLookup[params.TapNoteScore]/10; + end; + end; + pss:SetScore(pss:GetScore()+vScore); + + -- [ja] 最後の1ステップの場合、端数を加算する + if ((vScore > 0) and (hyb_Steps[p] == totalItems)) then + pss:SetScore(pss:GetScore()+sLast); + end; +end; + +----------------------------------------------------------- +--DDR SuperNOVA scoring (Use MARVELOUS) by @sakuraponila +----------------------------------------------------------- +local sntmp_Score = {0,0}; +local sntmp_Steps = {0,0}; +r['DDR SuperNOVA'] = function(params, pss) + local multLookup = + { + ['TapNoteScore_W1'] = 3, + ['TapNoteScore_W2'] = 2, + ['TapNoteScore_W3'] = 1 + }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues) + local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; + + -- initialized when score is 0 + -- [ja] スコアが0の時に初期化 + if pss:GetScore() == 0 then + sntmp_Score[p] = 0; + sntmp_Steps[p] = 0; + end; + + -- [ja] 判定によって加算量を変更 + local maxAdd = 0; + -- [ja] O.K.判定時は問答無用で満点 + if params.HoldNoteScore == 'HoldNoteScore_Held' then + maxAdd = 3; + else + -- [ja] N.G.判定時は問答無用で0点 + if params.HoldNoteScore == 'HoldNoteScore_LetGo' then + maxAdd = 0; + -- [ja] それ以外ということは、ロングノート以外の判定である + else + maxAdd = multLookup[params.TapNoteScore]; + end + end; + sntmp_Score[p] = sntmp_Score[p] + maxAdd; + + -- [ja] 踏み踏みしたステップ数 + sntmp_Steps[p] = sntmp_Steps[p] + 1; + -- [ja] 現時点での、All W1判定の時のスコア + pss:SetCurMaxScore(math.floor(10000000 * sntmp_Steps[p] / totalItems / 3)); + -- [ja] 計算して代入 + pss:SetScore(math.floor(10000000 * sntmp_Score[p] / totalItems / 3)); +end; + +----------------------------------------------------------- +--DDR SuperNOVA 2 scoring by @waiei +----------------------------------------------------------- +local sn2tmp_Sub={0,0}; +local sn2tmp_Score={0,0}; +local sn2tmp_Steps={0,0}; +r['DDR SuperNOVA 2'] = function(params, pss) + local multLookup = + { + ['TapNoteScore_W1'] = 10, + ['TapNoteScore_W2'] = 10, + ['TapNoteScore_W3'] = 5 + }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + local p = (params.Player == 'PlayerNumber_P1') and 1 or 2; + + -- [ja] スコアが0の時に初期化 + if pss:GetScore()==0 then + sn2tmp_Sub[p]=0; + sn2tmp_Score[p]=0; + sn2tmp_Steps[p]=0; + end; + + -- [ja] maxAdd は 加算する最高点を 10 とした時の値(つまり、10=100% / 5=50%) + local maxAdd = 0; + -- [ja] O.K.判定時は問答無用で満点 + if params.HoldNoteScore == 'HoldNoteScore_Held' then + maxAdd = 10; + else + -- [ja] N.G.判定時は問答無用で0点 + if params.HoldNoteScore == 'HoldNoteScore_LetGo' then + maxAdd = 0; + -- [ja] それ以外ということは、ロングノート以外の判定である + else + maxAdd = multLookup[params.TapNoteScore]; + if (params.TapNoteScore == 'TapNoteScore_W2') or (params.TapNoteScore=='TapNoteScore_W3') then + -- [ja] W2とW3の数を記録 + sn2tmp_Sub[p]=sn2tmp_Sub[p]+1; + end; + end + end; + sn2tmp_Score[p]=sn2tmp_Score[p]+maxAdd; + -- [ja] 踏み踏みしたステップ数 + sn2tmp_Steps[p]=sn2tmp_Steps[p]+1; + -- [ja] 現時点での、All W1判定の時のスコア + pss:SetCurMaxScore(math.floor(10000*sn2tmp_Steps[p]/totalItems) * 10); + + -- [ja] 計算して代入 + pss:SetScore((math.floor(10000*sn2tmp_Score[p]/totalItems) * 10) - (sn2tmp_Sub[p]*10) ); +end; + +----------------------------------------------------------- +--Radar Master (disabled; todo: get this working with StepMania 5) +----------------------------------------------------------- +r['[SSC] Radar Master'] = function(params, pss) + local masterTable = { + ['RadarCategory_Stream'] = 0, + ['RadarCategory_Voltage'] = 0, + ['RadarCategory_Air'] = 0, + ['RadarCategory_Freeze'] = 0, + ['RadarCategory_Chaos'] = 0 + }; + local totalRadar = 0; + local finalScore = 0; + for k,v in pairs(masterTable) do + local firstRadar = GetDirectRadar(params.Player):GetValue(k); + if firstRadar == 0 then + masterTable[k] = nil; + else + masterTable[k] = firstRadar; + totalRadar = totalRadar + firstRadar; + end; + end; + --two loops are needed because we need to calculate totalRadar + --to actually calculate any part of the score + for k,v in pairs(masterTable) do + local curPortion = pss:GetRadarActual():GetValue(k) / v; + finalScore = finalScore + curPortion*(500000000*(v/totalRadar)); + end; + pss:SetScore(finalScore); +end; +------------------------------------------------------------ +--Marvelous Incorporated Grading System (or MIGS for short) +--basically like DP scoring with locked DP values +------------------------------------------------------------ +r['MIGS'] = function(params,pss) + local curScore = 0; + local tapScoreTable = + { + ['TapNoteScore_W1'] = 3, + ['TapNoteScore_W2'] = 2, + ['TapNoteScore_W3'] = 1, + ['TapNoteScore_W5'] = -4, + ['TapNoteScore_Miss'] = -8 + }; + for k,v in pairs(tapScoreTable) do + curScore = curScore + ( pss:GetTapNoteScores(k) * v ); + end; + curScore = math.max(0,curScore + ( pss:GetHoldNoteScores('HoldNoteScore_Held') * 6 )); + pss:SetScore(curScore); +end; + +-------------------------------------------------------------- +--1bilDP scoring because I can. +-------------------------------------------------------------- +r['Billions DP']= function(params,pss) + local poss = pss:GetPossibleDancePoints() + pss:SetScore(math.floor((pss:GetActualDancePoints()/poss)*1000000000)) + pss:SetCurMaxScore(math.floor((pss:GetCurrentPossibleDancePoints()/poss)*1000000000)) +end +------------------------------------------------------------------------------- +-- Formulas end here. +for v in ivalues(DisabledScoringModes) do r[v] = nil end +Scoring = r; diff --git a/Themes/_fallback/Scripts/05 NewScoringFrontend.lua b/Themes/_fallback/Scripts/05 NewScoringFrontend.lua new file mode 100644 index 0000000000..dad9cb1f52 --- /dev/null +++ b/Themes/_fallback/Scripts/05 NewScoringFrontend.lua @@ -0,0 +1,170 @@ +--[[DO NOT MODIFY THIS FILE. +You can add new scoring modes just by creating a different file and adding them to the +ScoringModes table. Replacing this file will cause additions to be lost during updates. +It's unnecessary and problematic.]] + +ScoringModes={} + +local function CreateOldScoringShim(name) + return function(judg,pss,player,mode) + judg,pss,player,mode=coroutine.yield() + while true do + if mode=="update" then + Scoring[name](judg,pss) + judg,pss,player,mode=coroutine.yield(pss:GetScore(),pss:GetCurMaxScore()) + elseif mode=="finalize" then + return pss:GetScore(),pss:GetCurMaxScore() + else + error("scoring shim for mode "..name.." got an unknown state.") + end + end + end +end + +local ZeroIfNotFound = { __index = function() return 0 end; }; + +function GetDirectRadar(player) + return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player) +end + +--The code here is an example of native modes. + +--[[There are three operation modes: +init mode: The JudgmentCommand is invalid in this mode. + This mode is designed to allow you to prepare your scoring mode. +update mode: all are valid. + This lets you respond to score changes. +finalize mode: JudgementCommand invalid. + This is designed to let you give score bonuses. +]] +--[[ +ScoringModes["Oldschool"]=function(judg,pss,player,mode) + local tscore = 0 + local tmaxscore = 1000000000 + local possibilities= { + ['TapNoteScore_W1']=999, + ['TapNoteScore_W2']=IsW1Allowed('TapNoteScore_W2') and 888 or 999, + ['TapNoteScore_W3']=777, + ['TapNoteScore_W4']=555, + ['TapNoteScore_W5']=111, + }; + assert(mode=="init","issues") + setmetatable(possibilities, {__index=function() return 0 end;}); + judg,pss,player,mode = coroutine.yield() + --holy crap it's a state machine i guess! + while true do + if mode=="update" then + tscore=tscore+((pss:GetCurrentCombo()*111)^1.1)+ possibilities[judg.TapNoteScore] + (judg.HoldNoteScore == 'HoldNoteScore_Held' and 777 or 0) + judg,pss,player,mode = coroutine.yield(tscore,tmaxscore) + end + if mode=="finalize" then + break + end + end + return tscore,tmaxscore +end + +ScoringModes['DDRMAX']=function(judge,pss,player,mode) + --[en] in init mode, you start here. judge will be nil. + --[jp] + local multLookup = { + TapNoteScore_W1=10, + TapNoteScore_W2=10, + TapNoteScore_W3=5 } + local notesToIgnore = { + TapNoteScore_CheckpointHit=true, + TapNoteScore_CheckpointMiss=true, + TapNoteScore_HitMine=true, + TapNoteScore_AvoidMine=true, + TapNoteScore_None=true} + local radarCategoriesAndBonuses={ + RadarCategory_Stream=20000000, + RadarCategory_Air=10000000, + RadarCategory_Voltage=10000000, + RadarCategory_Chaos=10000000, + RadarCategory_Freeze=10000000} + setmetatable(multLookup,ZeroIfNotFound) + local numNoteObjects = GetDirectRadar(player):GetValue('RadarCategory_TapsAndHolds') + local base = 5000000 + local curstep = 0 + local score = 0 + local bestscore = 0 + local s = numNoteObjects<1 and 0 or ((numNoteObjects/2)*(1+numNoteObjects)) + --[en] coroutine.yield() acts somewhat like return, but when the function is run by UpdateScoreKeepers() it will start here. + --[jp] xxx + judge,pss,player,mode = coroutine.yield() + --[en] a while loop is only one way to make the mode selection system, but it's probably the easiest. + --ideally, this would just be 'while mode=="update" do', with finalize stuff after it, + --but I had written the code already when I thought of that. + --[jp] xxx + while true do + --update mode code + if mode == "update" then + --[en] this filters out holds and spurious judgments. DDRMAX ignores holds for scoring purposes. + --[jp] xxx + if (not notesToIgnore[judge.TapNoteScore]) and judge.HoldNoteScore==nil then + curstep=curstep+1 + if curstep>numNoteObjects then error "is bery bad" end + score=score+(pss:GetFailed() and 1 or (multLookup[judge.TapNoteScore]*math.floor(base/s)*curstep))+((curstep==numNoteObjects and pss:FullComboOfScore('TapNoteScore_W2')) and (10*(base-(math.floor(base/s)*numNoteObjects))) or 0) + bestscore = (curstep==numNoteObjects and 50000000 or bestscore+(10*math.floor(base/s)*curstep)) + end + judge,pss,player,mode=coroutine.yield(score,bestscore) + end + if mode == "finalize" then + --[en] this code would work, but SM5 behavior prevents it from doing anything. it should give the groove radar bonuses. + --[jp] xyz + local actradar = pss:GetRadarActual() + local possradar = pss:GetRadarPossible() + for k,v in pairs(radarCategoriesAndBonuses) do + local thispossradar=possradar:GetValue(k) + if thispossradar>0 then + score=score+math.floor((actradar:GetValue(k)/thispossradar)*thispossradar*v) + bestscore=bestscore+(thispossradar*v) + end + end + break + end + end + return score,bestscore +end]] + +for k,v in pairs(Scoring) do + if ScoringModes[k] == nil then + ScoringModes[k] = CreateOldScoringShim(k) + end +end + +function UserPrefScoringMode() + local baseChoices = {} + for k,v in pairs(ScoringModes) do table.insert(baseChoices,k) end + if next(baseChoices) == nil then UndocumentedFeature "No scoring modes available" end + local t = { + Name = "UserPrefScoringMode"; + LayoutType = "ShowAllInRow"; + SelectType = "SelectOne"; + OneChoiceForAllPlayers = true; + ExportOnChange = false; + Choices = baseChoices; + LoadSelections = function(self, list, pn) + if ReadPrefFromFile("UserPrefScoringMode") ~= nil then + --Load the saved scoring mode from UserPrefs. + local theValue = ReadPrefFromFile("UserPrefScoringMode"); + local success = false; + --HACK: Preview 4 took out 1st and 4th scoring. Replace with a close equivalent. + if theValue == "DDR 1stMIX" or theValue == "DDR 4thMIX" then theValue = "Oldschool" end + --Search the list of scoring modes for the saved scoring mode. + for k,v in ipairs(baseChoices) do if v == theValue then list[k] = true success = true break end end; + --We couldn't find it, pick the first available scoring mode as a sane default. + if success == false then list[1] = true end; + else + WritePrefToFile("UserPrefScoringMode", baseChoices[1]); + list[1] = true; + end; + end; + SaveSelections = function(self, list, pn) + for k,v in ipairs(list) do if v then WritePrefToFile("UserPrefScoringMode", baseChoices[k]) break end end; + end; + }; + setmetatable( t, t ); + return t; +end \ No newline at end of file diff --git a/Themes/_fallback/Scripts/05 ScoringEngine2.lua b/Themes/_fallback/Scripts/05 ScoringEngine2.lua new file mode 100644 index 0000000000..0e18b36dbf --- /dev/null +++ b/Themes/_fallback/Scripts/05 ScoringEngine2.lua @@ -0,0 +1,118 @@ +--ScoringEngine2 by FSX v1.41 +--essentially a really chunky layer to make SetScore elegant(ish) +--arguments for scorekeepers: JudgmentMessageCommand,PlayerStageStats,PlayerNumber,State +--[[changelog +v1.41 6 May 2012 +*Not really sure. +*Included in SM5 for alpha 3. +v1.4 18 Apr 2012 +*Support for judgment filtering. +*Minor changes. +*First public release (in SE2 Dev Kit) (didn't happen) +v1.3 17 Apr 2012 +*First complete release. +*Error reporting in FinalizeScoreKeepers() +*Bug fixes.]] +--scoring modes written for the old ad-hoc system don't work, but don't cause crashes either. +--SM5 has some glue code for them, though +local stageKey = nil +local ReadiedScoreKeepers = {} +local JudgmentFilters = {} + +local function CoroutineIsGood(cr) + return coroutine.status(cr)=="suspended" +end + +function InitScoreKeepers(p1Mode, p2Mode) + local newStgK = {pcall(GameState.GetStageSeed,GAMESTATE)} + assert(newStgK[1], "it's too early to initialize the ScoreKeepers, the GameState isn't ready yet") + if newStgK[2] == stageKey then + Log "[InitScoreKeepers] unnecessary call" + return true + end + ReadiedScoreKeepers={} + JudgmentFilters={} + stageKey = newStgK + local intab = {} + if p1Mode ~= nil then + intab.P1 = p1Mode + end + if p2Mode ~= nil then + intab.P2 = p2Mode + end + assert(next(intab), "InitScoreKeepers didn't get any args") + for k,v in pairs(intab) do + if not ScoringModes[v] then + --SPOILER: UndocumentedFeature crashes the game intentionally. + UndocumentedFeature(k.."'s scoring mode \""..v.."\" doesn't exist.") + end + ReadiedScoreKeepers[k] = coroutine.create(ScoringModes[v]) + --call each scoring mode one time in init mode + checks={coroutine.resume(ReadiedScoreKeepers[k],nil,STATSMAN:GetCurStageStats():GetPlayerStageStats("PlayerNumber_"..k), "PlayerNumber_"..k, "init")} + if not CoroutineIsGood(ReadiedScoreKeepers[k]) then SCREENMAN:SystemMessage("scoring init error: "..checks[2]) return false end + --very very very very safe filtering rule load code + if type(checks[2])=="table" then + if type(checks[2][1])..type(checks[2][2]) == "tabletable" then + local isGood=false + local tapscan = Enum.Reverse(TapNoteScore) + local holdscan = Enum.Reverse(HoldNoteScore) + local finaltable = {{},{}} + for i=1,2 do + for k,v in pairs(checks[2][i]) do + finaltable[i][v]=true + if (not (i==2 and holdscan[v] or tapscan[v])) or v==nil then isGood=false break end + isGood=true + end + if not isGood then break end + end + if isGood then + JudgmentFilters[k]=finaltable + end + end + end + end + return true +end + +function UpdateScoreKeepers(JMC) + assert(JMC,"pass args, please") + runplayer = ToEnumShortString(JMC.Player) + if ReadiedScoreKeepers[runplayer] then + if JudgmentFilters[runplayer] and (JudgmentFilters[runplayer][1][JMC.TapNoteScore] or JudgmentFilters[runplayer][2][JMC.HoldNoteScore]) then + return true + end + local pss = STATSMAN:GetCurStageStats():GetPlayerStageStats(JMC.Player) + local newscores = {coroutine.resume(ReadiedScoreKeepers[runplayer],JMC,pss,JMC.Player,"update")} + if CoroutineIsGood(ReadiedScoreKeepers[runplayer]) then + pss:SetScore(newscores[2]) + pss:SetCurMaxScore(newscores[3]) + return true + else + SCREENMAN:SystemMessage("scoring update error: "..newscores[2]) + ReadiedScoreKeepers[runplayer]=nil + return false + end + end +end + +function FinalizeScoreKeepers() + for k,v in pairs(ReadiedScoreKeepers) do + local pss = STATSMAN:GetCurStageStats():GetPlayerStageStats("PlayerNumber_"..k) + local newscores = {coroutine.resume(v,nil,pss,"PlayerNumber_"..k,"finalize")} + local status = coroutine.status(v) + --kill the scorekeeper now, we don't need it again + ReadiedScoreKeepers[k] = nil + if status=="dead" then + if newscores[1]==true then + pss:SetScore(newscores[2]) + pss:SetCurMaxScore(newscores[3]) + else + SCREENMAN:SystemMessage("scoring finalize error: "..newscores[2]) + return false + end + else + return false + end + end + return true +end \ No newline at end of file diff --git a/Themes/default/BGAnimations/ScreenEvaluation decorations/default.lua b/Themes/default/BGAnimations/ScreenEvaluation decorations/default.lua index 8695387dfe..ff478c90c8 100644 --- a/Themes/default/BGAnimations/ScreenEvaluation decorations/default.lua +++ b/Themes/default/BGAnimations/ScreenEvaluation decorations/default.lua @@ -1,3 +1,7 @@ +if not GAMESTATE:IsCourseMode() then + FinalizeScoreKeepers() +end + local function GraphDisplay( pn ) local t = Def.ActorFrame { Def.GraphDisplay { diff --git a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua index 3bacf03843..b6ff781803 100644 --- a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua +++ b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua @@ -215,8 +215,7 @@ if( not GAMESTATE:IsCourseMode() ) then params.TapNoteScore ~= 'TapNoteScore_Invalid' and params.TapNoteScore ~= 'TapNoteScore_None' then - Scoring[GetUserPref("UserPrefScoringMode")](params, - STATSMAN:GetCurStageStats():GetPlayerStageStats(params.Player)) + UpdateScoreKeepers(params) end end; }; diff --git a/Themes/default/BGAnimations/ScreenStageInformation underlay/default.lua b/Themes/default/BGAnimations/ScreenStageInformation underlay/default.lua index 249debdbdf..6d753b9d5f 100644 --- a/Themes/default/BGAnimations/ScreenStageInformation underlay/default.lua +++ b/Themes/default/BGAnimations/ScreenStageInformation underlay/default.lua @@ -77,4 +77,10 @@ t[#t+1] = Def.ActorFrame { }; }; +--Get scoring ready. +if not GAMESTATE:IsCourseMode() then + InitScoringModes((GAMESTATE:IsSideJoined(PLAYER_1) and GetUserPref("UserPrefScoringMode")), + (GAMESTATE:IsSideJoined(PLAYER_2) and GetUserPref("UserPrefScoringMode")) +end + return t \ No newline at end of file