Add support for upcoming cards and stages

This commit is contained in:
Andrio Celos 2024-02-22 15:42:39 +11:00
parent 3bcf9cbb71
commit 125531cfbe
6 changed files with 389 additions and 28 deletions

View File

@ -106,18 +106,20 @@ function openGalleryCardView(card: Card) {
galleryCardEditorSubmitButton.hidden = true;
galleryCardEditorCancelButton.innerText = 'Close';
galleryCardEditorRarityBox.value = card.rarity.toString();
galleryCardEditorColour1.value = `#${card.inkColour1.r.toString(16).padStart(2, '0')}${card.inkColour1.g.toString(16).padStart(2, '0')}${card.inkColour1.b.toString(16).padStart(2, '0')}`;
galleryCardEditorColour2.value = `#${card.inkColour2.r.toString(16).padStart(2, '0')}${card.inkColour2.g.toString(16).padStart(2, '0')}${card.inkColour2.b.toString(16).padStart(2, '0')}`;
updateSelectedPreset([card.inkColour1, card.inkColour2]);
if (card.isCustom) {
galleryCardEditorRarityBox.value = card.rarity.toString();
galleryCardEditorColour1.value = `#${card.inkColour1.r.toString(16).padStart(2, '0')}${card.inkColour1.g.toString(16).padStart(2, '0')}${card.inkColour1.b.toString(16).padStart(2, '0')}`;
galleryCardEditorColour2.value = `#${card.inkColour2.r.toString(16).padStart(2, '0')}${card.inkColour2.g.toString(16).padStart(2, '0')}${card.inkColour2.b.toString(16).padStart(2, '0')}`;
updateSelectedPreset([card.inkColour1, card.inkColour2]);
galleryCardEditorName.value = card.line2 == null ? card.name : `${card.line1}\n${card.line2}`;
for (let y = 0; y < 8; y++) {
for (let x = 0; x < 8; x++) {
galleryCardEditorGridButtons[y][x].dataset.state = card.grid[y][x].toString();
galleryCardEditorName.value = card.line2 == null ? card.name : `${card.line1}\n${card.line2}`;
for (let y = 0; y < 8; y++) {
for (let x = 0; x < 8; x++) {
galleryCardEditorGridButtons[y][x].dataset.state = card.grid[y][x].toString();
}
}
updateCustomCardSize();
}
updateCustomCardSize();
galleryCardDialog.showModal();
}
@ -176,7 +178,7 @@ function updateBitsToComplete() {
if (!cardDatabase.cards) throw new Error('Card database not loaded');
let bitsRequired = 0;
for (const card of cardDatabase.cards) {
if (card.number in ownedCards) continue;
if (card.isUpcoming || card.number in ownedCards) continue;
switch (card.rarity) {
case Rarity.Fresh: bitsRequired += 40; break;
case Rarity.Rare: bitsRequired += 15; break;

View File

@ -63,7 +63,9 @@ function setLoadingMessage(message: string | null) {
function preGameInitStageDatabase(stages: Stage[]) {
for (let i = 0; i < stages.length; i++) {
const stage = stages[i];
const status = userConfig.lastCustomRoomConfig ? userConfig.lastCustomRoomConfig.stageSwitch[i] : 0;
const status = userConfig.lastCustomRoomConfig && userConfig.lastCustomRoomConfig.stageSwitch.length > i
? userConfig.lastCustomRoomConfig.stageSwitch[i]
: (stages[i].name.startsWith('Upcoming') ? 2 : 0);
const button = document.createElement('button');

View File

@ -23,17 +23,36 @@ class StageButton extends CheckButton {
for (var x = 0; x < stage.grid.length; x++) {
let col = [ ];
for (var y = 0; y < stage.grid[x].length; y++) {
if (stage.grid[x][y] == Space.Empty) {
if (stage.grid[x][y] == Space.OutOfBounds)
col.push(null);
else {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.classList.add('empty');
rect.classList.add(Space[stage.grid[x][y]].toString());
rect.setAttribute('x', (100 * x).toString());
rect.setAttribute('y', (100 * y + offset).toString());
rect.setAttribute('width', '100');
rect.setAttribute('height', '100');
gridSvg.appendChild(rect);
col.push(rect);
} else
col.push(null);
if (stage.grid[x][y] & Space.SpecialInactive1) {
const image = document.createElementNS('http://www.w3.org/2000/svg', 'image');
image.setAttribute('href', 'assets/SpecialOverlay.png');
image.setAttribute('x', rect.getAttribute('x')!);
image.setAttribute('y', rect.getAttribute('y')!);
image.setAttribute('width', rect.getAttribute('width')!);
image.setAttribute('height', rect.getAttribute('height')!);
gridSvg.appendChild(image);
} else if (stage.grid[x][y] & Space.Ink1) {
const image = document.createElementNS('http://www.w3.org/2000/svg', 'image');
image.setAttribute('href', 'assets/InkOverlay.png');
image.setAttribute('x', rect.getAttribute('x')!);
image.setAttribute('y', rect.getAttribute('y')!);
image.setAttribute('width', rect.getAttribute('width')!);
image.setAttribute('height', rect.getAttribute('height')!);
gridSvg.appendChild(image);
}
}
}
cols.push(col);
}
@ -50,7 +69,7 @@ class StageButton extends CheckButton {
setStartSpaces(numPlayers: number) {
for (const el of this.startCells) {
el[0].setAttribute('class', 'empty');
el[0].setAttribute('class', 'Empty');
el[1].parentElement!.removeChild(el[1]);
}
this.startCells.splice(0);
@ -59,7 +78,7 @@ class StageButton extends CheckButton {
for (let i = 0; i < numPlayers; i++) {
const space = startSpaces[i];
const cell = this.cells[space.x][space.y]!;
cell.classList.add(`start${i + 1}`);
cell.setAttribute('class', `SpecialInactive${i + 1}`);
const image = document.createElementNS('http://www.w3.org/2000/svg', 'image');
image.setAttribute('href', 'assets/SpecialOverlay.png');

View File

@ -389,10 +389,14 @@ dialog::backdrop {
box-sizing: border-box;
}
.stageGrid rect.start1 { fill: var(--special-colour-1); }
.stageGrid rect.start2 { fill: var(--special-colour-2); }
.stageGrid rect.start3 { fill: var(--special-colour-3); }
.stageGrid rect.start4 { fill: var(--special-colour-4); }
.stageGrid rect.Ink1 { fill: var(--primary-colour-1); }
.stageGrid rect.Ink2 { fill: var(--primary-colour-2); }
.stageGrid rect.Ink3 { fill: var(--primary-colour-3); }
.stageGrid rect.Ink4 { fill: var(--primary-colour-4); }
.stageGrid rect.SpecialInactive1 { fill: var(--special-colour-1); }
.stageGrid rect.SpecialInactive2 { fill: var(--special-colour-2); }
.stageGrid rect.SpecialInactive3 { fill: var(--special-colour-3); }
.stageGrid rect.SpecialInactive4 { fill: var(--special-colour-4); }
:is(.stage, .stageRandom):is(:hover, :focus-within):not(.checked, .disabled)::before {
content: '';
@ -632,15 +636,16 @@ svg.card text.cardDisplayName {
transform: scaleX(var(--scale));
}
rect.empty {
rect.Empty, rect.empty {
fill: #00000080;
stroke: #60606080;
stroke-width: 6;
}
.stageGrid rect.empty {
.stageGrid rect.Empty {
stroke: grey;
stroke-width: 12;
}
rect.Wall { fill: grey; }
rect.ink {
fill: var(--player-primary-colour);
@ -1956,7 +1961,7 @@ button.dragging {
#galleryCardEditorImageFile { display: none; }
#galleryCardEditorImageToolbar2 input {
width: 3em;
width: 3em;
}
#galleryCardEditorColourPresetBox {

View File

@ -2326,14 +2326,215 @@ public static class CardDatabase {
{ 0, I, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-24, "Order Dualies", Rarity.Fresh, 2, "UpcomingOrderDualies", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, S, 0, 0, 0, 0 },
{ 0, 0, I, 0, I, 0, 0, 0 },
{ 0, 0, I, I, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-25, "Marina", Rarity.Fresh, "UpcomingMarina", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, I, 0, I, 0, 0 },
{ 0, I, I, I, I, 0, 0, 0 },
{ 0, I, 0, 0, I, I, 0, 0 },
{ 0, I, I, I, I, 0, 0, 0 },
{ 0, 0, I, I, 0, I, 0, 0 },
{ 0, S, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(242, 159, 104), InkColour2 = new(27, 27, 186) },
new(-26, "Pearl", Rarity.Fresh, "UpcomingPearl", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, I, 0, I, 0, 0, I, 0 },
{ 0, 0, I, I, I, I, 0, 0 },
{ 0, I, I, 0, 0, I, I, 0 },
{ 0, 0, I, I, I, I, 0, 0 },
{ 0, 0, 0, I, 0, 0, S, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(232, 232, 232), InkColour2 = new(248, 177, 213) },
new(-27, "Pearl Drone", Rarity.Fresh, 2, "UpcomingPearlDrone", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, I, 0, 0 },
{ 0, 0, 0, S, I, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(248, 177, 213), InkColour2 = new(232, 232, 232) },
new(-28, "Acht", Rarity.Rare, "UpcomingAcht", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, I, 0, I, 0, 0 },
{ 0, I, 0, I, I, 0, 0, 0 },
{ 0, I, I, 0, I, S, 0, 0 },
{ 0, I, 0, I, I, 0, 0, 0 },
{ 0, 0, I, I, 0, I, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(237, 61, 65), InkColour2 = new(80, 80, 239) },
new(-29, "Cipher", Rarity.Rare, "UpcomingCipher", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, I, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, I, I, I, I, 0, 0 },
{ 0, 0, I, 0, S, I, I, 0 },
{ 0, I, 0, 0, I, I, 0, 0 },
{ 0, 0, 0, 0, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(221, 183, 172), InkColour2 = new(182, 187, 219) },
new(-30, "Flow", Rarity.Rare, "UpcomingFlow", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, I, 0, I, 0, I, 0, 0 },
{ 0, 0, S, I, I, 0, 0, 0 },
{ 0, 0, I, I, I, 0, 0, 0 },
{ 0, I, 0, I, 0, I, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(r: 159, 104, 242), InkColour2 = new(240, 111, 96) },
new(-31, "Jelfonzo", Rarity.Rare, "UpcomingJelfonzo", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, I, 0, 0, 0 },
{ 0, 0, I, I, 0, I, 0, 0 },
{ 0, I, I, I, I, 0, 0, 0 },
{ 0, 0, I, S, 0, I, 0, 0 },
{ 0, 0, 0, 0, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(149, 119, 220), InkColour2 = new(106, 178, 215) },
new(-32, "Bisk", Rarity.Rare, "UpcomingBisk", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, I, I, I, I, 0, 0, 0 },
{ 0, 0, I, S, 0, I, 0, 0 },
{ 0, 0, I, 0, I, 0, I, 0 },
{ 0, 0, 0, I, 0, I, 0, 0 },
{ 0, 0, 0, 0, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}) { InkColour1 = new(228, 94, 69), InkColour2 = new(240, 225, 96) },
new(-33, "Douser\nDualies FF", Rarity.Common, "UpcomingDouserDualiesFF", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, S, 0, 0, 0 },
{ 0, 0, I, I, I, 0, 0, 0 },
{ 0, 0, I, 0, I, 0, 0, 0 },
{ 0, 0, I, I, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-34, "Recycled Brella\n24 Mk I", Rarity.Common, "UpcomingRecycledBrellaMkI", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, I, 0, 0 },
{ 0, 0, I, 0, I, 0, 0, 0 },
{ 0, 0, S, I, 0, 0, 0, 0 },
{ 0, 0, I, I, I, I, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-35, ".52 Gal Deco", Rarity.Common, "Upcoming52GalDeco", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, S, 0, 0, 0, 0, 0 },
{ 0, 0, I, I, 0, 0, 0, 0 },
{ 0, 0, I, I, 0, 0, 0, 0 },
{ 0, 0, I, 0, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-36, "Foil\nFlingza Roller", Rarity.Common, "UpcomingFoilFlingzaRoller", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, I, I, I, 0, 0, 0 },
{ 0, 0, S, I, I, I, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, I, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-37, "New Squiffer", Rarity.Common, "UpcomingNewSquiffer", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, S, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-38, "Custom E-Liter 4K", Rarity.Common, "UpcomingCustomELiter4K", new Space[,] {
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, S, 0, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-39, "Custom E-Liter\n4K Scope", Rarity.Common, "UpcomingCustomELiter4KScope", new Space[,] {
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, S, I, 0, 0, 0, 0 },
{ 0, 0, I, I, 0, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-40, "Custom Explosher", Rarity.Common, "UpcomingCustomExplosher", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, S, 0, 0, 0 },
{ 0, 0, I, I, I, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, 0, I, I, 0, 0, 0 },
{ 0, 0, I, I, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-41, "Dread Wringer D", Rarity.Common, "UpcomingDreadWringerD", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, S, I, 0, 0 },
{ 0, 0, I, I, I, I, 0, 0 },
{ 0, 0, I, I, I, I, 0, 0 },
{ 0, 0, 0, I, 0, I, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-42, "Nautilus 79", Rarity.Common, "UpcomingNautilus79", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, S, 0, 0, 0 },
{ 0, 0, 0, 0, I, 0, 0, 0 },
{ 0, 0, 0, 0, I, 0, 0, 0 },
{ 0, 0, I, I, I, 0, 0, 0 },
{ 0, 0, I, I, I, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
new(-43, "Glooga Dualies\nDeco", Rarity.Common, "UpcomingGloogaDualiesDeco", new Space[,] {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, S, 0, 0, 0, 0 },
{ 0, 0, I, I, I, I, 0, 0 },
{ 0, 0, 0, I, I, I, 0, 0 },
{ 0, 0, 0, I, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
}),
];
private static readonly Dictionary<int, Card> byAltNumber;
public static int LastOfficialCardNumber { get; }
public static Version Version { get; } = new(6, 1, 0, 0);
public static DateTime LastModified { get; } = new(2024, 2, 9, 6, 0, 0, DateTimeKind.Utc);
public static Version Version { get; } = new(7, 0, 0, 0);
public static DateTime LastModified { get; } = new(2024, 2, 21, 1, 0, 0, DateTimeKind.Utc);
public static string JSON { get; }
public static ReadOnlyCollection<Card> Cards { get; }

View File

@ -3,7 +3,12 @@
namespace TableturfBattleServer;
internal class StageDatabase {
private const Space E = Space.Empty;
private const Space W = Space.Wall;
private const Space o = Space.OutOfBounds;
private const Space a = Space.Ink1;
private const Space b = Space.Ink2;
private const Space A = Space.SpecialInactive1;
private const Space B = Space.SpecialInactive2;
private static readonly Stage[] stages = [
new("Main Street", new Space[9, 26], [
@ -116,10 +121,137 @@ internal class StageDatabase {
[new(3, 21), new(13, 3), new(8, 16), new(8, 8)]
]),
new("Box Seats", new Space[10, 10], [[new(2, 7), new(7, 2), new(7, 7), new(2, 2)]]),
new("Upcoming: Bases", new Space[,] {
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
{ E, E, E, E, E, E, o, o, o, o, o, o, E, E, E, E, E, E },
}, [
[new(8, 17), new(8, 0), new(8, 9)],
[new(2, 17), new(14, 0), new(14, 17), new(2, 0)]
]),
new("Upcoming: Walls", new Space[,] {
{ o, o, o, E, E, E, E, E, E, E, E, E, E, E, o, o, o },
{ o, o, o, E, E, E, E, E, E, E, E, E, E, E, o, o, o },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, W, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, W, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, W, E, E, E, E, E, E, E, E },
{ E, E, E, E, W, E, E, E, E, E, E, E, W, E, E, E, E },
{ E, E, E, E, W, E, E, E, E, E, E, E, W, E, E, E, E },
{ E, E, E, E, W, E, E, E, E, E, E, E, W, E, E, E, E },
{ E, E, E, E, W, E, E, E, E, E, E, E, W, E, E, E, E },
{ E, E, E, E, W, E, E, E, E, E, E, E, W, E, E, E, E },
{ E, E, E, E, E, E, E, E, W, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, W, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, W, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ o, o, o, E, E, E, E, E, E, E, E, E, E, E, o, o, o },
{ o, o, o, E, E, E, E, E, E, E, E, E, E, E, o, o, o },
}, [
[new(8, 15), new(8, 1), new(8, 8)],
[new(3, 15), new(13, 1), new(13, 15), new(3, 1)]
]),
new("Upcoming: Pillars", new Space[,] {
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, B, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, A, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, B, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, A, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, W, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
}, [
[new(3, 20), new(3, 4)]
]),
new("Upcoming: River", new Space[,] {
{ o, o, o, o, o, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ o, o, o, o, o, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, o, o, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, o, o, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, o, o, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, o, o, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, o, o, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, o, o, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, o, o, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, o, o, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, o, o, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, o, o, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, o, o, o, o, o },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, o, o, o, o, o },
}, [
[new(2, 17), new(11, 2), new(7, 11)],
[new(9, 17), new(4, 2), new(11, 10), new(2, 9)]
]),
new("Upcoming: Dual Streets", new Space[,] {
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, B, E, E, E, E, E, E, E, E, E, E, E, A, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o },
{ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, B, E, E, E, E, E, E, E, E, E, E, E, A, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
}, [
[new(3, 14), new(3, 2)]
]),
new("Upcoming: Super", new Space[,] {
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, B, B, B, E, E, E, E, E, E, E, E, E, E, E, E, A, A, A, E, E, E },
{ E, E, E, B, B, B, E, E, E, E, E, E, E, E, E, E, E, E, A, A, A, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E },
}, [
[new(4, 19), new(4, 3)]
]),
new("Upcoming: Back-to-Back", new Space[,] {
{ E, E, E, E, E, E, E, E, E, E, b, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, A, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, A, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, B, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, B, a, E, E, E, E, E, E, E, E, E, E },
{ E, E, E, E, E, E, E, E, E, E, b, a, E, E, E, E, E, E, E, E, E, E },
}, [
[new(1, 11), new(8, 10)]
]),
];
public static Version Version { get; } = new(1, 2, 0, 1);
public static DateTime LastModified { get; } = new(2023, 4, 12, 23, 0, 0, DateTimeKind.Utc);
public static Version Version { get; } = new(2, 0, 0, 0);
public static DateTime LastModified { get; } = new(2024, 2, 21, 1, 0, 0, DateTimeKind.Utc);
public static string JSON { get; }
public static ReadOnlyCollection<Stage> Stages { get; }