diff --git a/dist/extension.zip b/dist/extension.zip index 8d055b9..72e789a 100644 Binary files a/dist/extension.zip and b/dist/extension.zip differ diff --git a/dist/extension/birb.js b/dist/extension/birb.js index 8bc1d11..c3b7a66 100644 --- a/dist/extension/birb.js +++ b/dist/extension/birb.js @@ -1604,6 +1604,7 @@ * @typedef {Object} BirbSaveData * @property {string[]} unlockedSpecies * @property {string} currentSpecies + * @property {string[]} unlockedHats * @property {string} currentHat * @property {Partial} settings * @property {SavedStickyNote[]} [stickyNotes] @@ -1676,14 +1677,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 { @@ -2122,6 +2123,9 @@ for (let type in SPECIES) { unlockBird(type); } + for (let hat in HAT) { + unlockHat(HAT[hat]); + } }), new DebugMenuItem("Add Feather", () => { activateFeather(); @@ -2190,6 +2194,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; @@ -2209,6 +2214,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 = []; @@ -2230,6 +2236,7 @@ const saveData = { unlockedSpecies: unlockedSpecies, currentSpecies: currentSpecies, + unlockedHats: unlockedHats, currentHat: currentHat, settings: userSettings }; @@ -2532,9 +2539,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(); @@ -2553,15 +2564,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 @@ -2583,6 +2587,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"); @@ -2591,7 +2596,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() { @@ -2761,6 +2783,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; @@ -2768,7 +2791,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); @@ -2780,6 +2803,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"); @@ -2791,7 +2815,6 @@ if (!hatCtx) { return; } - console.log(hat); birb.getFrames().base.draw( hatCtx, Directions.RIGHT, @@ -2801,7 +2824,7 @@ ); hatElement.appendChild(hatCanvas); content.appendChild(hatElement); - { + if (unlocked) { onClick(hatElement, () => { switchHat(hat); document.querySelectorAll(".birb-grid-item").forEach((element) => { @@ -2809,6 +2832,8 @@ }); hatElement.classList.add("birb-grid-item-selected"); }); + } else { + hatElement.classList.add("birb-grid-item-locked"); } hatElement.addEventListener("mouseover", () => { description.textContent = ""; @@ -2843,7 +2868,6 @@ * @param {string} hat */ function switchHat(hat) { - log("Switching hat to: " + hat); currentHat = hat; save(); } diff --git a/dist/obsidian/main.js b/dist/obsidian/main.js index 536995d..716ca26 100644 --- a/dist/obsidian/main.js +++ b/dist/obsidian/main.js @@ -1647,6 +1647,7 @@ module.exports = class PocketBird extends Plugin { * @typedef {Object} BirbSaveData * @property {string[]} unlockedSpecies * @property {string} currentSpecies + * @property {string[]} unlockedHats * @property {string} currentHat * @property {Partial} settings * @property {SavedStickyNote[]} [stickyNotes] @@ -1719,14 +1720,14 @@ module.exports = class PocketBird extends Plugin { 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 { @@ -2165,6 +2166,9 @@ module.exports = class PocketBird extends Plugin { for (let type in SPECIES) { unlockBird(type); } + for (let hat in HAT) { + unlockHat(HAT[hat]); + } }), new DebugMenuItem("Add Feather", () => { activateFeather(); @@ -2233,6 +2237,7 @@ module.exports = class PocketBird extends Plugin { let petStack = []; let currentSpecies = DEFAULT_BIRD; let unlockedSpecies = [DEFAULT_BIRD]; + let unlockedHats = [DEFAULT_HAT]; let currentHat = DEFAULT_HAT; // let visible = true; let lastPetTimestamp = 0; @@ -2252,6 +2257,7 @@ module.exports = class PocketBird extends Plugin { userSettings = saveData.settings ?? {}; unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD]; currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD; + unlockedHats = saveData.unlockedHats ?? [DEFAULT_HAT]; currentHat = saveData.currentHat ?? DEFAULT_HAT; stickyNotes = []; @@ -2273,6 +2279,7 @@ module.exports = class PocketBird extends Plugin { const saveData = { unlockedSpecies: unlockedSpecies, currentSpecies: currentSpecies, + unlockedHats: unlockedHats, currentHat: currentHat, settings: userSettings }; @@ -2575,9 +2582,13 @@ module.exports = class PocketBird extends Plugin { 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(); @@ -2596,15 +2607,8 @@ module.exports = class PocketBird extends Plugin { 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 @@ -2626,6 +2630,7 @@ module.exports = class PocketBird extends Plugin { 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"); @@ -2634,7 +2639,24 @@ module.exports = class PocketBird extends Plugin { 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() { @@ -2804,6 +2826,7 @@ module.exports = class PocketBird extends Plugin { 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; @@ -2811,7 +2834,7 @@ module.exports = class PocketBird extends Plugin { 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); @@ -2823,6 +2846,7 @@ module.exports = class PocketBird extends Plugin { 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"); @@ -2834,7 +2858,6 @@ module.exports = class PocketBird extends Plugin { if (!hatCtx) { return; } - console.log(hat); birb.getFrames().base.draw( hatCtx, Directions.RIGHT, @@ -2844,7 +2867,7 @@ module.exports = class PocketBird extends Plugin { ); hatElement.appendChild(hatCanvas); content.appendChild(hatElement); - { + if (unlocked) { onClick(hatElement, () => { switchHat(hat); document.querySelectorAll(".birb-grid-item").forEach((element) => { @@ -2852,6 +2875,8 @@ module.exports = class PocketBird extends Plugin { }); hatElement.classList.add("birb-grid-item-selected"); }); + } else { + hatElement.classList.add("birb-grid-item-locked"); } hatElement.addEventListener("mouseover", () => { description.textContent = ""; @@ -2886,7 +2911,6 @@ module.exports = class PocketBird extends Plugin { * @param {string} hat */ function switchHat(hat) { - log("Switching hat to: " + hat); currentHat = hat; save(); } diff --git a/dist/userscript/birb.user.js b/dist/userscript/birb.user.js index 21b9da3..83a501f 100644 --- a/dist/userscript/birb.user.js +++ b/dist/userscript/birb.user.js @@ -1609,6 +1609,7 @@ * @typedef {Object} BirbSaveData * @property {string[]} unlockedSpecies * @property {string} currentSpecies + * @property {string[]} unlockedHats * @property {string} currentHat * @property {Partial} settings * @property {SavedStickyNote[]} [stickyNotes] @@ -1681,14 +1682,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 { @@ -2127,6 +2128,9 @@ for (let type in SPECIES) { unlockBird(type); } + for (let hat in HAT) { + unlockHat(HAT[hat]); + } }), new DebugMenuItem("Add Feather", () => { activateFeather(); @@ -2195,6 +2199,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; @@ -2214,6 +2219,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 = []; @@ -2235,6 +2241,7 @@ const saveData = { unlockedSpecies: unlockedSpecies, currentSpecies: currentSpecies, + unlockedHats: unlockedHats, currentHat: currentHat, settings: userSettings }; @@ -2537,9 +2544,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(); @@ -2558,15 +2569,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 @@ -2588,6 +2592,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"); @@ -2596,7 +2601,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() { @@ -2766,6 +2788,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; @@ -2773,7 +2796,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); @@ -2785,6 +2808,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"); @@ -2796,7 +2820,6 @@ if (!hatCtx) { return; } - console.log(hat); birb.getFrames().base.draw( hatCtx, Directions.RIGHT, @@ -2806,7 +2829,7 @@ ); hatElement.appendChild(hatCanvas); content.appendChild(hatElement); - { + if (unlocked) { onClick(hatElement, () => { switchHat(hat); document.querySelectorAll(".birb-grid-item").forEach((element) => { @@ -2814,6 +2837,8 @@ }); hatElement.classList.add("birb-grid-item-selected"); }); + } else { + hatElement.classList.add("birb-grid-item-locked"); } hatElement.addEventListener("mouseover", () => { description.textContent = ""; @@ -2848,7 +2873,6 @@ * @param {string} hat */ function switchHat(hat) { - log("Switching hat to: " + hat); currentHat = hat; save(); } diff --git a/dist/web/birb.embed.js b/dist/web/birb.embed.js index 43eb0bb..9520421 100644 --- a/dist/web/birb.embed.js +++ b/dist/web/birb.embed.js @@ -1589,6 +1589,7 @@ * @typedef {Object} BirbSaveData * @property {string[]} unlockedSpecies * @property {string} currentSpecies + * @property {string[]} unlockedHats * @property {string} currentHat * @property {Partial} 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(); } diff --git a/dist/web/birb.js b/dist/web/birb.js index 43eb0bb..9520421 100644 --- a/dist/web/birb.js +++ b/dist/web/birb.js @@ -1589,6 +1589,7 @@ * @typedef {Object} BirbSaveData * @property {string[]} unlockedSpecies * @property {string} currentSpecies + * @property {string[]} unlockedHats * @property {string} currentHat * @property {Partial} 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(); } diff --git a/src/application.js b/src/application.js index 6c3273e..d136947 100644 --- a/src/application.js +++ b/src/application.js @@ -54,6 +54,7 @@ import { HAT, HAT_METADATA, createHatItemAnimation } from './hats.js'; * @typedef {Object} BirbSaveData * @property {string[]} unlockedSpecies * @property {string} currentSpecies + * @property {string[]} unlockedHats * @property {string} currentHat * @property {Partial} settings * @property {SavedStickyNote[]} [stickyNotes] @@ -174,6 +175,9 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { for (let type in SPECIES) { unlockBird(type); } + for (let hat in HAT) { + unlockHat(HAT[hat]); + } }), new DebugMenuItem("Add Feather", () => { activateFeather(); @@ -242,6 +246,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { let petStack = []; let currentSpecies = DEFAULT_BIRD; let unlockedSpecies = [DEFAULT_BIRD]; + let unlockedHats = [DEFAULT_HAT]; let currentHat = DEFAULT_HAT; // let visible = true; let lastPetTimestamp = 0; @@ -261,6 +266,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { userSettings = saveData.settings ?? {}; unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD]; currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD; + unlockedHats = saveData.unlockedHats ?? [DEFAULT_HAT]; currentHat = saveData.currentHat ?? DEFAULT_HAT; stickyNotes = []; @@ -282,6 +288,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { const saveData = { unlockedSpecies: unlockedSpecies, currentSpecies: currentSpecies, + unlockedHats: unlockedHats, currentHat: currentHat, settings: userSettings }; @@ -587,9 +594,13 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { 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(); @@ -608,15 +619,8 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { 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 @@ -638,6 +642,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { 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"); @@ -646,7 +651,24 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { 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() { @@ -817,7 +839,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { const generateDescription = (/** @type {string} */ hat) => { const metadata = HAT_METADATA[hat] ?? { name: "Unknown Hat", description: "todo" }; - const unlocked = true; + const unlocked = unlockedHats.includes(hat); const boldName = document.createElement("b"); boldName.textContent = metadata.name; @@ -837,7 +859,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { description.appendChild(generateDescription(currentHat)); for (const hat of Object.values(HAT)) { - const unlocked = true; + const unlocked = unlockedHats.includes(hat); const hatElement = makeElement("birb-grid-item"); if (hat === currentHat) { hatElement.classList.add("birb-grid-item-selected"); @@ -849,7 +871,6 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { if (!hatCtx) { return; } - console.log(hat); birb.getFrames().base.draw( hatCtx, Directions.RIGHT, @@ -903,7 +924,6 @@ function startApplication(birbPixels, featherPixels, hatsPixels) { * @param {string} hat */ function switchHat(hat) { - log("Switching hat to: " + hat); currentHat = hat; save(); } diff --git a/src/stylesheet.css b/src/stylesheet.css index 4ea5aab..8fdc58c 100644 --- a/src/stylesheet.css +++ b/src/stylesheet.css @@ -47,14 +47,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 {