From 19ffac4a90ff516c4ea7f623ef0c83b240837cb9 Mon Sep 17 00:00:00 2001 From: zyl Date: Thu, 24 Oct 2024 13:10:33 -0700 Subject: [PATCH] add very basic clicker game --- site/config.yaml | 2 +- site/pages/click.md | 10 ++ site/pages/games.md | 11 ++ site/root/js/click.js | 222 ++++++++++++++++++++++++++++++++ site/sass/click.scss | 27 ++++ site/templates/base.hbs | 2 +- site/templates/extras/click.hbs | 30 +++++ src/builder.rs | 8 +- src/extras.rs | 40 ++++-- 9 files changed, 335 insertions(+), 17 deletions(-) create mode 100644 site/pages/click.md create mode 100644 site/pages/games.md create mode 100644 site/root/js/click.js create mode 100644 site/sass/click.scss create mode 100644 site/templates/extras/click.hbs diff --git a/site/config.yaml b/site/config.yaml index 4427dce..2458b56 100644 --- a/site/config.yaml +++ b/site/config.yaml @@ -1,7 +1,7 @@ base_url: "https://zyl.gay" title: zyl is gay description: "zyl's website." -sass_styles: [index.scss, "pet.scss"] +sass_styles: [index.scss, pet.scss, click.scss] images_per_page: 10 blog_posts_per_page: 20 cdn_url: "https://i.zyl.gay" diff --git a/site/pages/click.md b/site/pages/click.md new file mode 100644 index 0000000..2bdd7e0 --- /dev/null +++ b/site/pages/click.md @@ -0,0 +1,10 @@ +--- +title: click +scripts: ["js/click.js"] +styles: ["click.css"] +embed: + title: click + site_name: zyl.gay + description: click click click +extra: click +--- diff --git a/site/pages/games.md b/site/pages/games.md new file mode 100644 index 0000000..1dd3656 --- /dev/null +++ b/site/pages/games.md @@ -0,0 +1,11 @@ +--- +title: games! +--- + +# games + +little games i've made on here :3 + +

pet game

+ +

clicker game

