TotalResult = {} TotalResult.__index = TotalResult local S = tex.get_screen_scale() local DIR = "total_result/tally" local F = 1000 / 60 local BLACK = { 0, 0, 0, 255 } local WHITE = { 255, 255, 255, 255 } local PANEL_X = { 48, 658 } -- ResultPanel origin per seat local PANEL_Y = 187 local PRESENT_X = { 353, 655 } -- PresentPanel local PRESENT_Y = 610 local BOX_X = { 236, 846 } -- OpenBox local BOX_Y = 400 local AD_DX = { 0, 610 } local TITLES_PER_PAGE = 8 -- AS constants (frames) local TITLE_INTRO, SLIDE_LEN, SKIP_FROM = 165, 234, 36 local FADE_IN, POP_LEN, WAIT_AFTER, GATHER, BETWEEN = 25, 58, 30, 19, 90 local METER_FULL, BOX_LEN, FULL_LEN = 118, 100, 100 local OPEN_LEN, ITEM_HOLD, ITEM_OUT = 155, 180, 18 local AD_CARDS = { 209, 180, 180, 182, 180, 260 } -- server present type (music, tone, dress, head, body) -> art frame (dress, music, tone, head, body) local ART_FRAME = { [0] = 1, [1] = 2, [2] = 0, [3] = 3, [4] = 4 } local function clamp01(v) return math.max(0.0, math.min(1.0, v)) end local function ramp(t, at, len) return clamp01((t - at) / len) end local function ease_in(u) return u * u end local function ease_out(u) return u * (2 - u) end local function lerp(a, b, u) return a + (b - a) * u end local function play(name) if audio.has_sound(name) then audio.play_sound(name, name:find("vo_") and "voice" or "sound") end end function TotalResult.new(data) local self = setmetatable({}, TotalResult) self.tex = {} self.draw_icon = data.draw_icon self.month = data.month or 1 self.seats = {} self.any_data = false for seat = 1, 2 do local p = data.players[seat] local s = { seat = seat, data = p ~= nil, gifts = 0, opened = 0 } if p then self.any_data = true s.songs, s.titles, s.presents = p.songs, p.titles, p.presents s.cur, s.aim, s.full = p.current, p.aim, p.aim < 0 s.title_pages = math.ceil(#s.titles / TITLES_PER_PAGE) s.song_sum = 0 for _, song in ipairs(s.songs) do s.song_sum = s.song_sum + song.points song.text = text.create_raw_text(song.title, math.floor(24 * S), WHITE, BLACK, false, 4, 1.0) end for _, title in ipairs(s.titles) do title.text = text.create_raw_text(title.name, math.floor(18 * S), WHITE, BLACK, false, 3, 1.0) end for _, gift in ipairs(s.presents) do gift.text = text.create_raw_text(gift.name, math.floor(32 * S), WHITE, BLACK, false, 4, 1.0) end s.next_present, s.left = 1, 0 s.meter = s.full and "full_idle" or "idle" end self.seats[seat] = s end self.state, self.t0 = "intro", tex.get_current_ms() self.page, self.done = 0, false self.f = 0 play("vo_call") if audio.has_sound("bgm") then audio.play_sound("bgm", "music") end return self end function TotalResult:t(key) local t = self.tex[key] if not t then local id = tex.get_texture(DIR .. "/" .. key) local info = tex.get_texture_info(DIR:match("[^/]+$"), key) t = { id = id, w = info and info.x2[1] or 0, h = info and info.y2[1] or 0 } self.tex[key] = t end return t end -- top-left at (x, y), scale sx/sy function TotalResult:put(key, x, y, opts) local t = self:t(key) opts = opts or {} local sx, sy = opts.sx or 1, opts.sy or opts.sx or 1 tex.draw_texture(t.id, { x = x * S, y = y * S, x2 = t.w * (sx - 1), y2 = t.h * (sy - 1), fade = opts.fade, frame = opts.frame, mirror = opts.mirror }) end -- centred on (cx, cy) function TotalResult:mid(key, cx, cy, s, fade, frame, sy) local t = self:t(key) local w, h = t.w * s, t.h * (sy or s) tex.draw_texture(t.id, { x = cx * S - w / 2, y = cy * S - h / 2, x2 = w - t.w, y2 = h - t.h, fade = fade, frame = frame }) end -- right-aligned; rightmost digit's left edge at x function TotalResult:digits(key, value, x, y, pitch, fade) local str = tostring(math.max(0, math.floor(value))) for i = 1, #str do self:put(key, x - (i - 1) * pitch, y, { frame = tonumber(str:sub(#str - i + 1, #str - i + 1)), fade = fade }) end end function TotalResult:go(state) self.state, self.t0, self.f = state, tex.get_current_ms(), 0 end -- meter: "mount" fills at METER_FULL frames per bar; reaching the aim opens the next gift, then goes on function TotalResult:mount(s, add) if not s.data or s.full then return end s.left, s.meter, s.tick = add, "mount", 0 end local function meter_busy(s) return s.data and (s.meter == "mount" or s.meter == "box" or s.meter == "full") end function TotalResult:reach_aim(s) s.cur = math.max(0, s.cur - s.aim) local gift = s.presents[s.next_present] s.next_present = s.next_present + 1 if gift then s.gifts = s.gifts + 1 s.gift_f = self.clock play("se_gohobi") play("vo_gohobi_get") s.aim = gift.next_aim end if s.aim < 0 then s.meter, s.full, s.box_f = "full", true, self.clock play("se_popup") else s.meter, s.box_f = "box", self.clock end end function TotalResult:update_meter(s) if not s.data then return end if s.meter == "mount" then local step = math.min(s.left, s.aim / METER_FULL) s.cur, s.left = s.cur + step, s.left - step if s.tick % 10 == 0 then play("se_pt_up") end s.tick = s.tick + 1 if s.cur >= s.aim and s.left > 0 then audio.stop_sound("se_pt_up") self:reach_aim(s) elseif s.left <= 0 then audio.stop_sound("se_pt_up") play("don") s.meter = "idle" end elseif s.meter == "box" and self.clock - s.box_f >= BOX_LEN then s.meter, s.tick = s.left > 0 and "mount" or "idle", 0 elseif s.meter == "full" and self.clock - s.box_f >= FULL_LEN then s.meter = "full_idle" end end -- finish a mount at once (Don pressed) function TotalResult:settle_meter(s) if not s.data or s.full then return end audio.stop_sound("se_pt_up") while s.left > 0 and not s.full do local need = s.aim - s.cur if s.left < need then s.cur, s.left = s.cur + s.left, 0 else s.left = s.left - need self:reach_aim(s) end end if s.meter ~= "full" then s.meter = s.full and "full_idle" or "idle" end end function TotalResult:gifts_pending() for _, s in ipairs(self.seats) do if s.data and s.opened < #s.presents then return true end end return false end function TotalResult:has_titles() for _, s in ipairs(self.seats) do if s.data and #s.titles > 0 then return true end end return false end function TotalResult:update(current_ms) if self.done then return end local dt = current_ms - self.t0 self.f = dt / F self.clock = current_ms / F local f, st = self.f, self.state for _, s in ipairs(self.seats) do self:update_meter(s) end if st == "intro" then if f >= TITLE_INTRO then self:go("slide") play("se_doncho") self.vo_said = false end elseif st == "slide" then if f >= 30 and not self.vo_said then self.vo_said = true play("vo_shukei") end if f >= SLIDE_LEN then self:go(self.any_data and "music_in" or "ad_only") end elseif st == "ad_only" then if f >= AD_CARDS[1] + AD_CARDS[2] then self:go("close") end elseif st == "music_in" then if f >= FADE_IN then self:go("music_pop") end elseif st == "music_pop" then if f >= POP_LEN + WAIT_AFTER then self:go("music_gather") end elseif st == "music_gather" then if f >= GATHER + WAIT_AFTER then for _, s in ipairs(self.seats) do self:mount(s, s.data and s.song_sum or 0) end self:go("music_mount") end elseif st == "music_mount" or st == "title_mount" then if not (meter_busy(self.seats[1]) or meter_busy(self.seats[2])) then self:go(st == "music_mount" and "music_out" or "title_out") end elseif st == "music_out" then if f >= BETWEEN then if self:has_titles() then self.page = 0 play("vo_shogo") self:go("title_in") else self:go("panel_out") end end elseif st == "title_in" then if f == 0 or not self.shogo_page or self.shogo_page ~= self.page then self.shogo_page = self.page play("se_shogo_get") end if f >= POP_LEN + WAIT_AFTER then self:go("title_gather") end elseif st == "title_gather" then if f >= GATHER + WAIT_AFTER then for _, s in ipairs(self.seats) do self:mount(s, self:page_sum(s)) end self:go("title_mount") end elseif st == "title_out" then if f >= BETWEEN then self.page = self.page + 1 if self:page_exists() then self:go("title_in") else self:go("panel_out") end end elseif st == "panel_out" then if f >= BETWEEN + 10 then if self:gifts_pending() then play("vo_gohoubi") self:go("reward_in") else self:go("close") end end elseif st == "reward_in" then if f >= 19 + 60 then self:open_next() end elseif st == "reward_open" then if f >= OPEN_LEN + ITEM_HOLD + ITEM_OUT then self:open_next() end elseif st == "reward_out" then if f >= 15 then self:go("close") end elseif st == "close" then if f >= 30 then self.done = true audio.stop_sound("bgm") end end end function TotalResult:open_next() if not self:gifts_pending() then self:go("reward_out") return end for _, s in ipairs(self.seats) do if s.data and s.opened < #s.presents then s.opened = s.opened + 1 s.showing = s.presents[s.opened] s.first_open = s.opened == 1 s.gifts = math.max(0, s.gifts - 1) else s.showing = nil end end self.gohobi_detail, self.gohobi_content = false, false self:go("reward_open") end function TotalResult:page_titles(s) local out = {} local first = self.page * TITLES_PER_PAGE for i = first + 1, math.min(first + TITLES_PER_PAGE, #s.titles) do out[#out + 1] = s.titles[i] end return out end function TotalResult:page_sum(s) if not s.data then return 0 end local sum = 0 for _, title in ipairs(self:page_titles(s)) do sum = sum + title.points end return sum end function TotalResult:page_exists() for _, s in ipairs(self.seats) do if s.data and self.page < s.title_pages then return true end end return false end -- Don: jumps the part that is playing to its end; returns whether it took function TotalResult:skip() local st = self.state if st == "intro" then self:go("slide") play("se_doncho") self.vo_said = false return true elseif st == "slide" and self.f >= SKIP_FROM then self:go(self.any_data and "music_in" or "ad_only") return true elseif st == "ad_only" then self:go("close") return true elseif st == "music_in" or st == "music_pop" or st == "music_gather" then for _, s in ipairs(self.seats) do self:mount(s, s.data and s.song_sum or 0) self:settle_meter(s) end self:go("music_out") return true elseif st == "title_in" or st == "title_gather" then for _, s in ipairs(self.seats) do self:mount(s, self:page_sum(s)) self:settle_meter(s) end self:go("title_out") return true elseif st == "music_mount" or st == "title_mount" then for _, s in ipairs(self.seats) do self:settle_meter(s) end return true elseif st == "reward_open" and self.f < OPEN_LEN then self.t0 = tex.get_current_ms() - OPEN_LEN * F return true end return false end function TotalResult:is_done() return self.done end -- nameplates fade in as the curtain rises, out as it comes down function TotalResult:nameplate() local st = self.state if st == "intro" then return 0 end if st == "slide" then return ramp(self.f, 9, 27) end if st == "close" then return 1 - ramp(self.f, 0, 15) end return 1 end -- ---------------------------------------------------------------- drawing function TotalResult:draw_curtain_y() local st, f = self.state, self.f if st == "intro" then return 364 end if st == "slide" then if f < 6 then return lerp(364, 370, ramp(f, 0, 6)) end if f < 51 then return lerp(342, -265, ease_out(ramp(f, 7, 44))) end return lerp(-265, -258, ramp(f, 51, 5)) end if st == "close" then return lerp(-258, 364, ease_out(ramp(f, 0, 30))) end return -258 end function TotalResult:draw_curtain() local y = self:draw_curtain_y() - 372 -- stripes' top on screen for i = 0, 10 do local key = (i % 2 == 0) and "stripe_red" or "stripe_white" self:put(key, -20 + i * 120, y, { sx = 15, sy = 1 }) end end function TotalResult:draw_intro_title() local st, f = self.state, self.f local X = { 167, 317, 465, 617, 772, 927 } if st == "intro" then for i = 1, 6 do local u = ramp(f, (i - 1) * 8, 10) if u > 0 then local s = lerp(1.6, 1, ease_out(u)) self:mid("title_shadow", X[i] + 100, 378, s, u, i - 1) self:mid("title_red", X[i] + 100, 378, s, u, i - 1) end end elseif st == "slide" then if f < 36 then -- big title shrinks into the small plaque local u = ease_in(ramp(f, 10, 26)) local s = lerp(1, 0.34, u) for i = 1, 6 do local cx = lerp(X[i] + 100, 187 + (i - 0.5) * 53, u) local cy = lerp(378, 48 + 40, u) self:mid("title_shadow", cx, cy, s, 1, i - 1) self:mid("title_red", cx, cy, s, 1, i - 1) end end if f >= 30 and f < 206 then local cloud_s = f < 45 and lerp(0.9, 1.05, ramp(f, 30, 15)) or lerp(1.05, 1, ramp(f, 45, 15)) self:mid("cloud", 642, 338, cloud_s, ramp(f, 30, 16) * (1 - ramp(f, 193, 13))) end if f >= 36 then self:put("title_small", 187, 48, { fade = 1 - ramp(f, 208, 26) }) end end end function TotalResult:draw_chip() local st, f = self.state, self.f local key if st == "music_in" or st == "music_pop" or st == "music_gather" or st == "music_mount" or st == "music_out" then key = "chip_total" elseif st == "title_in" or st == "title_gather" or st == "title_mount" or st == "title_out" then key = "chip_title" end if not key then return end local u = (st == "music_in" or (st == "title_in" and self.page == 0)) and ramp(f, 0, 22) or 1 self:put(key, lerp(636, 201, ease_out(u)), 48, { fade = u }) end function TotalResult:panel_alpha() local st, f = self.state, self.f if st == "music_in" then return ramp(f, 0, FADE_IN) end if st == "panel_out" then return 1 - ramp(f, BETWEEN, 10) end if st == "intro" or st == "slide" or st:find("reward") or st == "close" or st == "ad_only" then return 0 end return 1 end -- pop of a point ball with its number; returns scale, alpha local function ball_pose(f) if f < 30 then return 0, 0 end if f < 44 then return lerp(0.24, 1.1, ease_out(ramp(f, 30, 14))), 1 end if f < 58 then return lerp(1.1, 1, ease_in(ramp(f, 44, 14))), 1 end return 1, 1 end function TotalResult:draw_ball(value, x, y, s, fade) if s <= 0 or fade <= 0 then return end local cx, cy = x + 48, y + 48 self:mid("ball", cx, cy, s, fade) self:mid("ball_shine", cx, cy - 0.8 * s, s, fade) local str = tostring(value) local w = (#str * 20 + 8.8) * s for i = 1, #str do local dx = -w / 2 + (i - 1) * 20 * s + 14.4 * s self:mid("digits_ball", cx + dx, cy, 1.2 * s, fade, tonumber(str:sub(i, i))) end end function TotalResult:draw_sum_bar(s, px, top, label_key, value, a) self:put("sum_bar", px + 14, top, { fade = a }) self:put(label_key, px + 108, top + 9, { fade = a }) self:digits("digits_black", value, px + 386, top + 12, 24, a) end local SONG_TOPS = { { -13 }, { -23, 57 }, { -33, 37, 107 }, { -43, 17, 77, 137 } } local SUM_TOPS = { 137, 157, 187, 197 } function TotalResult:draw_music(s) local st, f = self.state, self.f local a = self:panel_alpha() if st == "music_out" then a = 1 - ramp(f, BETWEEN - 15, 15) end if a <= 0 or not (st:find("music")) then return end local px = PANEL_X[s.seat] local n = math.min(#s.songs, 4) if n == 0 then return end local first = #s.songs - n local gather = st == "music_gather" and ramp(f, 0, GATHER) or ((st == "music_mount" or st == "music_out") and 1 or 0) local pop = st == "music_pop" and f or ((st == "music_in") and 0 or 999) local sum = 0 for i = 1, n do local top = SONG_TOPS[n][i] local song = s.songs[first + i] self:put("song_bar", px + 14, PANEL_Y + top, { fade = a }) self:put("badge", px + 17, PANEL_Y + top, { frame = i - 1, fade = a }) song.text:draw({ x = (px + 280) * S - song.text.width / 2, y = (PANEL_Y + top + 32) * S - song.text.height / 2, fade = a }) local bs, ba = ball_pose(pop) local bx, by = px + 477, PANEL_Y + top - 17 if gather > 0 then bx, by = lerp(bx, px + 278, gather), lerp(by, PANEL_Y + 270, gather) ba = 1 - gather end self:draw_ball(song.points, bx, by, bs, ba * a) end if pop >= 30 then sum = s.song_sum * ramp(pop, 30, 28) end self:draw_sum_bar(s, px, PANEL_Y + SUM_TOPS[n], "sum_label", sum, a) end function TotalResult:draw_titles(s) local st, f = self.state, self.f if not st:find("title") then return end local titles = self:page_titles(s) if #titles == 0 then return end local px, py = PANEL_X[s.seat] + 30, PANEL_Y + 20 local a = 1 if st == "title_in" then a = ramp(f, 0, 15) end if st == "title_out" then a = 1 - ramp(f, BETWEEN - 15, 15) end local gather = st == "title_gather" and ramp(f, 0, GATHER) or ((st == "title_mount" or st == "title_out") and 1 or 0) local pop = st == "title_in" and f or 999 for i, title in ipairs(titles) do local col, row = (i - 1) % 2, math.floor((i - 1) / 2) local bx, by = px + col * 260, py - 45 + row * 55 self:put("board", bx, by, { fade = a }) self:put("board_new", bx, by, { fade = a * (0.5 + 0.5 * math.sin((self.clock or 0) / 30 * math.pi)) }) title.text:draw({ x = (bx + 128) * S - title.text.width / 2, y = (by + 24) * S - title.text.height / 2, fade = a }) local bs, ba = ball_pose(pop) local tx, ty = bx + 192.2, by - 10.8 -- draw_ball centres on +48; rest centre is (240, 37) of the board if gather > 0 then tx, ty = lerp(tx, PANEL_X[s.seat] + 105, gather), lerp(ty, PANEL_Y + 296, gather) ba = 1 - gather end self:draw_ball(title.points, tx, ty, bs * 0.4, ba * a) end local sum = pop >= 30 and self:page_sum(s) * ramp(pop, 30, 28) or (st == "title_in" and 0 or self:page_sum(s)) self:draw_sum_bar(s, px - 30, PANEL_Y + 197, "sum_label_title", sum, a) end function TotalResult:draw_meter(s, a) if a <= 0 then return end local mx, my = PANEL_X[s.seat] + 195, PANEL_Y + 276 self:put("meter_base", mx + 15, my + 20, { fade = a }) local u = (s.full or s.aim <= 0) and 1 or clamp01(s.cur / s.aim) -- the arcade's `rainbow` clip only plays once the track has ended if s.full then local frame = math.floor((self.clock or 0) / 5) % 8 self:put("meter_fill", mx + 15, my + 18, { frame = frame, fade = a }) end local marker = 17.95 + 231.05 * u if u < 1 then self:put("meter_cover", mx + marker, my + 20, { sx = (249 - marker) / 8, sy = 1, fade = a }) end self:put("meter_marker", mx + marker - 2.5, my + 16, { fade = a }) -- above the bar: its window is what cuts the 96 px tall fill down to the 64 px bar self:put("meter_panel", mx - 35, my + 2, { fade = a }) self:put("meter_arrow", mx + marker - 21.5, my - 14, { fade = a }) local box_f = s.box_f and (self.clock - s.box_f) or 999 if s.full and s.meter ~= "box" then self:mid("meter_face", mx + 288, my + 52, 1, a) local fa = s.meter == "full" and ramp(box_f, 0, 50) or 1 self:put("full_bar", mx + 19, my + 74, { sx = 28.75, sy = 4.375, fade = fa * a }) self:put("full_text", mx, my + 71, { fade = fa * a }) local pop = s.meter == "full" and ramp(box_f, 0, 20) * (1 - ramp(box_f, FULL_LEN - 15, 15)) or 0 if pop > 0 then self:mid("full_popup", mx + 288, my + 37, lerp(0.8, 1, pop), pop) end else local pop = s.meter == "box" and box_f or 999 local scale = pop < 24 and lerp(1, 1.5, ease_out(ramp(pop, 0, 14))) or 1 local shown = pop < 39 and (1 - ramp(pop, 39, 5)) or (pop >= 80 and ramp(pop, 80, 15) or (pop == 999 and 1 or 0)) if pop >= 80 and pop < 110 then self:mid("meter_gift", mx + 288, my + 52 + lerp(40, 0, ease_out(ramp(pop, 80, 15))), 1, shown * a) else self:mid("meter_gift", mx + 288, my + 52, scale, shown * a) end if pop < 39 then local burst = pop < 15 and ramp(pop, 0, 15) or (1 - ramp(pop, 15, 15)) self:mid("gift_white", mx + 288, my + 52, lerp(1, 1.6, ease_out(ramp(pop, 0, 15))), burst * a) end self:put("meter_slash", mx + 115, my + 71, { fade = a }) self:digits("digits_red", s.cur, mx + 88, my + 71, 24, a) self:digits("digits_black", s.aim, mx + 214, my + 71, 24, a) end end function TotalResult:draw_present_panel(s) if s.gifts <= 0 and not s.gift_f then return end local a = self.state == "close" and 1 - ramp(self.f, 0, 15) or 1 if a <= 0 then return end local px = PRESENT_X[s.seat] self:put("present_panel", px, PRESENT_Y, { fade = a }) if s.gifts > 10 then self:put("gift", px + 64, PRESENT_Y + 18, { fade = a }) self:put("times", px + 124, PRESENT_Y + 36, { fade = a }) self:digits("digits_present", math.min(s.gifts, 99), px + 174, PRESENT_Y + 36, 20, a) else for i = 0, s.gifts - 1 do -- bottom row first from the right, like the BoxIcon depths local col, row = 4 - (i % 5), i < 5 and 1 or 0 self:mid("gift", px + 46 + col * 45, PRESENT_Y + 30 + row * 44, 0.3, a) end end end function TotalResult:draw_reward(s) if not s.showing then return end local f, x, y = self.f, BOX_X[s.seat], BOX_Y local gift = s.showing -- the first box flies in over 30 f; each next one is already there local fly = s.first_open and ease_out(ramp(f, 0, 30)) or 1 local bs = lerp(0.5, 1, fly) local dx, dy = lerp(205, 0, fly) * (1 - fly), lerp(180, 0, fly) * (1 - fly) local out = f >= OPEN_LEN + ITEM_HOLD and ramp(f, OPEN_LEN + ITEM_HOLD, ITEM_OUT) or 0 local at = f - 30 -- box clock: closed, squash, then open at 81 local text_at = s.first_open and at or f + 60 if text_at >= 141 then local a = ramp(text_at, 141, 15) * (1 - out) if not self.gohobi_content then self.gohobi_content = true play("se_gohobi_content") end self:put("reward_plate", x - 200, y - 240, { fade = a }) self:put("reward_title", x - 92, y - 317, { frame = ART_FRAME[gift.type], fade = a }) if gift.text then gift.text:draw({ x = (x + 100) * S - gift.text.width / 2, y = (y - 236 + 25) * S - gift.text.height / 2, fade = a }) end end local key = "box_closed" if at >= 27 then key = "box_squash" end if not s.first_open or at >= 81 then key = "box_open" end local squash = (at >= 22 and at < 34) and 0.9 or 1 self:mid(key, x + 100 + dx, y + 100 + dy, bs, 1 - out, nil, bs * squash) if at >= 81 or not s.first_open then local u = s.first_open and ramp(at, 81, 22) or ramp(f, 0, 22) local icon_y = lerp(y + 10, y - 180, ease_out(u)) local icon_s = lerp(0.5, 1, ease_out(u)) local cx, cy = x + 100, icon_y + 100 self:mid("reward_glow", cx, cy, icon_s * 1.1, (1 - out) * 0.65) self:mid("reward_icon", cx, cy, icon_s, 1 - out, ART_FRAME[gift.type]) self.draw_icon(gift.icon, cx * S, cy * S, 120 * icon_s * S, 1 - out) if s.first_open and at >= 81 and not self.gohobi_detail then self.gohobi_detail = true play("se_gohobi_detail") end local smoke = s.first_open and at or (f + 81) if smoke >= 81 and smoke < 117 then local stage = smoke < 98 and 0 or (smoke < 104 and 1 or (smoke < 110 and 2 or 3)) local grow = smoke < 91 and lerp(0.1, 0.83, ease_out(ramp(smoke, 81, 10))) or 1 self:mid("smoke", x + 100, y + 110 - (smoke - 81) * 0.8, grow, 1 - ramp(smoke, 110, 7), stage) end end end function TotalResult:draw_heading() local st, f = self.state, self.f if st == "reward_in" or st == "reward_open" or st == "reward_out" then local a = st == "reward_in" and ramp(f, 0, 19) or (st == "reward_out" and 1 - ramp(f, 0, 15) or 1) self:mid("heading_reward", 640, 77, 0.8 + 0.2 * ((st == "reward_in") and ramp(f, 0, 9) or 1), a) end end -- no-card panel: the arcade loops six cards; art rests are kept, motion is a fade function TotalResult:draw_ad_card(i, dx, a) if i == 1 then self:put("ad_touch", 195 + dx, 356, { fade = a }) self:put("ad_or", 316 + dx, 259, { fade = a }) self:put("ad_phone", 381 + dx, 163, { sx = 1.13, fade = a }) self:put("ad_card", 104 + dx, 205, { fade = a }) elseif i == 2 then self:put("ad_stage", 55 + dx, 131, { fade = a }) self:put("ad_hand", 413 + dx, 406, { fade = a }) elseif i == 3 then self:mid("ad_rays", 335 + dx, 363, 1, a) local month = (self.month - 6) % 12 local costume = math.min(month, 10) self:put("ad_month", 155 + dx, 108, { frame = costume, fade = a }) self:put("ad_month_name", 155 + dx, 440, { frame = costume, fade = a }) self:put("ad_now", 53 + dx, 163, { sx = 0.6, fade = a }) elseif i == 4 then self:put("ad_bana", 251 + dx, 398, { fade = a }) self:put("ad_don_a", 450 + dx, 174, { fade = a }) self:put("ad_don_b", 66 + dx, 179, { fade = a }) self:put("ad_don_c", 414 + dx, 297, { fade = a }) self:put("ad_don_d", 99 + dx, 294, { fade = a }) self:put("ad_don_main", 231 + dx, 207, { fade = a }) self:put("ad_kisekae", 191 + dx, 173, { fade = a }) elseif i == 5 then self:put("ad_flower", 55 + dx, 131, { fade = a }) self:put("ad_phone2", 345 + dx, 234, { fade = a }) self:put("ad_card2", 76 + dx, 262, { sx = 1.16, fade = a }) self:put("ad_fun", 153 + dx, 168, { fade = a }) else self:put("ad_lines", 55 + dx, 131, { fade = a }) self:put("ad_boy", 66 + dx, 249, { fade = a }) self:put("ad_girl", 420 + dx, 215, { fade = a }) self:put("ad_getit", 189 + dx, 219, { fade = a }) end end function TotalResult:draw_ad(s) local st = self.state if st == "intro" or st == "slide" then return end if st == "close" and self.f >= 15 then return end local dx = AD_DX[s.seat] local a = st == "close" and 1 - ramp(self.f, 0, 15) or 1 self:put("ad_panel", 55 + dx, 131, { fade = a }) local total = 0 for _, len in ipairs(AD_CARDS) do total = total + len end local clock = (self.clock or 0) % total for i, len in ipairs(AD_CARDS) do if clock < len then local fade = ramp(clock, 0, 15) * (1 - ramp(clock, len - 15, 15)) self:draw_ad_card(i, dx, a * fade) break end clock = clock - len end self:put("ad_footer", (s.seat == 1 and 265 or 671), 491, { fade = a }) self:put("ad_mascot", (s.seat == 1 and 62 or 1092), 485, { fade = a }) end function TotalResult:draw() self:put("bg", 0, 0, { sx = 160, sy = 1 }) local st = self.state if st ~= "intro" then self:put("footer", 0, 577) end local pa = self:panel_alpha() for _, s in ipairs(self.seats) do if s.data then if pa > 0 then self:put("panel_back", (s.seat == 1 and 55 or 665), 131, { fade = pa * 0.5 }) end self:draw_music(s) self:draw_titles(s) self:draw_meter(s, pa) else self:draw_ad(s) end end for _, s in ipairs(self.seats) do if s.data then self:draw_present_panel(s) end end self:draw_curtain() self:draw_chip() self:draw_heading() for _, s in ipairs(self.seats) do self:draw_reward(s) end self:draw_intro_title() end