Store unlocked hats

This commit is contained in:
Idrees Hassan
2026-01-21 22:52:53 -05:00
parent 130fae6e0c
commit 7b1df9bc4f
8 changed files with 254 additions and 114 deletions

View File

@@ -1589,6 +1589,7 @@
* @typedef {Object} BirbSaveData
* @property {string[]} unlockedSpecies
* @property {string} currentSpecies
* @property {string[]} unlockedHats
* @property {string} currentHat
* @property {Partial<Settings>} settings
* @property {SavedStickyNote[]} [stickyNotes]
@@ -1661,14 +1662,14 @@
bottom: 0;
transform: scale(calc(var(--birb-scale) * 1.5)) !important;
transform-origin: bottom;
transition-duration: 0.2s;
transition-duration: 0.15s;
z-index: 2147483630 !important;
cursor: pointer;
}
.birb-item:hover {
transform: scale(calc(var(--birb-scale) * 2)) !important;
transition-duration: 0.2s;
transform: scale(calc(var(--birb-scale) * 1.9)) !important;
transition-duration: 0.15s;
}
.birb-window {
@@ -2107,6 +2108,9 @@
for (let type in SPECIES) {
unlockBird(type);
}
for (let hat in HAT) {
unlockHat(HAT[hat]);
}
}),
new DebugMenuItem("Add Feather", () => {
activateFeather();
@@ -2175,6 +2179,7 @@
let petStack = [];
let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD];
let unlockedHats = [DEFAULT_HAT];
let currentHat = DEFAULT_HAT;
// let visible = true;
let lastPetTimestamp = 0;
@@ -2194,6 +2199,7 @@
userSettings = saveData.settings ?? {};
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
unlockedHats = saveData.unlockedHats ?? [DEFAULT_HAT];
currentHat = saveData.currentHat ?? DEFAULT_HAT;
stickyNotes = [];
@@ -2215,6 +2221,7 @@
const saveData = {
unlockedSpecies: unlockedSpecies,
currentSpecies: currentSpecies,
unlockedHats: unlockedHats,
currentHat: currentHat,
settings: userSettings
};
@@ -2517,9 +2524,13 @@
if (document.querySelector("#" + HAT_ID)) {
return;
}
// Select a random hat
const hats = Object.values(HAT);
const hatId = hats[Math.floor(Math.random() * (hats.length - 1)) + 1];
// Select a random hat that hasn't been unlocked yet
const availableHats = Object.values(HAT)
.filter(hat => hat !== HAT.NONE && !unlockedHats.includes(hat));
if (availableHats.length === 0) {
return;
}
const hatId = availableHats[Math.floor(Math.random() * availableHats.length)];
// Find a random valid element to place the hat on
const element = getRandomValidElement();
@@ -2538,15 +2549,8 @@
return;
}
onClick(hatCanvas, () => {
switchHat(hatId);
unlockHat(hatId);
hatCanvas.remove();
const message = makeElement("birb-message-content");
message.appendChild(document.createTextNode("You've unlocked the "));
const bold = document.createElement("b");
bold.textContent = HAT_METADATA[hatId].name;
message.appendChild(bold);
message.appendChild(document.createTextNode("! To see all of your unlocked accessories, click the Wardrobe from the menu."));
insertModal("New Hat Found!", message);
});
// Create hat animation
@@ -2568,6 +2572,7 @@
function unlockBird(birdType) {
if (!unlockedSpecies.includes(birdType)) {
unlockedSpecies.push(birdType);
save();
const message = makeElement("birb-message-content");
message.appendChild(document.createTextNode("You've found a "));
const bold = document.createElement("b");
@@ -2576,7 +2581,24 @@
message.appendChild(document.createTextNode(" feather! Use the Field Guide to switch your bird's species."));
insertModal("New Bird Unlocked!", message);
}
save();
}
/**
* @param {string} hatId
*/
function unlockHat(hatId) {
if (!unlockedHats.includes(hatId)) {
unlockedHats.push(hatId);
save();
switchHat(hatId);
const message = makeElement("birb-message-content");
message.appendChild(document.createTextNode("You've unlocked the "));
const bold = document.createElement("b");
bold.textContent = HAT_METADATA[hatId].name;
message.appendChild(bold);
message.appendChild(document.createTextNode("! To see all of your unlocked accessories, click the Wardrobe from the menu."));
insertModal("New Hat Found!", message);
}
}
function updateFeather() {
@@ -2746,6 +2768,7 @@
const generateDescription = (/** @type {string} */ hat) => {
const metadata = HAT_METADATA[hat] ?? { name: "Unknown Hat", description: "todo" };
const unlocked = unlockedHats.includes(hat);
const boldName = document.createElement("b");
boldName.textContent = metadata.name;
@@ -2753,7 +2776,7 @@
const spacer = document.createElement("div");
spacer.style.height = "0.3em";
const descText = document.createTextNode(metadata.description);
const descText = document.createTextNode(!unlocked ? "Not yet unlocked" : metadata.description);
const fragment = document.createDocumentFragment();
fragment.appendChild(boldName);
@@ -2765,6 +2788,7 @@
description.appendChild(generateDescription(currentHat));
for (const hat of Object.values(HAT)) {
const unlocked = unlockedHats.includes(hat);
const hatElement = makeElement("birb-grid-item");
if (hat === currentHat) {
hatElement.classList.add("birb-grid-item-selected");
@@ -2776,7 +2800,6 @@
if (!hatCtx) {
return;
}
console.log(hat);
birb.getFrames().base.draw(
hatCtx,
Directions.RIGHT,
@@ -2786,7 +2809,7 @@
);
hatElement.appendChild(hatCanvas);
content.appendChild(hatElement);
{
if (unlocked) {
onClick(hatElement, () => {
switchHat(hat);
document.querySelectorAll(".birb-grid-item").forEach((element) => {
@@ -2794,6 +2817,8 @@
});
hatElement.classList.add("birb-grid-item-selected");
});
} else {
hatElement.classList.add("birb-grid-item-locked");
}
hatElement.addEventListener("mouseover", () => {
description.textContent = "";
@@ -2828,7 +2853,6 @@
* @param {string} hat
*/
function switchHat(hat) {
log("Switching hat to: " + hat);
currentHat = hat;
save();
}

62
dist/web/birb.js vendored
View File

@@ -1589,6 +1589,7 @@
* @typedef {Object} BirbSaveData
* @property {string[]} unlockedSpecies
* @property {string} currentSpecies
* @property {string[]} unlockedHats
* @property {string} currentHat
* @property {Partial<Settings>} settings
* @property {SavedStickyNote[]} [stickyNotes]
@@ -1661,14 +1662,14 @@
bottom: 0;
transform: scale(calc(var(--birb-scale) * 1.5)) !important;
transform-origin: bottom;
transition-duration: 0.2s;
transition-duration: 0.15s;
z-index: 2147483630 !important;
cursor: pointer;
}
.birb-item:hover {
transform: scale(calc(var(--birb-scale) * 2)) !important;
transition-duration: 0.2s;
transform: scale(calc(var(--birb-scale) * 1.9)) !important;
transition-duration: 0.15s;
}
.birb-window {
@@ -2107,6 +2108,9 @@
for (let type in SPECIES) {
unlockBird(type);
}
for (let hat in HAT) {
unlockHat(HAT[hat]);
}
}),
new DebugMenuItem("Add Feather", () => {
activateFeather();
@@ -2175,6 +2179,7 @@
let petStack = [];
let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD];
let unlockedHats = [DEFAULT_HAT];
let currentHat = DEFAULT_HAT;
// let visible = true;
let lastPetTimestamp = 0;
@@ -2194,6 +2199,7 @@
userSettings = saveData.settings ?? {};
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
unlockedHats = saveData.unlockedHats ?? [DEFAULT_HAT];
currentHat = saveData.currentHat ?? DEFAULT_HAT;
stickyNotes = [];
@@ -2215,6 +2221,7 @@
const saveData = {
unlockedSpecies: unlockedSpecies,
currentSpecies: currentSpecies,
unlockedHats: unlockedHats,
currentHat: currentHat,
settings: userSettings
};
@@ -2517,9 +2524,13 @@
if (document.querySelector("#" + HAT_ID)) {
return;
}
// Select a random hat
const hats = Object.values(HAT);
const hatId = hats[Math.floor(Math.random() * (hats.length - 1)) + 1];
// Select a random hat that hasn't been unlocked yet
const availableHats = Object.values(HAT)
.filter(hat => hat !== HAT.NONE && !unlockedHats.includes(hat));
if (availableHats.length === 0) {
return;
}
const hatId = availableHats[Math.floor(Math.random() * availableHats.length)];
// Find a random valid element to place the hat on
const element = getRandomValidElement();
@@ -2538,15 +2549,8 @@
return;
}
onClick(hatCanvas, () => {
switchHat(hatId);
unlockHat(hatId);
hatCanvas.remove();
const message = makeElement("birb-message-content");
message.appendChild(document.createTextNode("You've unlocked the "));
const bold = document.createElement("b");
bold.textContent = HAT_METADATA[hatId].name;
message.appendChild(bold);
message.appendChild(document.createTextNode("! To see all of your unlocked accessories, click the Wardrobe from the menu."));
insertModal("New Hat Found!", message);
});
// Create hat animation
@@ -2568,6 +2572,7 @@
function unlockBird(birdType) {
if (!unlockedSpecies.includes(birdType)) {
unlockedSpecies.push(birdType);
save();
const message = makeElement("birb-message-content");
message.appendChild(document.createTextNode("You've found a "));
const bold = document.createElement("b");
@@ -2576,7 +2581,24 @@
message.appendChild(document.createTextNode(" feather! Use the Field Guide to switch your bird's species."));
insertModal("New Bird Unlocked!", message);
}
save();
}
/**
* @param {string} hatId
*/
function unlockHat(hatId) {
if (!unlockedHats.includes(hatId)) {
unlockedHats.push(hatId);
save();
switchHat(hatId);
const message = makeElement("birb-message-content");
message.appendChild(document.createTextNode("You've unlocked the "));
const bold = document.createElement("b");
bold.textContent = HAT_METADATA[hatId].name;
message.appendChild(bold);
message.appendChild(document.createTextNode("! To see all of your unlocked accessories, click the Wardrobe from the menu."));
insertModal("New Hat Found!", message);
}
}
function updateFeather() {
@@ -2746,6 +2768,7 @@
const generateDescription = (/** @type {string} */ hat) => {
const metadata = HAT_METADATA[hat] ?? { name: "Unknown Hat", description: "todo" };
const unlocked = unlockedHats.includes(hat);
const boldName = document.createElement("b");
boldName.textContent = metadata.name;
@@ -2753,7 +2776,7 @@
const spacer = document.createElement("div");
spacer.style.height = "0.3em";
const descText = document.createTextNode(metadata.description);
const descText = document.createTextNode(!unlocked ? "Not yet unlocked" : metadata.description);
const fragment = document.createDocumentFragment();
fragment.appendChild(boldName);
@@ -2765,6 +2788,7 @@
description.appendChild(generateDescription(currentHat));
for (const hat of Object.values(HAT)) {
const unlocked = unlockedHats.includes(hat);
const hatElement = makeElement("birb-grid-item");
if (hat === currentHat) {
hatElement.classList.add("birb-grid-item-selected");
@@ -2776,7 +2800,6 @@
if (!hatCtx) {
return;
}
console.log(hat);
birb.getFrames().base.draw(
hatCtx,
Directions.RIGHT,
@@ -2786,7 +2809,7 @@
);
hatElement.appendChild(hatCanvas);
content.appendChild(hatElement);
{
if (unlocked) {
onClick(hatElement, () => {
switchHat(hat);
document.querySelectorAll(".birb-grid-item").forEach((element) => {
@@ -2794,6 +2817,8 @@
});
hatElement.classList.add("birb-grid-item-selected");
});
} else {
hatElement.classList.add("birb-grid-item-locked");
}
hatElement.addEventListener("mouseover", () => {
description.textContent = "";
@@ -2828,7 +2853,6 @@
* @param {string} hat
*/
function switchHat(hat) {
log("Switching hat to: " + hat);
currentHat = hat;
save();
}