diff --git a/site/root/js/click.js b/site/root/js/click.js new file mode 100644 index 0000000..96175bf --- /dev/null +++ b/site/root/js/click.js @@ -0,0 +1,222 @@ +(function () { + "use strict"; + + const click = document.querySelector("#click"); + const petsCounter = click.querySelector("#pets"); + const petsPerSecondCounter = click.querySelector("#pets-per-second"); + const barksCounter = click.querySelector("#barks"); + const barksPerSecondCounter = click.querySelector("#barks-per-second"); + const kissesCounter = click.querySelector("#kisses"); + const kissesPerSecondCounter = click.querySelector("#kisses-per-second"); + const barker = click.querySelector("#barker"); + const toolsEl = click.querySelector(".tools"); + + const toolPriceFactor = 0.1; + const upgradePriceFactor = 0.2; + const upgradeProductionFactor = 1.1; + + const toolData = { + hand: { + priceIn: "barks", + basePrice: 10, + petsPerSecond: 0.5, + }, + puppy: { + priceIn: "pets", + basePrice: 5, + barksPerSecond: 0.5, + }, + foodBowl: { + priceIn: "barks", + basePrice: 50, + barksPerSecond: 1.3, + }, + kisser: { + priceIn: "pets", + basePrice: 500, + kissesPerSecond: 0.25, + }, + }; + + let barks = 0; + let pets = 0; + let kisses = 0; + let tools = {}; + + let petsPerSecond = 0; + let barksPerSecond = 0; + let kissesPerSecond = 0; + + function calcPrice(base, count) { + return Math.floor(base ** (1 + toolPriceFactor * count)); + } + + function calcUpgradePrice(base, count) { + return Math.floor((base * 2) ** (1 + upgradePriceFactor * count)); + } + + const getValue = (name) => { + if (name === "pets") { + return pets; + } else if (name === "barks") { + return barks; + } else if (name === "kisses") { + return kisses; + } else if (name === "petsPerSecond") { + return petsPerSecond; + } else if (name === "barksPerSecond") { + return barksPerSecond; + } else if (name === "kissesPerSecond") { + return kissesPerSecond; + } + }; + + const setValue = (name, value) => { + if (name === "pets") { + pets = value; + } else if (name === "barks") { + barks = value; + } else if (name === "kisses") { + kisses = value; + } else if (name === "petsPerSecond") { + petsPerSecond = value; + } else if (name === "barksPerSecond") { + barksPerSecond = value; + } else if (name === "kissesPerSecond") { + kissesPerSecond = value; + } + }; + + const updatePerSecondValues = () => { + let pets = 0; + let barks = 0; + let kisses = 0; + + for (const [id, tool] of Object.entries(tools)) { + pets += + (toolData[id].petsPerSecond || 0) * + tool.count * + tool.upgrades * + upgradeProductionFactor; + barks += + (toolData[id].barksPerSecond || 0) * + tool.count * + tool.upgrades * + upgradeProductionFactor; + kisses += + (toolData[id].kissesPerSecond || 0) * + tool.count * + tool.upgrades * + upgradeProductionFactor; + } + + petsPerSecond = pets; + barksPerSecond = barks; + kissesPerSecond = kisses; + }; + + const updateDisplay = () => { + petsCounter.innerText = pets; + petsPerSecondCounter.innerText = petsPerSecond.toFixed(2); + barksCounter.innerText = barks; + barksPerSecondCounter.innerText = barksPerSecond.toFixed(2); + kissesCounter.innerText = kisses; + kissesPerSecondCounter.innerText = kissesPerSecond.toFixed(2); + }; + + for (const el of toolsEl.querySelectorAll(".tool")) { + const id = el.getAttribute("data-tool"); + if (id) { + const data = toolData[id]; + if (data) { + const toolInfo = { + count: 0, + upgrades: 1, + }; + tools[id] = toolInfo; + + const count = el.querySelector(".count"); + const level = el.querySelector(".level"); + const buy = el.querySelector(".buy"); + const upgrade = el.querySelector(".upgrade"); + + const updateText = () => { + count.innerText = toolInfo.count; + level.innerText = toolInfo.upgrades; + const price = calcPrice(data.basePrice, toolInfo.count); + const upgradePrice = calcUpgradePrice( + data.basePrice, + toolInfo.upgrades + ); + buy.innerText = `buy - ${price} ${data.priceIn}`; + upgrade.innerText = `upgrade - ${upgradePrice} kisses`; + }; + updateText(); + + buy.addEventListener("click", () => { + const price = calcPrice(data.basePrice, toolInfo.count); + const v = getValue(data.priceIn); + if (v >= price) { + setValue(data.priceIn, v - price); + toolInfo.count += 1; + updatePerSecondValues(); + updateText(); + updateDisplay(); + } + }); + + upgrade.addEventListener("click", () => { + const price = calcUpgradePrice(data.basePrice, toolInfo.upgrades); + if (kisses >= price) { + kisses -= price; + toolInfo.upgrades += 1; + updatePerSecondValues(); + updateText(); + updateDisplay(); + } + }); + } + } + } + + barker.addEventListener("click", () => { + barks += 1; + updateDisplay(); + }); + + let lastUpdate = 0; + let petsQueued = 0; + let barksQueued = 0; + let kissesQueued = 0; + + const checkQueue = (name, queued) => { + const perSecond = getValue(`${name}PerSecond`); + if (perSecond > 0) { + const amount = 1000 / perSecond; + const toAdd = Math.floor(queued / amount); + setValue(name, getValue(name) + toAdd); + updateDisplay(); + queued -= toAdd * amount; + } else { + queued = 0; + } + return queued; + }; + + const update = (ts) => { + requestAnimationFrame(update); + + const diff = ts - lastUpdate; + petsQueued += diff; + barksQueued += diff; + kissesQueued += diff; + + petsQueued = checkQueue("pets", petsQueued); + barksQueued = checkQueue("barks", barksQueued); + kissesQueued = checkQueue("kisses", kissesQueued); + + lastUpdate = ts; + }; + + requestAnimationFrame(update); +})(); diff --git a/site/sass/click.scss b/site/sass/click.scss new file mode 100644 index 0000000..b27918c --- /dev/null +++ b/site/sass/click.scss @@ -0,0 +1,27 @@ +#click { + .resources { + display: grid; + grid-template-columns: repeat(3, 0fr); + grid-auto-flow: row; + + & > span { + margin-right: 5px; + width: max-content; + + &.resource { + font-weight: bold; + } + } + } + + #barker { + font-size: 2rem; + padding: 8px; + } + + .tools { + .name { + font-weight: bold; + } + } +} diff --git a/site/templates/base.hbs b/site/templates/base.hbs index 635ba5a..8ffd82b 100644 --- a/site/templates/base.hbs +++ b/site/templates/base.hbs @@ -23,7 +23,7 @@ it/puppy(/she) - creature | + games | my projects | blog | images | diff --git a/site/templates/extras/click.hbs b/site/templates/extras/click.hbs new file mode 100644 index 0000000..c727c7e --- /dev/null +++ b/site/templates/extras/click.hbs @@ -0,0 +1,30 @@ +
+

