Score rank (粋 / 雅 / 極): in-game badge and result plate #19

Merged
Yonokid merged 4 commits from GanYiZhong/YataiDONNijiiro:score-rank-display into main 2026-09-09 17:35:16 +02:00
10 changed files with 235 additions and 53 deletions
Showing only changes of commit cb022740cd - Show all commits

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

+30
View File
@@ -0,0 +1,30 @@
{
"s36": {
"x": 0,
"y": 0
},
"s38": {
"x": 0,
"y": 0
},
"s40": {
"x": 0,
"y": 0
},
"s42": {
"x": 0,
"y": 0
},
"s44": {
"x": 0,
"y": 0
},
"s46": {
"x": 0,
"y": 0
},
"s48": {
"x": 0,
"y": 0
}
}
+24 -53
View File
@@ -1,15 +1,16 @@
-- Score-rank badge (粋 / 雅 / 極) at the top-left of the player panel, shown while the
-- song is played as the score crosses each rank line.
-- Score-rank badge (粋 / 雅 / 極) at the top-left of the player panel, shown as the
-- score crosses each rank line during play.
--
-- Original: enso/information/score.nulm `scorerank_1p` (498x264 panel stage, placed at
-- (152, -118) -> screen (152, 158) for 1P; `scorerank_2p` at (152, 646) -> 922 for 2P):
-- labels wait / in (f4..28) / keep (f29, held) / out (f149..165). The plate inside
-- (`scorerank_panel`) is a 7-way label switch, one shape per rank. Exported as
-- game/ending_anim/rank_hud_in (in + keep) and rank_hud_out (out) with the seven plate
-- shapes; the shape is swapped per rank.
-- Original: enso/information/score.nulm `scorerank_1p` (498x264 panel stage at screen
-- y 276; placed at (152, -118) -> screen (152, 158) for 1P, `scorerank_2p` at
-- (152, 646) -> 922 for 2P). The game only ever plays the label `in`; the clip then
-- runs in (f4..28) -> keep (to f148) -> out (f149..165) on its own. Exported from
-- `in` as game/ending_anim/rank_hud (162 frames, last frame empty) with the seven
-- plate shapes (`scorerank_panel` rank_1..7); the plate is swapped per rank and a new
-- rank line simply restarts the clip, as the original's goto_label("in") does.
--
-- Rank lines (the engine's own table, scores.h / game.cpp): 1 white 500 000, 2 bronze
-- 600 000, 3 silver 700 000, 4 gold 800 000, 5 pink 900 000, 6 purple 950 000,
-- Rank lines (the engine's own table): 1 white 500 000, 2 bronze 600 000,
-- 3 silver 700 000, 4 gold 800 000, 5 pink 900 000, 6 purple 950 000,
-- 7 rainbow 1 000 000.
local ClipPlayer = require("game/clip_player")
@@ -29,68 +30,38 @@ function RankBadge.rank_of(score)
return r
end
function RankBadge.available()
local ok, d = pcall(require, "game/ending_anim/rank_hud")
return ok and type(d) == "table" and d.frames ~= nil
end
function RankBadge.new(player_num, path)
local self = setmetatable({}, RankBadge)
local p = POS[player_num] or POS[1]
self.clip_in = ClipPlayer.new("game/ending_anim/rank_hud_in", path or "game", "rank_hud_in_anim", p[1], p[2])
self.clip_out = ClipPlayer.new("game/ending_anim/rank_hud_out", path or "game", "rank_hud_out_anim", p[1], p[2])
if self.clip_out then self.clip_out.hold_last = true end
self.clip = ClipPlayer.new("game/ending_anim/rank_hud", path or "game", "rank_hud_anim", p[1], p[2])
if self.clip then self.clip.hold_last = true end
self.rank = 0
self.shown = 0 -- rank currently on screen (0 = none)
self.pending = 0 -- rank waiting for the out animation to finish
self.state = "idle" -- idle | in | out
return self
end
function RankBadge.available()
local ok, d = pcall(require, "game/ending_anim/rank_hud_in")
return ok and type(d) == "table" and d.frames ~= nil
end
function RankBadge:set_score(score, now)
local r = RankBadge.rank_of(score)
if r == self.rank then return end
self.rank = r
if not self.clip_in then return end
if self.state == "idle" and r > 0 then
self:show(r, now)
elseif self.state == "in" then
-- a new line crossed while the plate is up: swap through the out/in pair
self.pending = r
self.state = "out"
if self.clip_out then
self.clip_out.shape_map = { [BASE_SHAPE] = PLATE_SHAPES[self.shown] }
self.clip_out:start(now)
else
self:show(r, now)
end
else
self.pending = r
if r > 0 and self.clip then
self.clip.shape_map = { [BASE_SHAPE] = PLATE_SHAPES[r] }
self.clip:start(now)
end
end
function RankBadge:show(r, now)
self.shown = r
self.clip_in.shape_map = { [BASE_SHAPE] = PLATE_SHAPES[r] }
self.clip_in:start(now)
self.state = "in"
end
function RankBadge:draw(now)
if self.state == "in" then
self.clip_in:draw(now)
elseif self.state == "out" and self.clip_out then
self.clip_out:draw(now)
if self.clip_out:finished(now) then
if self.pending > 0 then self:show(self.pending, now) else self.state = "idle" end
self.pending = 0
end
if self.clip and self.clip:started() and not self.clip:finished(now) then
self.clip:draw(now)
end
end
function RankBadge:destroy()
if self.clip_in then self.clip_in:destroy() end
if self.clip_out then self.clip_out:destroy() end
if self.clip then self.clip:destroy() end
end
return RankBadge
+181
View File
@@ -0,0 +1,181 @@
-- GENERATED by scratchpad/lyric/clip_export.py from enso/information/score.nulm sprite 52 -- do not hand-edit.
-- 498x264 stage. frames[f+1] = {{shape, tx, ty, sx, sy, rot_deg, alpha}, ...}; after the last
-- frame the player continues from frames[loop_at+1]. shapes[c] = {w, h, ox, oy}.
return {
nframes = 162,
loop_at = 161,
stage = {498, 264},
shapes = {
[36] = {208, 208, 104, 104},
[38] = {208, 208, 104, 104},
[40] = {208, 208, 104, 104},
[42] = {208, 208, 104, 104},
[44] = {208, 208, 104, 104},
[46] = {208, 208, 104, 104},
[48] = {208, 208, 104, 104},
},
frames = {
{},
{{36,0,-1.45,1,1,0,0.07}},
{{36,0,-2.85,1,1,0,0.145}},
{{36,0,-4.3,1,1,0,0.215}},
{{36,0,-5.7,1,1,0,0.285}},
{{36,0,-7.15,1,1,0,0.355}},
{{36,0,-8.55,1,1,0,0.43}},
{{36,0,-10,1,1,0,0.5}},
{{36,0,-11.45,1,1,0,0.57}},
{{36,0,-12.85,1,1,0,0.645}},
{{36,0,-14.3,1,1,0,0.715}},
{{36,0,-15.7,1,1,0,0.785}},
{{36,0,-17.15,1,1,0,0.855}},
{{36,0,-18.55,1,1,0,0.93}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1.016,1.016,0,1}},
{{36,0,-20.05,1.032,1.032,0,1}},
{{36,0,-20.05,1.049,1.049,0,1}},
{{36,0,-20.1,1.065,1.065,0,1}},
{{36,0,-20,1.081,1.081,0,1}},
{{36,0,-19.95,1.065,1.065,0,1}},
{{36,0,-19.9,1.049,1.049,0,1}},
{{36,0,-19.9,1.032,1.032,0,1}},
{{36,0,-19.85,1.016,1.016,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-20,1,1,0,1}},
{{36,0,-22.3,1,1,0,0.938}},
{{36,0,-24.6,1,1,0,0.875}},
{{36,0,-26.95,1,1,0,0.812}},
{{36,0,-29.25,1,1,0,0.75}},
{{36,0,-31.55,1,1,0,0.688}},
{{36,0,-33.85,1,1,0,0.625}},
{{36,0,-36.2,1,1,0,0.562}},
{{36,0,-38.5,1,1,0,0.5}},
{{36,0,-40.8,1,1,0,0.438}},
{{36,0,-43.1,1,1,0,0.375}},
{{36,0,-45.45,1,1,0,0.312}},
{{36,0,-47.75,1,1,0,0.25}},
{{36,0,-50.05,1,1,0,0.188}},
{{36,0,-52.35,1,1,0,0.125}},
{{36,0,-54.7,1,1,0,0.062}},
{},
},
}