remove Lua scoring for now. Themes don't need to remove Lua scoring code to work, but it won't do anything.
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
--This provides wrappers to prevent themes that used functions that are now unavailable from crashing.
|
||||||
|
|
||||||
|
Scoring={}
|
||||||
|
|
||||||
|
setmetatable(Scoring,{__index=function() return function() Log("Lua scoring unimplemented") end end})
|
||||||
@@ -1,292 +0,0 @@
|
|||||||
--[[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;
|
|
||||||
-----------------------------------------------------------
|
|
||||||
--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;
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
-- Formulas end here.
|
|
||||||
for v in ivalues(DisabledScoringModes) do r[v] = nil end
|
|
||||||
Scoring = r;
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
--[[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)
|
|
||||||
local func = Scoring[name]
|
|
||||||
return function(judg,pss,player,mode)
|
|
||||||
judg,pss,player,mode=coroutine.yield()
|
|
||||||
while true do
|
|
||||||
if mode=="update" then
|
|
||||||
if not judg.TapNoteScore:find("Mine") then func(judg,pss) end
|
|
||||||
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
|
|
||||||
|
|
||||||
--[[----------------------------------------------------------------------------
|
|
||||||
Scoring modes begin here.
|
|
||||||
--]]----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--[[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)
|
|
||||||
--If you know Japanese and English, and can translate these comments, please help.
|
|
||||||
--日本のコメントは、機械解釈されました。 あなたが彼らを人間を翻訳されたコメントと入れ替えるのを手伝うことができるならば、どうぞ。
|
|
||||||
--[en] in init mode, you start here. judge will be nil.
|
|
||||||
--[jp] initモードで、あなたがここに出発すること。judgeが、nilです
|
|
||||||
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] coroutine.yield()はいくぶん「return」のようなふりをします、しかし、機能がUpdateScoreKeepers()に通されるとき、それはここで始まります。
|
|
||||||
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.
|
|
||||||
--[jp]「while」ループはモード選択システムを行う1つの方法だけです、しかし、それは多分最も簡単でしょう。
|
|
||||||
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] これは、holdともっともらしい判断を除去します。 DDRMAXは、目的を記録するために、holdを無視します。
|
|
||||||
if (not notesToIgnore[judge.TapNoteScore]) and judge.HoldNoteScore==nil then
|
|
||||||
curstep=curstep+1
|
|
||||||
if curstep>numNoteObjects then error "Got some things we shouldn't have" 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 isn't accurate, but it's good enough
|
|
||||||
--[jp] このコードは正確でありません、しかし、それは十分によいです
|
|
||||||
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
|
|
||||||
|
|
||||||
ScoringModes["DDR SuperNOVA 2"]=function(judge,pss,player,mode)
|
|
||||||
local function dTransform(number)
|
|
||||||
return 10*math.round(number/10)
|
|
||||||
end
|
|
||||||
local curScore=0
|
|
||||||
local curMaxScore=0
|
|
||||||
local tnsMultiplier={
|
|
||||||
TapNoteScore_W1=1,
|
|
||||||
TapNoteScore_W2=1,
|
|
||||||
TapNoteScore_W3=0.5,
|
|
||||||
TapNoteScore_AvoidMine=1}
|
|
||||||
local subtract10Points = {
|
|
||||||
TapNoteScore_W2=IsW1Allowed('TapNoteScore_W2'),
|
|
||||||
TapNoteScore_W3=true}
|
|
||||||
setmetatable(tnsMultiplier, ZeroIfNotFound)
|
|
||||||
local radar = pss:GetRadarPossible()
|
|
||||||
local stepScore = 1000000/math.max(radar:GetValue('RadarCategory_TapsAndHolds')+
|
|
||||||
radar:GetValue('RadarCategory_Mines')+
|
|
||||||
radar:GetValue('RadarCategory_Holds')+
|
|
||||||
radar:GetValue('RadarCategory_Rolls'),1)
|
|
||||||
--this is how one activates ScoringEngine2's built-in filter system.
|
|
||||||
judge,pss,player,mode=coroutine.yield({{'TapNoteScore_None','TapNoteScore_CheckpointHit','TapNoteScore_CheckpointMiss'},{"HoldNoteScore_None"}})
|
|
||||||
local mineWasHit=false
|
|
||||||
while mode=="update" do
|
|
||||||
if judge.TapNoteScore:find("Mine") then mineWasHit = true end
|
|
||||||
curScore=curScore+(stepScore*(not judge.HoldNoteScore and tnsMultiplier[judge.TapNoteScore] -
|
|
||||||
(subtract10Points[judge.TapNoteScore] and 10 or 0) or
|
|
||||||
(judge.HoldNoteScore=='HoldNoteScore_Held' and 1 or 0)))
|
|
||||||
curMaxScore=curMaxScore+stepScore
|
|
||||||
judge,pss,player,mode=coroutine.yield(dTransform(curScore),dTransform(curMaxScore))
|
|
||||||
end
|
|
||||||
--We might not always be able to register mines in gameplay. Add the scores after gameplay if we couldn't.
|
|
||||||
if not mineWasHit and radar:GetValue('RadarCategory_Mines')~=0 then
|
|
||||||
curMaxScore=curMaxScore+(stepScore*radar:GetValue('RadarCategory_Mines'))
|
|
||||||
curScore=curScore+(stepScore*pss:GetRadarActual():GetValue('RadarCategory_Miines'))
|
|
||||||
end
|
|
||||||
return dTransform(curScore),dTransform(curMaxScore)
|
|
||||||
end
|
|
||||||
|
|
||||||
ScoringModes["Billions DP"]=function(judge,pss,player,mode)
|
|
||||||
local possibleDP=pss:GetPossibleDancePoints()
|
|
||||||
possibleDP=possibleDP>0 and possibleDP or 1
|
|
||||||
local curScore = 0
|
|
||||||
local curMaxScore = 0
|
|
||||||
while true do
|
|
||||||
judge,pss,player,mode=coroutine.yield(curScore,curMaxScore)
|
|
||||||
curScore = (pss:GetActualDancePoints()/possibleDP)*1000000000
|
|
||||||
curMaxScore = (pss:GetCurrentPossibleDancePoints()/possibleDP)*1000000000
|
|
||||||
if mode=="finalize" then return curScore,curMaxScore end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[----------------------------------------------------------------------------
|
|
||||||
Scoring modes end here.
|
|
||||||
--]]----------------------------------------------------------------------------
|
|
||||||
for k,v in pairs(Scoring) do
|
|
||||||
if ScoringModes[k] == nil then
|
|
||||||
ScoringModes[k] = CreateOldScoringShim(k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--if you are using the old Scoring system in the standard way, your theme will not need to be updated
|
|
||||||
local OldCallShimMt={
|
|
||||||
__index=function(t,k,v)
|
|
||||||
return function(judg, _)
|
|
||||||
--sacrifice some efficiency for reliability
|
|
||||||
InitScoreKeepers(ArgsIfPlayerJoinedOrNil(v))
|
|
||||||
UpdateScoreKeepers(judg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
Scoring={}
|
|
||||||
setmetatable(Scoring,OldCallShimMt)
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
--ScoringEngine2 by FSX v1.43
|
|
||||||
--essentially a really chunky layer to make SetScore elegant(ish)
|
|
||||||
--arguments for scorekeepers: JudgmentMessageCommand,PlayerStageStats,PlayerNumber,State
|
|
||||||
--[[changelog
|
|
||||||
v1.43 12 Jun 2012
|
|
||||||
*Remove a log that could create a lot of log noise
|
|
||||||
in certain situations
|
|
||||||
v1.42 21 May 2012
|
|
||||||
*Add more type checking.
|
|
||||||
*Don't crash on missing modes.
|
|
||||||
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 GetNumReadiedScoreKeepers()
|
|
||||||
return table.itemcount(ReadiedScoreKeepers)
|
|
||||||
end
|
|
||||||
|
|
||||||
--InitScoreKeepers(string p1Mode, string p2Mode)
|
|
||||||
--Both are optional.
|
|
||||||
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
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
if p1Mode~=nil then
|
|
||||||
assert(type(p1Mode)=="string", "only pass string or nil")
|
|
||||||
end
|
|
||||||
if p2Mode~=nil then
|
|
||||||
assert(type(p2Mode)=="string", "only pass string or nil")
|
|
||||||
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
|
|
||||||
Warn(k.."'s scoring mode \""..v.."\" doesn't exist.")
|
|
||||||
else
|
|
||||||
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
|
|
||||||
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
|
|
||||||
|
|
||||||
-- (c) 2012 Jack Walstrom and the spinal shark collective
|
|
||||||
-- All rights reserved.
|
|
||||||
--
|
|
||||||
-- Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
-- copy of this software and associated documentation files (the
|
|
||||||
-- "Software"), to deal in the Software without restriction, including
|
|
||||||
-- without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
-- distribute, and/or sell copies of the Software, and to permit persons to
|
|
||||||
-- whom the Software is furnished to do so, provided that the above
|
|
||||||
-- copyright notice(s) and this permission notice appear in all copies of
|
|
||||||
-- the Software and that both the above copyright notice(s) and this
|
|
||||||
-- permission notice appear in supporting documentation.
|
|
||||||
--
|
|
||||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
||||||
-- THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
||||||
-- INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
||||||
-- OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
||||||
-- OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
||||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
-- PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
if not GAMESTATE:IsCourseMode() then
|
|
||||||
FinalizeScoreKeepers()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GraphDisplay( pn )
|
local function GraphDisplay( pn )
|
||||||
local t = Def.ActorFrame {
|
local t = Def.ActorFrame {
|
||||||
Def.GraphDisplay {
|
Def.GraphDisplay {
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ local function CreateSegments(Player)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
kids.Target:GetTexture():FinishRenderingTo();
|
kids.Target:GetTexture():FinishRenderingTo();
|
||||||
|
|
||||||
kids.Actual:SetTexture(kids.Target:GetTexture());
|
kids.Actual:SetTexture(kids.Target:GetTexture());
|
||||||
FirstPass=false;
|
FirstPass=false;
|
||||||
end
|
end
|
||||||
@@ -230,17 +231,4 @@ t[#t+1] = StandardDecorationFromFileOptional("BPMDisplay","BPMDisplay");
|
|||||||
t[#t+1] = StandardDecorationFromFileOptional("StageDisplay","StageDisplay");
|
t[#t+1] = StandardDecorationFromFileOptional("StageDisplay","StageDisplay");
|
||||||
t[#t+1] = StandardDecorationFromFileOptional("SongTitle","SongTitle");
|
t[#t+1] = StandardDecorationFromFileOptional("SongTitle","SongTitle");
|
||||||
|
|
||||||
if( not GAMESTATE:IsCourseMode() ) then
|
|
||||||
t[#t+1] = Def.Actor{
|
|
||||||
JudgmentMessageCommand = function(self, params)
|
|
||||||
if params.TapNoteScore and
|
|
||||||
params.TapNoteScore ~= 'TapNoteScore_Invalid' and
|
|
||||||
params.TapNoteScore ~= 'TapNoteScore_None'
|
|
||||||
then
|
|
||||||
UpdateScoreKeepers(params)
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
};
|
|
||||||
end;
|
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|||||||
@@ -87,12 +87,4 @@ t[#t+1] = Def.ActorFrame {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
--Get scoring ready.
|
|
||||||
if not GAMESTATE:IsCourseMode() then
|
|
||||||
InitScoreKeepers(
|
|
||||||
GAMESTATE:IsSideJoined(PLAYER_1) and GetUserPref("UserPrefScoringMode") or nil,
|
|
||||||
GAMESTATE:IsSideJoined(PLAYER_2) and GetUserPref("UserPrefScoringMode") or nil
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|||||||
Reference in New Issue
Block a user