WARNING: no save mechanic is implemented yet!!

+

click

+ +
+ {{#*inline "resource"}} + {{name}}0 (0/s) + {{/inline}} + {{> resource id="pets" name="pets"}} + {{> resource id="barks" name="barks"}} + {{> resource id="kisses" name="kisses"}} +
+ +
+ {{#*inline "tool"}} +
+

{{name}} (0, lvl 1)

+

{{description}}

+ +
+ {{/inline}} + {{> tool id="hand" name="hand" description="don't bite the hand that pets you"}} + {{> tool id="puppy" name="puppy" description="arf arf wruff :3"}} + {{> tool id="foodBowl" name="food bowl" description="more food for more barking"}} + {{> tool id="kisser" name="kisser wow" description="someone to kiss all those poor puppies,,"}} +
+
diff --git a/src/builder.rs b/src/builder.rs index 90caf00..0fa487d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -10,9 +10,7 @@ use pulldown_cmark::{Options, Parser}; use serde::Serialize; use url::Url; -use crate::{ - extras::Extra, resource::ResourceBuilder, util, PageMetadata, Site, ROOT_PATH, SASS_PATH, -}; +use crate::{resource::ResourceBuilder, util, PageMetadata, Site, ROOT_PATH, SASS_PATH}; /// Struct containing data to be sent to templates when rendering them. #[derive(Debug, Serialize)] @@ -283,8 +281,8 @@ impl<'a> SiteBuilder<'a> { // Modify HTML output let mut out = self.rewrite_html(out)?; - if let Some(Extra::HtmlModification(f)) = extra { - out = f(out, self)?; + if let Some(extra) = extra { + out = extra.handle(out, self)?; } if !self.serving { diff --git a/src/extras.rs b/src/extras.rs index ee0cac7..92c43c2 100644 --- a/src/extras.rs +++ b/src/extras.rs @@ -5,17 +5,46 @@ use crate::{blog::BlogPostMetadata, builder::SiteBuilder, resource::ResourceTemp #[derive(Debug)] pub enum Extra { + Basic(&'static str), HtmlModification(fn(page: String, builder: &SiteBuilder) -> eyre::Result), } +impl Extra { + /// runs the handler for the extra + pub fn handle(&self, page: String, builder: &SiteBuilder) -> eyre::Result { + match self { + Self::Basic(template) => { + println!("{template}"); + let content = builder.reg.render(template, &())?; + append_to(&page, &content, "main.page") + } + Self::HtmlModification(f) => (f)(page, builder), + } + } +} + /// Gets the extra for the given value. pub fn get_extra(extra: &str) -> Option { match extra { "index" => Some(Extra::HtmlModification(index)), + "click" => Some(Extra::Basic("extras/click")), _ => None, } } +fn append_to(page: &str, content: &str, selector: &str) -> eyre::Result { + Ok(lol_html::rewrite_str( + page, + RewriteStrSettings { + element_content_handlers: vec![element!(selector, move |el| { + el.append(content, lol_html::html_content::ContentType::Html); + Ok(()) + })], + ..Default::default() + }, + )?) +} + /// Extra to add a sidebar to the index page with recent blog posts on it. fn index(page: String, builder: &SiteBuilder) -> eyre::Result { #[derive(Debug, Serialize)] @@ -42,14 +71,5 @@ fn index(page: String, builder: &SiteBuilder) -> eyre::Result { }, )?; - Ok(lol_html::rewrite_str( - &page, - RewriteStrSettings { - element_content_handlers: vec![element!("#content", move |el| { - el.append(&sidebar, lol_html::html_content::ContentType::Html); - Ok(()) - })], - ..Default::default() - }, - )?) + append_to(&page, &sidebar, "#content") }