Nameplate = {} Nameplate.__index = Nameplate local PLAYER_NUM_AI = 5 local PLAYER_NUM_ALL = 0 local BG_PLATINUM = 3 local BG_GOLD = 4 local ORIGIN_X, ORIGIN_Y = 136.95, 15.0 local LOOP_MS = 2000 local FRAME_MS = 1000 / 60 local HALF = 35 -- shimmer and sparkle art are 70x70 -- One shimmer sweep per loop: grow in, glide across the title, shrink away local SHIMMER_Y = 15.85 local SHIMMER = { { 0, 13.3, 0.4, 0 }, { 100, 44.3, 1, 1 }, { 400, 224.3, 1, 1 }, { 500, 254.8, 0.2, 0 }, } -- Small sparkles pop in and shrink away: { start frame, x, y, frame index in sparkle folder } local SPARKS = { { 40, -56.65, 9.35, 1 }, { 42, -93.65, -10.65, 2 }, { 45, -76.65, -11.65, 1 }, { 47, -3.65, 13.35, 2 }, { 55, -63.65, 13.35, 2 }, { 56, -17.65, -16.65, 1 }, { 58, -107.65, 11.35, 1 }, { 60, 48.35, -8.65, 2 }, { 68, 78.35, 13.35, 1 }, { 68, 96.35, -6.65, 2 }, { 70, 28.35, 11.35, 1 }, { 73, 56.35, 13.35, 2 }, { 82, 66.35, 9.35, 2 }, { 83, 19.35, 12.35, 1 }, { 85, 79.35, -7.65, 1 }, { 87, -73.65, -8.65, 2 }, { 97, 126.35, -0.65, 2 }, { 100, 104.35, 11.35, 1 }, { 102, 46.35, 13.35, 2 }, { 104, 4.35, -8.65, 1 }, } local STAR_X, STAR_Y = ORIGIN_X + 99.85, ORIGIN_Y - 10.15 local function lerp(a, b, u) return a + (b - a) * u end function Nameplate.new(name, title, player_num, dan, is_gold, is_rainbow, title_bg) local self = setmetatable({}, Nameplate) self.player_num = player_num self.dan = dan self.is_gold = is_gold self.is_rainbow = is_rainbow self.title_bg = title_bg self.shadow = tex.get_texture("global/nameplate/shadow") self.ai = tex.get_texture("global/nameplate/ai") self.outline = tex.get_texture("global/nameplate/outline") self.frame_top = tex.get_texture("global/nameplate/frame_top") self.frame_top_rainbow = tex.get_texture("global/nameplate/frame_top_rainbow") self.dan_emblem_bg = tex.get_texture("global/nameplate/dan_emblem_bg") self.dan_emblem = tex.get_texture("global/nameplate/dan_emblem") self.dan_emblem_gold = tex.get_texture("global/nameplate/dan_emblem_gold") self.shimmer = tex.get_texture("global/nameplate/shimmer") if title_bg == BG_GOLD then self.sparkle = tex.get_texture("global/nameplate/sparkle_gold") else self.sparkle = tex.get_texture("global/nameplate/sparkle") end self.shiny = not is_rainbow and player_num ~= PLAYER_NUM_ALL and player_num ~= PLAYER_NUM_AI and (title_bg == BG_GOLD or title_bg == BG_PLATINUM) self.rainbow_anim = tex.get_animation(12, "global") local s = tex.get_screen_scale() self.name_text = text.create_raw_text(name, math.floor(22 * s), { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, 3) self.title_text = text.create_raw_text(title, math.floor(20 * s), { 0, 0, 0, 255 }, { 0, 0, 0, 0 }, false, 0) self.padding = tex.get_skin_config("nameplate_text_padding").x self.name_offset = tex.get_skin_config("nameplate_name_offset").y self.title_offset = 2 * s self.outline_info = tex.get_texture_info("nameplate", "outline") self.frame_top_info = tex.get_texture_info("nameplate", "frame_top") self.emblem_info = tex.get_texture_info("nameplate", "dan_emblem") if player_num ~= PLAYER_NUM_ALL and player_num ~= PLAYER_NUM_AI then local pnum_key = tostring(player_num) .. "p" self.pnum_tex = tex.get_texture("global/nameplate/" .. pnum_key) self.pnum_info = tex.get_texture_info("nameplate", pnum_key) end return self end function Nameplate:update(current_ms) self.rainbow_anim:update(current_ms) self.t0 = self.t0 or current_ms self.now = current_ms - self.t0 end function Nameplate:draw_shimmer(x, y, fade) local t = self.now % LOOP_MS if t >= SHIMMER[#SHIMMER][1] then return end for i = 2, #SHIMMER do local a, b = SHIMMER[i - 1], SHIMMER[i] if t < b[1] then local u = (t - a[1]) / (b[1] - a[1]) local s = lerp(a[3], b[3], u) tex.draw_texture(self.shimmer, { x = x + lerp(a[2], b[2], u) - HALF, y = y + SHIMMER_Y - HALF, scale = s, center = true, fade = fade * lerp(a[4], b[4], u), }) return end end end function Nameplate:draw_sparkles(x, y, fade) local fr = (self.now % LOOP_MS) / FRAME_MS if fr >= 22 and fr < 39 then local s, rot, alpha = 1, 0, 1 if fr < 28 then local u = (fr - 22) / 6 local e = 1 - (1 - u) * (1 - u) s, rot = lerp(0.543, 1, e), -360 * e elseif fr < 31 then s = lerp(1, 1.371, (fr - 28) / 3) else local u = (fr - 31) / 8 s, alpha = lerp(1.371, 1, u), 1 - u end tex.draw_texture(self.sparkle, { frame = 0, x = x + STAR_X - HALF + HALF * s, y = y + STAR_Y - HALF + HALF * s, -- origin shifts dest rect, add it back scale = s, center = true, origin = { HALF * s, HALF * s }, rotation = rot, fade = fade * alpha, }) end for _, p in ipairs(SPARKS) do local lf = fr - p[1] if lf >= 0 and lf < 9 then local s if p[4] == 1 then s = lf < 5 and 1 or lerp(0.886, 0.543, (lf - 5) / 3) else s = lf < 4 and 1 or lerp(0.87, 0.35, (lf - 4) / 4) end tex.draw_texture(self.sparkle, { frame = p[4], x = x + ORIGIN_X + p[2] - HALF, y = y + ORIGIN_Y + p[3] - HALF, scale = s, center = true, fade = fade, }) end end end function Nameplate:draw(x, y, fade) fade = fade or 1.0 tex.draw_texture(self.shadow, { x = x, y = y, fade = math.min(0.5, fade) }) if self.player_num == PLAYER_NUM_AI then tex.draw_texture(self.ai, { x = x, y = y }) return end local frame = (self.player_num == PLAYER_NUM_ALL) and 2 or self.title_bg if self.is_rainbow then local ra = self.rainbow_anim.attribute if ra > 0 and ra < 6 then tex.draw_texture(self.frame_top_rainbow, { frame = math.floor(ra) - 1, x = x, y = y, fade = fade }) end tex.draw_texture(self.frame_top_rainbow, { frame = math.floor(ra), x = x, y = y, fade = fade }) else tex.draw_texture(self.frame_top, { frame = frame, x = x, y = y, fade = fade }) end if self.now and self.shiny and not self.is_rainbow then self:draw_shimmer(x, y, fade) end tex.draw_texture(self.outline, { x = x, y = y, fade = fade }) if self.now and self.shiny then self:draw_sparkles(x, y, fade) end local dan_offset = 0 if self.dan ~= -1 then tex.draw_texture(self.dan_emblem_bg, { x = x, y = y, fade = fade }) if self.is_gold then tex.draw_texture(self.dan_emblem_gold, { frame = self.dan, x = x, y = y, fade = fade }) else tex.draw_texture(self.dan_emblem, { frame = self.dan, x = x, y = y, fade = fade }) end dan_offset = self.emblem_info.width end local offset = 0 if self.player_num ~= PLAYER_NUM_ALL then tex.draw_texture(self.pnum_tex, { x = x, y = y, fade = fade }) offset = self.pnum_info.width / 2.0 end local outline_w = self.outline_info.width local frame_top_w = self.frame_top_info.width local frame_top_h = self.frame_top_info.height local outline_h = self.outline_info.height local name_max = frame_top_w - self.padding - offset - dan_offset local name_width = math.min(self.name_text.width, name_max) local name_x = x + offset + dan_offset + (outline_w - offset - dan_offset) / 2.0 - name_width / 2 local name_y = y + outline_h / 2.0 + self.name_offset self.name_text:draw({ x = name_x, y = name_y, x2 = name_width - self.name_text.width, fade = fade }) local title_max = frame_top_w - self.padding - offset local title_width = math.min(self.title_text.width, title_max) local title_x = x + offset + (frame_top_w - offset) / 2.0 - title_width / 2 local title_y = y + frame_top_h / 2.0 - self.title_text.height / 2 + self.title_offset self.title_text:draw({ x = title_x, y = title_y, x2 = title_width - self.title_text.width, fade = fade }) end