This commit is contained in:
boonsboos
2025-09-08 22:59:59 +02:00
commit aca5cd42f1
36 changed files with 1137 additions and 0 deletions

BIN
asset/clippy-bubble.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
asset/groove-gauge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
asset/jacket.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
asset/song-data.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
asset/taskbar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
asset/time-container.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

BIN
asset/window.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
customize/bg/fail/bsod.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

View File

BIN
customize/clippy/ASIO.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
customize/clippy/Bonzi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
customize/clippy/Clippy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
customize/clippy/Penger.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

70
dst/clippy.lua Normal file
View File

@@ -0,0 +1,70 @@
local function getClippy(speechBubbleX, speechBubbleY, speechBubbleFontHeight)
return {
-- clippy
{
id = "clippy_character",
filter = 0, -- nearest neigbour
dst = {
{ x = speechBubbleX - 10, y = 66, w = 300, h = 300, a = 255 }
}
},
{
id = "clippy_speechbubble",
dst = {
{ x = speechBubbleX, y = speechBubbleY, w = 300, h = 300, a = 255 }
}
},
-- clippy speech text
{
id = "clippy_rank",
dst = {
{ x = speechBubbleX + 10, y = speechBubbleY + 220, w = 300, h = 60, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "clippy_rank_best",
dst = {
{ x = speechBubbleX + 190, y = speechBubbleY + 230, w = 100, h = speechBubbleFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
-- gauge type
{
id = "clippy_clear_type",
dst = {
{ x = speechBubbleX + 10, y = speechBubbleY + 160, w = 300, h = speechBubbleFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "clippy_clear_type_best",
dst = {
{ x = speechBubbleX + 190, y = speechBubbleY + 160, w = 100, h = speechBubbleFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
-- ir display
{
id = "clippy_ir_unavailable",
op = { 50 },
dst = {
{ x = speechBubbleX + 10, y = speechBubbleY + 100, w = 300, h = speechBubbleFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "clippy_ir_rank",
op = { 51 },
dst = {
{ x = speechBubbleX + 10, y = speechBubbleY + 100, w = 300, h = speechBubbleFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
-- rate
{
id = "clippy_rate",
dst = {
{ x = speechBubbleX + 10, y = speechBubbleY + 40, w = 300, h = speechBubbleFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
}
}
end
return {
getClippy = getClippy
}

37
dst/gauge.lua Normal file
View File

@@ -0,0 +1,37 @@
local function getGauge(grooveX, grooveY)
return {
-- gauge graph
{
id = "bg_groove",
loop = 200,
dst = {
{ time = 0, x = grooveX, y = grooveY, w = 600, h = 300, a = 0, filter = 1 },
{ time = 200, a = 255 }
}
},
{
id = "text_groove_title",
loop = 200,
dst = {
{ time = 0, x = grooveX + 70, y = grooveY + 240, w = 400, h = 40, a = 0, r = 255, g = 255, b = 255, filter = 1 },
{ time = 200, a = 255 }
}
},
{
id = "gauge_line",
dst = {
{ x = grooveX + 4, y = grooveY + 4, w = 592, h = 230, a = 255 }
}
},
{
id = "gauge_bg",
dst = {
{ x = grooveX + 4, y = grooveY + 4, w = 592, h = 230, a = 192 }
}
}
}
end
return {
getGauge = getGauge
}

42
dst/jacket.lua Normal file
View File

@@ -0,0 +1,42 @@
local function getJacket(jacketWindowX, jacketWindowY)
-- jacket image
return {
{
id = "jacket_window",
dst = {
{ x = jacketWindowX, y = jacketWindowY, w = 408, h = 372, a = 255 }
}
},
{
id = "text_jacket_title",
dst = {
{ x = jacketWindowX + 68, y = jacketWindowY + 314, w = 130, h = 40, a = 255, r = 255, g = 255, b = 255 }
}
},
{
id = -110, -- black image for the black bars in the jacket window
dst = {
{ x = jacketWindowX + 6, y = jacketWindowY + 6, w = 396, h = 296, a = 255 }
}
},
{
id = -100, -- stage file (music select image)
op = { 191 },
dst = {
{ x = jacketWindowX + 6, y = jacketWindowY + 6, w = 396, h = 296, a = 255 }
}
},
{
id = "jacket_no_jacket",
op = { 190 },
dst = { -- text is centered so the draw origin is shifted by 200 px
{ x = jacketWindowX + 206, y = jacketWindowY + 120, w = 400, h = 52, a = 255, r = 255, g = 255, b = 255 }
}
}
}
end
return {
getJacket = getJacket
}

105
dst/songdata.lua Normal file
View File

@@ -0,0 +1,105 @@
local game = require("main_state")
local function getDiffColor(op)
local diff = tonumber(game.number(op))
if diff < 0 then
return 192
end
return 10
end
local function getSongData(judgeX, judgeY, judgeFontHeight, judgeOffset)
return {
-- song data + playdata
{
id = "bg_song",
dst = {
{ x = judgeX - 10, y = judgeY - 305, w = 1220, h = 376, a = 255, filter = 1 }
}
},
{
id = "text_title",
dst = {
{ x = judgeX + 60, y = judgeY + 12, w = 960, h = 40, a = 255, r = 255, g = 255, b = 255, filter = 1 }
}
},
{
id = "text_level",
dst = {
{ x = judgeX, y = judgeY - judgeOffset * 7 - 20, w = 150, h = 40, a = 255, r = 10, g = 10, b = 10, filter = 1 }
}
},
-- playdata
{
id = "pgreat",
dst = {
{ x = judgeX, y = judgeY - judgeOffset * 1, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "great",
dst = {
{ x = judgeX, y = judgeY - judgeOffset * 2, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "good",
dst = {
{ x = judgeX, y = judgeY - judgeOffset * 3, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "bad",
dst = {
{ x = judgeX, y = judgeY - judgeOffset * 4, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "poor",
dst = {
{ x = judgeX, y = judgeY - judgeOffset * 5, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "expoor",
dst = {
{ x = judgeX, y = judgeY - judgeOffset * 6, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "exscore",
dst = {
{ x = judgeX + 275, y = judgeY - judgeOffset * 1, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 10, b = 10 }
}
},
{
id = "exscore_diff",
dst = {
{ x = judgeX + 275, y = judgeY - judgeOffset * 2, w = 300, h = judgeFontHeight, a = 255, r = getDiffColor(172), g = 10, b = 10 }
}
},
{
id = "exscore_diff_target",
dst = {
{ x = judgeX + 275, y = judgeY - judgeOffset * 3, w = 300, h = judgeFontHeight, a = 255, r = getDiffColor(153), g = 10, b = 10 }
}
},
-- fastslow
{
id = "total_fast",
dst = {
{ x = judgeX + 275, y = judgeY - judgeOffset * 5, w = 300, h = judgeFontHeight, a = 255, r = 10, g = 140, b = 180 }
}
},
{
id = "total_slow",
dst = {
{ x = judgeX + 275, y = judgeY - judgeOffset * 6, w = 300, h = judgeFontHeight, a = 255, r = 140, g = 10, b = 10 }
}
},
}
end
return {
getSongData = getSongData
}

27
dst/taskbar.lua Normal file
View File

@@ -0,0 +1,27 @@
local function getTaskbar()
return {
-- task bar
{ -- todo(boons): extract start button icon so we can use it to toggle the leaderboard
id = "taskbar",
dst = {
{ x = 0, y = 0, w = 1920, h = 63, a = 255, filter = 1 }
}
},
{
id = "taskbar_time",
dst = {
{ x = 1455, y = 7, w = 460, h = 50, a = 255, filter = 1 }
}
},
{
id = "taskbar_time_text",
dst = {
{ x = 1463, y = 8, w = 444, h = 40, a = 255, r = 0, g = 0, b = 0 }
}
}
}
end
return {
getTaskbar = getTaskbar
}

Binary file not shown.

BIN
font/Windows_Regular.ttf Normal file

Binary file not shown.

16
readme.md Normal file
View File

@@ -0,0 +1,16 @@
# win95 skin for \*oraja
what it says on the tin
fully lua, i dont know json
tested with vanilla 0.8.8 and ED 0.3
## contents
1. result (wip)
1. course result (soon)
## customizing
drop things into the folders, then choose in the config window or ingame

6
result.luaskin Normal file
View File

@@ -0,0 +1,6 @@
local result_skin = require("win95-main")
if skin_config then
return result_skin.main()
else
return result_skin.header
end

45
util/index.html Normal file
View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="win95.css" />
<title>Document</title>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
</head>
<body>
<!-- my first idea was to use this win95 css shit, but it sucked and was bad. -->
<div id="card" class="card w95" style="height: 1076px; width: 1918px">
<div class="card-header" style="height: 60px"></div>
</div>
<div
id="wallpaper"
style="
background-image: url('tiles/Clouds_\(Windows_95\).png');
background-repeat: repeat;
height: 360px;
width: 640px;
"
></div>
</body>
<script>
html2canvas(card, {
width: 1920,
height: 1080,
windowWidth: 1920,
windowHeight: 1080,
}).then((canvas) => {
document.body.appendChild(canvas);
});
html2canvas(wallpaper, {
width: 640,
height: 360,
windowWidth: 1920,
windowHeight: 1080,
}).then((canvas) => {
document.body.appendChild(canvas);
});
</script>
</html>

View File

@@ -0,0 +1,13 @@
U+25BD : WHITE DOWN-POINTING TRIANGLE {Hamilton operator}
U+25BC : BLACK DOWN-POINTING TRIANGLE
U+2606 : WHITE STAR
U+2605 : BLACK STAR
U+25C6 : BLACK DIAMOND
U+25CE : BULLSEYE

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
util/tiles/Gold_Weave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
util/tiles/Red_Blocks.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

BIN
util/tiles/Stitches.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

1
util/tiles/i.txt Normal file
View File

@@ -0,0 +1 @@
from https://windowswallpaper.miraheze.org/wiki/Windows_95

498
util/win95.css Normal file
View File

@@ -0,0 +1,498 @@
/*
WIN95.CSS
https://github.com/AlexBSoft/win95.css
Author: Alex B (alex-b.me)
License: MIT
Version: 1.2.0
06.12.2020
*/
html {
position: relative;
min-height: 100%;
}
/*
Body styles
*/
body {
font-family: "Windows Regular", monospace;
background: teal;
color: white;
padding-bottom: 28px;
}
/*
Button styles
*/
.btn {
border-width: 2px;
border-style: outset;
border-color: buttonface;
border-right-color: #424242;
border-bottom-color: #424242;
background: silver;
color: black;
padding: 0 0 4px;
border-radius: 1px;
}
.btn:hover {
border: 2px inset #fff;
background: silver;
color: #424242;
box-shadow: -1px -1px #000;
}
.btn:focus {
border: 2px inset #fff !important;
background: silver;
color: #424242;
box-shadow: -1px -1px #000 !important;
outline: 0 !important;
background: url(background.bmp);
}
.btn:active {
border: 2px inset #fff !important;
color: #424242;
box-shadow: -1px -1px #000 !important;
outline: 0 !important;
background: url(background.bmp);
}
.btn-primary {
padding-left: 8px;
padding-right: 8px;
}
button:focus {
outline: 1px dotted;
}
.btn.disabled,
.btn:disabled {
cursor: default;
background-color: silver;
border-style: outset;
border-color: buttonface;
border-right-color: #424242;
border-bottom-color: #424242;
color: grey;
text-shadow: 1px 1px #fff;
}
/*
CARDS
*/
.card {
border: solid;
border-width: 2px;
border-bottom-color: #424242;
border-right-color: #424242;
border-left-color: #fff;
border-top-color: #fff;
background: silver;
color: #212529;
}
.card.square {
border-radius: 0px;
}
.card.square .card-header {
border-radius: 0px;
}
.card.w95 .card-header {
background: #08216b;
/* OR #000082 is better?*/
}
.card-header {
background: -webkit-linear-gradient(left, #08216b, #a5cef7);
color: #fff;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-top: 2px;
padding-bottom: 1px;
text-align: left;
}
.card-header.icon {
padding-left: 4px;
}
.header-inactive {
background: gray !important;
}
/*
LIST GROUPS
*/
.list-group {
border: solid;
border-width: 2px;
border-bottom-color: #424242;
border-right-color: #424242;
border-left-color: #fff;
border-top-color: #fff;
background: silver;
color: #212529;
}
.list-group-item {
position: relative;
display: block;
background: transparent;
color: #212529;
}
.list-group-item-primary {
color: white;
background: -webkit-linear-gradient(left, #08216b, #a5cef7);
}
.list-group-item-action:hover {
color: #08216b;
}
/*
NAVBAR
*/
.navbar-95 {
background: silver;
margin: 0;
border: 1px outset #fff;
min-height: 40px;
padding: 0 6px;
color: #212529;
}
.navbar-brand {
color: #212529;
padding: 0 6px;
}
.nav-link {
text-decoration: none;
display: inline-block;
padding: 0 9px;
color: #212529;
}
.dropdown-menu {
display: none;
min-width: 119px;
padding: 0 0 2px;
margin-left: 12px;
font-size: 12px;
list-style-type: none;
background: silver;
border: 1.8px outset #fff;
border-radius: 0;
-webkit-box-shadow: 1.5px 1.5px #000;
box-shadow: 1.5px 1.5px #000;
}
.dropdown-item {
padding: 1px 0 1px 2px;
}
.dropdown-item:hover {
color: #08216b;
}
.navbar-light .navbar-toggler.collapsed .navbar-toggler-icon {
width: 32px;
background: url(icons/directory_closed_cool-5.png);
}
.navbar-light .navbar-toggler .navbar-toggler-icon {
width: 32px;
background: url(icons/directory_open_cool-5.png);
}
.navbar-toggler {
width: auto;
}
/*
FOOTER
*/
.taskbar {
cursor: default;
background-color: silver;
margin: 16px 0 0 0;
padding: 0 8px;
position: static;
bottom: 0;
border-top: 2px outset #fff;
z-index: 228;
width: 100%;
margin-right: 0px;
position: absolute;
bottom: 0;
}
.taskbar .start-button {
cursor: default;
display: inline-block;
border: 1px outset #fff;
padding: 0 0 0 2px;
box-shadow: 1px 1px #000;
margin-bottom: 2px;
font-size: 14px;
}
.taskbar .time {
color: #212529;
margin-top: 2px;
text-align: right;
font-size: 14px;
margin-right: 0px;
}
#page-content {
flex: 1 0 auto;
}
/*
ICONS
*/
.icon-16 {
margin-bottom: 2px;
max-height: 16px;
}
.icon-16-4 {
margin-bottom: 4px;
max-height: 16px;
}
/*
FORMS
*/
.form-95 {
width: 100%;
border: 2px inset #d5d5d5;
color: #424242;
background: #fff;
box-shadow: -1px -1px 0 0 #828282;
margin-top: 4px;
padding-left: 2px;
}
.bootstrap-select,
textarea:focus,
textarea.form-control:focus,
input.form-control:focus,
input[type="text"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
input[type="number"]:focus,
[type="text"].form-control:focus,
[type="password"].form-control:focus,
[type="email"].form-control:focus,
[type="tel"].form-control:focus,
[contenteditable].form-control:focus {
outline: 0 !important;
}
input[type="radio"],
input[type="checkbox"] {
position: absolute;
left: -9999px;
}
.form-check-label::before,
.form-check-label::after {
content: "";
position: absolute;
top: 0;
left: 0;
}
.form-check-label {
margin-left: 6px;
}
input[type="radio"] + .form-check-label::before,
input[type="radio"] + .form-check-label::after {
border-radius: 50%;
}
.form-check-label::before {
height: 20px;
width: 20px;
top: 3px;
padding-right: 2px;
border: 2px inset #d5d5d5;
background: white;
box-shadow: -1px -1px 0 0 #828282;
}
input[type="radio"] + .form-check-label::after {
display: none;
width: 8px;
height: 8px;
margin: 6px;
top: 3px;
background: black;
}
input[type="checkbox"] + .form-check-label::after {
display: none;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23000' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
width: 12px;
height: 12px;
margin: 4px;
top: 3px;
}
input:checked + .form-check-label::after {
display: block;
}
/*
Progress bar
*/
.progress {
height: 1rem;
overflow: hidden;
font-size: 0.75rem;
background-color: silver;
border-radius: 0rem;
border: 1px inset #d5d5d5;
color: #424242;
}
.progress-bar {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
color: #fff;
text-align: center;
background-color: #1a0094;
transition: width 0.6s ease;
}
.progress-bar-blocks {
background-image: linear-gradient(90deg, transparent 75%, #d5d5d5 25%);
background-size: 1rem 1rem;
}
/*
TABS
*/
.tab-content {
background: silver;
border: solid;
border-width: 2px;
border-bottom-color: #424242;
border-right-color: #424242;
border-left-color: #fff;
border-top-color: silver;
padding: 1rem 1.4rem;
}
.nav-tabs {
border-bottom: 2px solid white;
}
.nav-tabs .nav-item {
position: relative;
margin-bottom: 0;
background: #c0c0c0;
color: black;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-right: 1px solid #5a5a5a;
box-sizing: border-box;
}
.nav-tabs .nav-item .nav-link {
color: black;
padding: 0.2rem 1.8rem;
box-sizing: border-box;
transform: none;
}
.nav-tabs .nav-item .nav-link.active {
position: relative;
background: #c0c0c0;
}
.nav-tabs .nav-item:not(:first-child) .nav-link.active {
border-left: 1px solid #5a5a5a;
}
.nav-tabs .nav-item:first-child {
border-left: 2px solid white;
}
.nav-tabs .nav-item .nav-link.active:after {
content: "";
display: block;
width: 100%;
height: 2px;
position: absolute;
left: 0;
bottom: -2px;
background: #c0c0c0;
}
.nav-tabs .nav-link {
border: 0;
padding: 1rem 1rem;
}
/*
MODAL
TODO: make it draggable;
*/
.modal-content {
box-shadow: 1px 1px 0 0 #424242;
border: 1px solid #fff;
border-right-color: #848484;
border-bottom-color: #848484;
background: silver;
padding: 2px;
}
.modal-header {
height: 32px;
background: -webkit-linear-gradient(left, #08216b, #a5cef7) !important;
color: white;
padding-top: 0px;
padding-bottom: 0px;
padding-left: 6px;
padding-right: 6px;
}
.modal-header .btn {
margin-top: 5px;
padding-bottom: 10px;
height: 22px;
width: 22px;
}
.modal-header .btn span {
position: absolute;
top: 6px;
right: 14px;
}
.modal-title {
padding-top: 2px;
padding-bottom: 1px;
}
.modal-footer {
padding: 6px;
}
/*
TABLES
*/
.table {
background: white;
border-color: #c0c0c0;
}
.table-bordered {
border: 1px solid #c0c0c0;
}
.table-bordered td,
.table-bordered th {
border: 1px solid #c0c0c0;
}
.table td,
.table th {
padding: 0.75rem;
vertical-align: top;
border-top: 1px solid #c0c0c0;
}

277
win95-main.lua Normal file
View File

@@ -0,0 +1,277 @@
-- get raja state
local game = require("main_state")
local timer_util = require("timer_util")
local judgeY = 992
local judgeX = 30
local judgeOffset = 40
local judgeFontHeight = 36
local grooveX = 660
local grooveY = 650
local speechBubbleX = 1600
local speechBubbleY = 374
local speechBubbleFontHeight = 30
local jacketWindowY = 200
local jacketWindowX = 1000
function Append(list, t)
if t then
for i, v in pairs(t) do
table.insert(list, v)
end
end
end
local function getDiff(op)
local diff = tonumber(game.number(op))
if diff < 0 then
return diff
end
return "+" .. diff
end
-- thanks mr mary
local function getClearType()
local cleartype = {
[0] = "PASSED",
[1] = "FAILED",
[2] = "A-CLEAR",
[3] = "LA-CLEAR",
[4] = "EASY CLEAR",
[5] = "CLEAR",
[6] = "HARD CLEAR",
[7] = "EXH CLEAR",
[8] = "FC",
[9] = "PERFECT",
[10] = "MAX"
}
-- clear id
return cleartype[game.number(370)]
end
local function isBestClear()
-- target clear < current clear
if game.number(371) < game.number(370) then
return "(BEST)"
else
return ""
end
end
-- thanks mr mary
local function getRank()
local rank = {
[1] = "AAA",
[2] = "AA",
[3] = "A",
[4] = "B",
[5] = "C",
[6] = "D",
[7] = "E",
[8] = "F"
}
local gradeOptionIdx = 0
repeat
gradeOptionIdx = gradeOptionIdx + 1
until game.option(299 + gradeOptionIdx)
return rank[gradeOptionIdx]
end
local function isBestRank()
local nowRank = 0
local bestRank = 0
repeat
nowRank = nowRank + 1
until game.option(299 + nowRank)
repeat
bestRank = bestRank + 1
until game.option(319 + bestRank)
-- counter-intuitive, but AAA is 0, and F is 8
-- so whichever stops earlier is win
if bestRank > nowRank then
return "(BEST)"
else
return ""
end
end
local function getIrRank()
return game.number(179)
end
local function getIrTotal()
return game.number(180)
end
local function constructIrRankDisplay()
return game.text(1020) .. ": " .. getIrRank() .. " / " .. getIrTotal()
end
local header = {
-- type = result
type = 7,
name = "win95 result",
-- skin size
w = 1920,
h = 1080,
-- scene timer
scene = 3600000,
-- time until inputs are active
input = 500,
-- time it takes to fade out
fadeout = 100,
-- me :D
author = "boons",
-- config options
filepath = {
{ name = "CLEAR", path = "customize/bg/clear/*.png", def = "_Default.png", category = "CLEAR" },
{ name = "FAIL", path = "customize/bg/fail/*.png", def = "BSOD.png", category = "FAIL" },
{ name = "CLIPPY", path = "customize/clippy/*.png", def = "Clippy.png", category = "CLIPPY" }
},
category = {
{
name = "RESULT BG",
item =
{
"CLEAR",
"FAIL"
}
},
{
name = "CLIPPY",
item =
{
"CLIPPY"
}
}
}
}
local function main()
local skin = {}
-- add header properties into skin
for k, v in pairs(header) do
skin[k] = v
end
-- tell raja where to look for assets
skin.source = {
{ id = 0, path = "customize/bg/fail/*.png" },
{ id = 1, path = "customize/bg/clear/*.png" },
{ id = 2, path = "asset/song-data.png" },
{ id = 3, path = "asset/groove-gauge.png" },
{ id = 4, path = "asset/clippy-bubble.png" },
{ id = 5, path = "customize/clippy/*.png" },
{ id = 6, path = "asset/jacket.png" },
{ id = 7, path = "asset/taskbar.png" },
{ id = 8, path = "asset/time-container.png" }
-- todo: taskbar items
}
skin.font = {
{ id = 0, path = "font/SarasaMonoCL-Regular.ttf" }, -- CJK monospace
{ id = 1, path = "font/Windows_Regular.ttf" } -- clippy speech
}
skin.image = {
{ id = "bg_clear", src = 1, x = 0, y = 0, w = -1, h = -1 },
{ id = "bg_failed", src = 0, x = 0, y = 0, w = -1, h = -1 },
{ id = "bg_song", src = 2, x = 0, y = 0, w = -1, h = -1 },
{ id = "bg_groove", src = 3, x = 0, y = 0, w = -1, h = -1 },
{ id = "clippy_speechbubble", src = 4, x = 0, y = 0, w = -1, h = -1 },
{ id = "clippy_character", src = 5, x = 0, y = 0, w = -1, h = -1 },
{ id = "jacket_window", src = 6, x = 0, y = 0, w = -1, h = -1 },
{ id = "taskbar", src = 7, x = 0, y = 0, w = -1, h = -1 },
{ id = "taskbar_time", src = 8, x = 0, y = 0, w = -1, h = -1 }
}
skin.text = {
{ id = "text_groove_title", font = 0, size = 40, align = 0, overflow = 1, constantText = "GAUGE: " .. game.number(107) .. "." .. game.number(407) .. "%" }, -- gauge
{ id = "text_title", font = 0, size = 40, align = 0, overflow = 2, ref = 12 }, -- shrink
{ id = "text_level", font = 0, size = 40, align = 0, overflow = 1, ref = 1002 },
{ id = "pgreat", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "PERFECT: " .. game.number(110) },
{ id = "great", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "GREAT : " .. game.number(111) },
{ id = "good", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "GOOD : " .. game.number(112) },
{ id = "bad", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "BAD : " .. game.number(113) },
{ id = "poor", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "POOR : " .. game.number(114) },
{ id = "expoor", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "EXPOOR : " .. game.number(420) },
{ id = "exscore", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "SCORE : " .. game.number(171) },
{ id = "exscore_diff", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "BEST : " .. getDiff(172) },
{ id = "exscore_diff_target", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "TARGET : " .. getDiff(153) },
-- judge rank
{ id = "total_fast", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "FAST : " .. game.number(423) },
{ id = "total_slow", font = 0, size = judgeFontHeight, align = 0, overflow = 1, constantText = "SLOW : " .. game.number(424) },
-- clippy
{ id = "clippy_rank", font = 1, size = 60, align = 0, overflow = 1, constantText = getRank() },
{ id = "clippy_rank_best", font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = isBestRank() },
{ id = "clippy_clear_type", font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = getClearType() },
{ id = "clippy_clear_type_best", font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = isBestClear() },
{ id = "clippy_rate", font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = "RATE: " .. game.number(155) .. "." .. game.number(156) .. "%" },
-- ir
{
id = "clippy_ir_rank",
font = 1,
size = speechBubbleFontHeight,
align = 0,
overflow = 1,
value = constructIrRankDisplay
},
{ id = "clippy_ir_unavailable", font = 1, size = speechBubbleFontHeight, align = 0, overflow = 1, constantText = "IR OFFLINE (^^);" },
--jacket
{ id = "text_jacket_title", font = 0, size = 40, align = 0, overflow = 1, constantText = "JACKET" },
{ id = "jacket_no_jacket", font = 0, size = 52, align = 1, overflow = 1, constantText = "NO JACKET (^^);" },
-- task bar
{ id = "taskbar_time_text", font = 1, size = 40, align = 0, overflow = 1, constantText = os.date("%c") }
}
-- gauge graph
skin.gaugegraph = {
{ id = "gauge_line", assistClearLineColor = "FF00FF00", assistAndEasyFailLineColor = "00ff0000", grooveFailLineColor = "00ffff00", grooveClearAndHardLineColor = "ff000000", exHardLineColor = "ffff0000", hazardLineColor = "cccccc00", borderlineColor = "ff000000" },
{ id = "gauge_bg", assistClearBGColor = "ff00ff00", assistAndEasyFailBGColor = "00ff0000", grooveFailBGColor = "00ffff00", grooveClearAndHardBGColor = "ff000000", exHardBGColor = "ffff0000", hazardBGColor = "44444400", borderColor = "eeeeee00" },
}
-- put it all to use
skin.destination = {
{
id = "bg_clear",
op = { 90 }, -- cleared
dst = {
{ x = 0, y = 0, w = 1920, h = 1080, a = 255, filter = 1 }
}
},
{
id = "bg_failed",
op = { 91 }, -- failed
dst = {
{ x = 0, y = 0, w = 1920, h = 1080, a = 255, filter = 1 }
}
}
}
local songdata = require("dst.songdata")
local clippy = require("dst.clippy")
local gauge = require("dst.gauge")
local jacket = require("dst.jacket")
local taskbar = require("dst.taskbar")
Append(skin.destination, songdata.getSongData(judgeX, judgeY, judgeFontHeight, judgeOffset))
Append(skin.destination, clippy.getClippy(speechBubbleX, speechBubbleY, speechBubbleFontHeight))
Append(skin.destination, gauge.getGauge(grooveX, grooveY))
Append(skin.destination, jacket.getJacket(jacketWindowX, jacketWindowY))
Append(skin.destination, taskbar.getTaskbar())
return skin
end
return {
header = header,
main = main
}