mirror of
https://github.com/zyllian/zyllian.github.io.git
synced 2025-01-18 03:32:30 -08:00
Merge branch 'pet'
This commit is contained in:
commit
849e6e8f97
8 changed files with 708 additions and 3 deletions
3
.cargo/config.toml
Normal file
3
.cargo/config.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[target.x86_64-pc-windows-msvc]
|
||||
linker = "ld.lld.exe"
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
|
|
@ -1,7 +1,7 @@
|
|||
base_url: "https://zyl.gay"
|
||||
title: zyl is gay
|
||||
description: "zyl's website."
|
||||
sass_styles: [index.scss]
|
||||
sass_styles: [index.scss, "pet.scss"]
|
||||
images_per_page: 10
|
||||
blog_posts_per_page: 20
|
||||
cdn_url: "https://i.zyl.gay"
|
||||
|
|
71
site/pages/pet.md
Normal file
71
site/pages/pet.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
title: pet
|
||||
scripts: ["js/pet.js"]
|
||||
styles: ["pet.css"]
|
||||
---
|
||||
|
||||
<div id="pet">
|
||||
<noscript><p>javascript is required for the pet game!!</p></noscript>
|
||||
<div id="pet-display">
|
||||
<h2 class="pet-name"></h2>
|
||||
<div class="the-pet"></div>
|
||||
<div class="status">
|
||||
<p name="hungry" class="hidden"><span class="pet-name"></span> looks hungry..</p>
|
||||
<p name="starving" class="hidden"><span class="pet-name"></span> is starving!! you need to feed them!!</p>
|
||||
<p name="unhappy" class="hidden"><span class="pet-name"></span> looks at you with wide eyes..</p>
|
||||
<p name="messy-1" class="hidden"><span class="pet-name"></span> has left a bit of a mess! time to clean!</p>
|
||||
<p name="messy-2" class="hidden">there's even more mess in here.. shouldn't you clean it for <span class="pet-name"></span>?</p>
|
||||
<p name="messy-3" class="hidden">what a mess!! <span class="pet-name"></span> can't be happy.. you've gotta clean in here</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="egg">
|
||||
<p>whoa! you just found a weird egg! maybe you should watch it and see what happens..</p>
|
||||
</div>
|
||||
|
||||
<div id="adult-info" class="hidden">
|
||||
<p><span class="pet-name"></span> has grown up to be an adult!! what will they do with their life now....</p>
|
||||
<button class="advance">okay!</button>
|
||||
</div>
|
||||
|
||||
<div id="elder-info" class="hidden">
|
||||
<p>oh? <span class="pet-name"></span> has aged and is now an elder creature! they may not have much left in their life.... hopefully it's been a good life!</p>
|
||||
<button class="advance">hopefully!!</button>
|
||||
</div>
|
||||
|
||||
<div id="passed-away-info" class="hidden">
|
||||
<p>oh... <span class="pet-name"></span> has finally gone and kicked the bucket. its story comes to an end....</p>
|
||||
<button>but what's this egg lying here about..?</button>
|
||||
</div>
|
||||
|
||||
<form id="pet-setup" class="hidden">
|
||||
<p>whoa! your egg just hatched into a new creature! what should you name it?</p>
|
||||
<input type="text" name="pet-name" min-length="3" max-length="50">
|
||||
<button type="submit">name it!</button>
|
||||
</form>
|
||||
|
||||
<div id="pet-actions">
|
||||
<div name="hatched-actions" class="hidden">
|
||||
<button name="feed">feed</button>
|
||||
<button name="pet">pet</button>
|
||||
<button name="clean">clean</button>
|
||||
</div>
|
||||
<button name="pause">pause</button>
|
||||
</div>
|
||||
|
||||
<div id="debug-section" class="hidden">
|
||||
<button id="force-update">force update</button> <button id="reset">reset</button>
|
||||
<p>LS: <span name="ls"></span> A: <span name="a"></span> F: <span name="f"></span> B: <span name="b"></span> P: <span name="p"></span> MC: <span name="mc"></span> H: <span name="h"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<details>
|
||||
<summary>tips!!</summary>
|
||||
<ul>
|
||||
<li>pets need to be fed about once every eight hours!</li>
|
||||
<li>the game (currently) doesn't simulate while the page is unloaded, so make sure to keep the page loaded for your pet to exist!</li>
|
||||
<li>make sure to keep your pet clean!!</li>
|
||||
<li>if your pet is turning grey, make sure you're giving them the attention they need!! pet's deserve happiness too :(</li>
|
||||
<li>if you take good enough care of your pet they'll stop going potty on the floor!</li>
|
||||
</ul>
|
||||
</details>
|
547
site/root/js/pet.js
Normal file
547
site/root/js/pet.js
Normal file
|
@ -0,0 +1,547 @@
|
|||
(function () {
|
||||
"use strict";
|
||||
|
||||
const UPDATES_PER_MINUTE = 2;
|
||||
const UPDATES_PER_HOUR = UPDATES_PER_MINUTE * 60;
|
||||
const UPDATES_PER_DAY = UPDATES_PER_HOUR * 24;
|
||||
|
||||
/** the current pet version.. */
|
||||
const CURRENT_PET_VERSION = 1;
|
||||
/** the max food a pet will eat */
|
||||
const MAX_FOOD = 100;
|
||||
/** the amount of time it takes for a pet to have to GO */
|
||||
const POTTY_TIME = 100;
|
||||
/** how fast a pet's food value decays */
|
||||
const FOOD_DECAY = MAX_FOOD / (UPDATES_PER_HOUR * 8); // to stay on top should be fed roughly once every 8 hours?
|
||||
/** the rate at which a pet ages */
|
||||
const AGING_RATE = 1;
|
||||
/** how fast a pet's potty need decays */
|
||||
const POTTY_DECAY = FOOD_DECAY / 2; // roughly every 4 hours?
|
||||
/** how much mess can be in a pet's space at once */
|
||||
const MAX_MESS = 5;
|
||||
/** how fast a pet's happiness decays */
|
||||
const HAPPINESS_DECAY = FOOD_DECAY;
|
||||
/** a pet's maximum happiness */
|
||||
const MAX_HAPPINESS = 100;
|
||||
/** how quickly a pet's happiness will be reduced by when hungry */
|
||||
const HAPPINESS_EMPTY_STOMACH_MODIFIER = -10 / UPDATES_PER_HOUR;
|
||||
/** how quickly a pet's happiness will be reduced by when their space is messy, per piece of mess */
|
||||
const HAPPINESS_MESS_MODIFIER = -5 / UPDATES_PER_HOUR;
|
||||
|
||||
/** the amount of happiness gained when the pet is fed (excluding when the pet doesn't yet need food) */
|
||||
const FEED_HAPPINESS = 5;
|
||||
/** the amount of happiness gained when the pet is pet */
|
||||
const PET_HAPPINESS = 20;
|
||||
/** the amount of happiness gained when the pet's space is cleaned */
|
||||
const CLEAN_HAPPINESS = 1;
|
||||
|
||||
/** the minimum amount of time between feedings */
|
||||
const FEED_TIMER = 5000;
|
||||
/** the minimum amount of time between pets */
|
||||
const PET_TIMER = 2000;
|
||||
/** the minimum amount of time between cleans */
|
||||
const CLEAN_TIMER = 5000;
|
||||
|
||||
const PET_SAVE_KEY = "pet-game";
|
||||
|
||||
/** life stage for an egg */
|
||||
const LIFE_STAGE_EGG = 1;
|
||||
/** life stage for a pup */
|
||||
const LIFE_STAGE_PUP = 2;
|
||||
/** life stage for an adult */
|
||||
const LIFE_STAGE_ADULT = 3;
|
||||
/** life stage for an elder pet */
|
||||
const LIFE_STAGE_ELDER = 4;
|
||||
/** the time it takes for a pet to grow past the egg phase */
|
||||
const EGG_TIME = UPDATES_PER_MINUTE;
|
||||
/** the time it takes for a pet to grow past the pup phase */
|
||||
const PUP_TIME = UPDATES_PER_DAY * 7;
|
||||
/** the time it takes for a pet to grow past the adult phase */
|
||||
const ADULT_TIME = UPDATES_PER_DAY * 15;
|
||||
/** the time it takes for a pet to grow past the elder phase */
|
||||
const ELDER_TIME = UPDATES_PER_DAY * 7;
|
||||
|
||||
const WIDTH_PUP = 150;
|
||||
const HEIGHT_PUP = 150;
|
||||
const WIDTH_ADULT = 250;
|
||||
const HEIGHT_ADULT = 250;
|
||||
const WIDTH_ELDER = 210;
|
||||
const HEIGHT_ELDER = 210;
|
||||
|
||||
/** the different types of pets available */
|
||||
const PET_TYPES = ["circle", "square", "triangle"];
|
||||
|
||||
const petDisplay = document.querySelector("#pet-display");
|
||||
const thePet = petDisplay.querySelector(".the-pet");
|
||||
|
||||
const status = petDisplay.querySelector(".status");
|
||||
const statusHungry = status.querySelector("[name=hungry]");
|
||||
const statusStarving = status.querySelector("[name=starving]");
|
||||
const statusUnhappy = status.querySelector("[name=unhappy]");
|
||||
const statusMessy1 = status.querySelector("[name=messy-1]");
|
||||
const statusMessy2 = status.querySelector("[name=messy-2]");
|
||||
const statusMessy3 = status.querySelector("[name=messy-3]");
|
||||
|
||||
const petName = document.querySelectorAll(".pet-name");
|
||||
const eggDiv = document.querySelector("div#egg");
|
||||
const petSetup = document.querySelector("#pet-setup");
|
||||
const adultInfo = document.querySelector("div#adult-info");
|
||||
const elderInfo = document.querySelector("div#elder-info");
|
||||
const passedAwayInfo = document.querySelector("div#passed-away-info");
|
||||
const name = petSetup.querySelector("input[name=pet-name]");
|
||||
|
||||
const petActions = document.querySelector("div#pet-actions");
|
||||
const pauseButton = petActions.querySelector("button[name=pause]");
|
||||
const hatchedActions = petActions.querySelector("div[name=hatched-actions]");
|
||||
const feedButton = hatchedActions.querySelector("button[name=feed]");
|
||||
const petButton = hatchedActions.querySelector("button[name=pet]");
|
||||
const cleanButton = hatchedActions.querySelector("button[name=clean]");
|
||||
|
||||
const debug = document.querySelector("div#debug-section");
|
||||
const debugLifeStage = debug.querySelector("span[name=ls]");
|
||||
const debugAge = debug.querySelector("span[name=a]");
|
||||
const debugFood = debug.querySelector("span[name=f]");
|
||||
const debugBehavior = debug.querySelector("span[name=b]");
|
||||
const debugPotty = debug.querySelector("span[name=p]");
|
||||
const debugMessCounter = debug.querySelector("span[name=mc]");
|
||||
const debugHappiness = debug.querySelector("span[name=h]");
|
||||
const forceUpdateButton = debug.querySelector("button#force-update");
|
||||
const resetButton = debug.querySelector("button#reset");
|
||||
|
||||
let canFeed = true;
|
||||
let canPet = true;
|
||||
let canClean = true;
|
||||
|
||||
/**
|
||||
* generates a random number within the given range
|
||||
* @param {number} min the minimum number for the random generation
|
||||
* @param {number} max the maximum number for the random generation
|
||||
* @returns the generated number
|
||||
*/
|
||||
function rand(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* class containing information about a pet
|
||||
*/
|
||||
class Pet {
|
||||
/** current pet version */
|
||||
version = CURRENT_PET_VERSION;
|
||||
/** whether the pet can die or not */
|
||||
canDie = false;
|
||||
/** whether the pet is alive or dead */
|
||||
alive = true;
|
||||
/** whether the pet simulation is paused */
|
||||
paused = false;
|
||||
/** whether the pet simulation needs an interactive advancement */
|
||||
needsAdvancement = false;
|
||||
/** the pet's current life stage */
|
||||
lifeStage = LIFE_STAGE_EGG;
|
||||
/** the pet's name */
|
||||
name = "";
|
||||
/** how much food the pet has stored */
|
||||
food = MAX_FOOD;
|
||||
/** the pet's age */
|
||||
age = 0;
|
||||
/** the pet's behavior score */
|
||||
behavior = 0;
|
||||
/** how long until the pet needs to go potty */
|
||||
pottyTimer = POTTY_TIME;
|
||||
/** how much mess the pet has made */
|
||||
messCounter = 0;
|
||||
/** the pet's current happiness */
|
||||
_happiness = MAX_HAPPINESS;
|
||||
/** the time the pet was last updated */
|
||||
lastUpdate = Date.now();
|
||||
/** the time the egg was found */
|
||||
eggFound = Date.now();
|
||||
/** the time the egg hatched */
|
||||
hatched = Date.now();
|
||||
/** the pet's type */
|
||||
type = PET_TYPES[Math.floor(rand(0, PET_TYPES.length))];
|
||||
/** the pet's color */
|
||||
color = `rgb(${rand(0, 255)}, ${rand(0, 255)}, ${rand(0, 255)})`;
|
||||
/** the pet's scaled width */
|
||||
scaleWidth = rand(0.6, 1.4);
|
||||
/** the pet's scaled height */
|
||||
scaleHeight = rand(0.6, 1.4);
|
||||
|
||||
/**
|
||||
* updates a pet
|
||||
*/
|
||||
update() {
|
||||
if (!this.alive || this.paused || this.needsAdvancement) {
|
||||
return;
|
||||
}
|
||||
console.log("update");
|
||||
|
||||
this.lastUpdate = Date.now();
|
||||
this.age += AGING_RATE;
|
||||
|
||||
if (this.lifeStage !== LIFE_STAGE_EGG) {
|
||||
this.food -= FOOD_DECAY;
|
||||
this.pottyTimer -= POTTY_DECAY;
|
||||
this.happiness -= HAPPINESS_DECAY;
|
||||
|
||||
if (this.food < 0) {
|
||||
this.happiness += HAPPINESS_EMPTY_STOMACH_MODIFIER;
|
||||
this.food = 0;
|
||||
if (this.canDie) {
|
||||
// TODO: pet dies
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pottyTimer < 0) {
|
||||
this.goPotty();
|
||||
}
|
||||
for (let i = 0; i < this.messCounter; i++) {
|
||||
this.happiness += HAPPINESS_MESS_MODIFIER;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.lifeStage === LIFE_STAGE_EGG && this.age >= EGG_TIME) {
|
||||
this.needsAdvancement = true;
|
||||
this.lifeStage = LIFE_STAGE_PUP;
|
||||
this.age = 0;
|
||||
} else if (this.lifeStage === LIFE_STAGE_PUP && this.age >= PUP_TIME) {
|
||||
this.needsAdvancement = true;
|
||||
this.lifeStage = LIFE_STAGE_ADULT;
|
||||
this.age = 0;
|
||||
} else if (
|
||||
this.lifeStage === LIFE_STAGE_ADULT &&
|
||||
this.age >= ADULT_TIME
|
||||
) {
|
||||
this.needsAdvancement = true;
|
||||
this.lifeStage = LIFE_STAGE_ELDER;
|
||||
this.age = 0;
|
||||
} else if (
|
||||
this.lifeStage === LIFE_STAGE_ELDER &&
|
||||
this.age >= ELDER_TIME
|
||||
) {
|
||||
this.needsAdvancement = true;
|
||||
this.alive = false;
|
||||
// TODO: DEATH
|
||||
}
|
||||
this.updateDom();
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the html dom
|
||||
*/
|
||||
updateDom() {
|
||||
eggDiv.classList.add("hidden");
|
||||
petSetup.classList.add("hidden");
|
||||
hatchedActions.classList.remove("hidden");
|
||||
|
||||
thePet.classList.remove("egg");
|
||||
thePet.classList.remove("pup");
|
||||
thePet.classList.remove("adult");
|
||||
thePet.classList.remove("elder");
|
||||
thePet.classList.remove("dead");
|
||||
|
||||
statusHungry.classList.add("hidden");
|
||||
statusStarving.classList.add("hidden");
|
||||
statusUnhappy.classList.add("hidden");
|
||||
statusMessy1.classList.add("hidden");
|
||||
statusMessy2.classList.add("hidden");
|
||||
statusMessy3.classList.add("hidden");
|
||||
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
|
||||
if (this.lifeStage === LIFE_STAGE_EGG) {
|
||||
eggDiv.classList.remove("hidden");
|
||||
hatchedActions.classList.add("hidden");
|
||||
|
||||
thePet.classList.add("egg");
|
||||
} else if (this.lifeStage === LIFE_STAGE_PUP) {
|
||||
if (this.needsAdvancement) {
|
||||
petSetup.classList.remove("hidden");
|
||||
}
|
||||
|
||||
thePet.classList.add("pup");
|
||||
width = WIDTH_PUP;
|
||||
height = HEIGHT_PUP;
|
||||
} else if (this.lifeStage === LIFE_STAGE_ADULT) {
|
||||
if (this.needsAdvancement) {
|
||||
adultInfo.classList.remove("hidden");
|
||||
}
|
||||
|
||||
thePet.classList.add("adult");
|
||||
width = WIDTH_ADULT;
|
||||
height = HEIGHT_ADULT;
|
||||
} else if (this.lifeStage === LIFE_STAGE_ELDER) {
|
||||
if (this.needsAdvancement) {
|
||||
if (this.alive) {
|
||||
elderInfo.classList.remove("hidden");
|
||||
} else {
|
||||
passedAwayInfo.classList.remove("hidden");
|
||||
|
||||
thePet.classList.add("elder");
|
||||
width = WIDTH_ELDER;
|
||||
height = HEIGHT_ELDER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
width *= this.scaleWidth;
|
||||
height *= this.scaleHeight;
|
||||
|
||||
thePet.style.setProperty("--width", `${width}px`);
|
||||
thePet.style.setProperty("--height", `${height}px`);
|
||||
thePet.style.setProperty("--color", this.color);
|
||||
let happinessFilter = 1 - this.happiness / MAX_HAPPINESS;
|
||||
if (happinessFilter < 0.6) {
|
||||
happinessFilter = 0;
|
||||
}
|
||||
happinessFilter = (happinessFilter - 0.6) * 2.5;
|
||||
if (happinessFilter < 0) {
|
||||
happinessFilter = 0;
|
||||
}
|
||||
thePet.style.setProperty(
|
||||
"filter",
|
||||
`grayscale(${happinessFilter * 100}%)`
|
||||
);
|
||||
|
||||
if (!this.alive) {
|
||||
thePet.classList.add("dead");
|
||||
} else if (this.lifeStage !== LIFE_STAGE_EGG) {
|
||||
thePet.classList.add(this.type);
|
||||
|
||||
if (this.food <= MAX_FOOD / 10) {
|
||||
statusStarving.classList.remove("hidden");
|
||||
} else if (this.food <= MAX_FOOD / 2) {
|
||||
statusHungry.classList.remove("hidden");
|
||||
}
|
||||
if (this.happiness <= MAX_HAPPINESS / 3) {
|
||||
statusUnhappy.classList.remove("hidden");
|
||||
}
|
||||
if (this.messCounter >= MAX_MESS) {
|
||||
statusMessy3.classList.remove("hidden");
|
||||
} else if (this.messCounter >= MAX_MESS / 2) {
|
||||
statusMessy2.classList.remove("hidden");
|
||||
} else if (this.messCounter > 0) {
|
||||
statusMessy1.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.paused) {
|
||||
pauseButton.innerText = "unpause";
|
||||
} else {
|
||||
pauseButton.innerText = "pause";
|
||||
}
|
||||
|
||||
debugLifeStage.innerText = this.lifeStage;
|
||||
debugAge.innerText = this.age;
|
||||
debugFood.innerText = this.food;
|
||||
debugBehavior.innerText = this.behavior;
|
||||
debugPotty.innerText = this.pottyTimer;
|
||||
debugMessCounter.innerText = this.messCounter;
|
||||
debugHappiness.innerText = this.happiness;
|
||||
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* feeds the pet
|
||||
* @param {number} amount the amount to feed the pet by
|
||||
*/
|
||||
feed(amount) {
|
||||
if (this.food > MAX_FOOD) {
|
||||
return;
|
||||
}
|
||||
this.food += amount;
|
||||
if (this.food <= MAX_FOOD) {
|
||||
this.happiness += FEED_HAPPINESS;
|
||||
}
|
||||
this.updateDom();
|
||||
}
|
||||
|
||||
/**
|
||||
* makes the pet go potty
|
||||
*/
|
||||
goPotty() {
|
||||
if (this.behavior > 45) {
|
||||
// go potty properly
|
||||
} else {
|
||||
this.messCounter += 1;
|
||||
if (this.messCounter > MAX_MESS) {
|
||||
this.messCounter = MAX_MESS;
|
||||
}
|
||||
}
|
||||
this.pottyTimer = POTTY_TIME;
|
||||
pet.updateDom();
|
||||
}
|
||||
|
||||
/**
|
||||
* pets the pet
|
||||
*/
|
||||
pet() {
|
||||
this.behavior += 0.5;
|
||||
this.happiness += PET_HAPPINESS;
|
||||
pet.updateDom();
|
||||
}
|
||||
|
||||
/**
|
||||
* cleans the pet's space
|
||||
*/
|
||||
clean() {
|
||||
if (this.messCounter > 0) {
|
||||
this.messCounter -= 1;
|
||||
this.happiness += CLEAN_HAPPINESS;
|
||||
} else {
|
||||
this.behavior += 1;
|
||||
this.happiness -= CLEAN_HAPPINESS;
|
||||
}
|
||||
pet.updateDom();
|
||||
}
|
||||
|
||||
/**
|
||||
* saves the pet
|
||||
*/
|
||||
save() {
|
||||
localStorage.setItem(PET_SAVE_KEY, JSON.stringify(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the pet
|
||||
*/
|
||||
load() {
|
||||
const item = localStorage.getItem(PET_SAVE_KEY);
|
||||
if (item != undefined) {
|
||||
const loaded = JSON.parse(localStorage.getItem(PET_SAVE_KEY));
|
||||
for (let k of Object.keys(loaded)) {
|
||||
this[k] = loaded[k];
|
||||
}
|
||||
this.version = CURRENT_PET_VERSION;
|
||||
this.updateDom();
|
||||
}
|
||||
}
|
||||
|
||||
/** whether the pet can be updated */
|
||||
get canUpdate() {
|
||||
return !this.paused && !this.needsAdvancement;
|
||||
}
|
||||
|
||||
/** the pet's happiness */
|
||||
get happiness() {
|
||||
return this._happiness;
|
||||
}
|
||||
|
||||
set happiness(amount) {
|
||||
if (amount < 0) {
|
||||
amount = 0;
|
||||
} else if (amount > MAX_HAPPINESS) {
|
||||
amount = MAX_HAPPINESS;
|
||||
}
|
||||
this._happiness = amount;
|
||||
}
|
||||
}
|
||||
|
||||
let pet = new Pet();
|
||||
|
||||
petSetup.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
const newName = name.value;
|
||||
if (newName.trim().length === 0) {
|
||||
return;
|
||||
}
|
||||
pet.name = newName;
|
||||
for (let name of petName) {
|
||||
name.innerText = pet.name;
|
||||
}
|
||||
pet.hatched = Date.now();
|
||||
pet.needsAdvancement = false;
|
||||
pet.updateDom();
|
||||
});
|
||||
|
||||
feedButton.addEventListener("click", () => {
|
||||
if (!canFeed || !pet.canUpdate) {
|
||||
return;
|
||||
}
|
||||
canFeed = false;
|
||||
feedButton.disabled = true;
|
||||
setTimeout(() => {
|
||||
canFeed = true;
|
||||
feedButton.disabled = false;
|
||||
}, FEED_TIMER);
|
||||
|
||||
pet.feed(38);
|
||||
});
|
||||
|
||||
petButton.addEventListener("click", () => {
|
||||
if (!canPet || !pet.canUpdate) {
|
||||
return;
|
||||
}
|
||||
canPet = false;
|
||||
petButton.disabled = true;
|
||||
setTimeout(() => {
|
||||
canPet = true;
|
||||
petButton.disabled = false;
|
||||
}, PET_TIMER);
|
||||
|
||||
pet.pet();
|
||||
});
|
||||
|
||||
cleanButton.addEventListener("click", () => {
|
||||
if (!canClean || !pet.canUpdate) {
|
||||
return;
|
||||
}
|
||||
canClean = false;
|
||||
cleanButton.disabled = true;
|
||||
setTimeout(() => {
|
||||
canClean = true;
|
||||
cleanButton.disabled = false;
|
||||
}, CLEAN_TIMER);
|
||||
|
||||
pet.clean();
|
||||
});
|
||||
|
||||
pauseButton.addEventListener("click", () => {
|
||||
pet.paused = !pet.paused;
|
||||
pet.updateDom();
|
||||
});
|
||||
|
||||
const advance = () => {
|
||||
pet.needsAdvancement = false;
|
||||
pet.updateDom();
|
||||
};
|
||||
for (let btn of document.querySelectorAll("button.advancement")) {
|
||||
btn.addEventListener("click", advance);
|
||||
}
|
||||
|
||||
passedAwayInfo.querySelector("button").addEventListener("click", () => {
|
||||
pet = new Pet();
|
||||
pet.updateDom();
|
||||
});
|
||||
|
||||
const update = () => {
|
||||
pet.update();
|
||||
};
|
||||
|
||||
setInterval(update, 60000 / UPDATES_PER_MINUTE);
|
||||
|
||||
forceUpdateButton.addEventListener("click", update);
|
||||
resetButton.addEventListener("click", () => {
|
||||
thePet.classList.remove(pet.type);
|
||||
|
||||
pet = new Pet();
|
||||
pet.updateDom();
|
||||
});
|
||||
|
||||
pet.load();
|
||||
|
||||
for (let name of petName) {
|
||||
name.innerText = pet.name;
|
||||
}
|
||||
|
||||
if (document.body.classList.contains("debug")) {
|
||||
debug.classList.remove("hidden");
|
||||
document.pet = pet;
|
||||
}
|
||||
|
||||
pet.updateDom();
|
||||
|
||||
console.log(pet);
|
||||
})();
|
50
site/sass/pet.scss
Normal file
50
site/sass/pet.scss
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pet {
|
||||
#pet-display {
|
||||
.the-pet {
|
||||
--color: red;
|
||||
--width: 250px;
|
||||
--height: 250px;
|
||||
|
||||
background-color: var(--color);
|
||||
width: var(--width);
|
||||
height: var(--height);
|
||||
margin-bottom: 8px;
|
||||
|
||||
&.egg {
|
||||
background-color: white;
|
||||
// egg shape from https://css-tricks.com/the-shapes-of-css/
|
||||
width: 126px;
|
||||
height: 180px;
|
||||
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
|
||||
}
|
||||
|
||||
&.square {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&.circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&.triangle {
|
||||
clip-path: polygon(50% 0, 100% 100%, 0 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
#debug-section [name] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,12 @@
|
|||
<link rel="stylesheet" href="/styles/index.css">
|
||||
<title>{{title}}</title>
|
||||
{{{head}}}
|
||||
{{#each scripts}}
|
||||
<script type="text/javascript" src="{{this}}" defer></script>
|
||||
{{/each}}
|
||||
{{#each styles}}
|
||||
<link rel="stylesheet" href="/styles/{{this}}">
|
||||
{{/each}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -16,6 +22,7 @@
|
|||
<span class="pronouns">it/puppy(/she)</span>
|
||||
</span>
|
||||
<span class="spacer"></span>
|
||||
<a href="/pet">creature</a> |
|
||||
<a href="/blog/">blog</a> |
|
||||
<a href="/images/">images</a> |
|
||||
<a href="/pay-me">pay me!</a> |
|
||||
|
|
|
@ -23,6 +23,10 @@ struct TemplateData<'a, T> {
|
|||
pub title: &'a str,
|
||||
/// Custom head data for the page.
|
||||
pub head: Option<String>,
|
||||
/// The page's custom scripts.
|
||||
pub scripts: &'a [String],
|
||||
/// the page's custom styles.
|
||||
pub styles: &'a [String],
|
||||
/// Custom template data.
|
||||
#[serde(flatten)]
|
||||
pub extra_data: T,
|
||||
|
@ -97,10 +101,16 @@ impl<'a> SiteBuilder<'a> {
|
|||
|
||||
let root_path = self.site.site_path.join(ROOT_PATH);
|
||||
if root_path.exists() {
|
||||
for entry in root_path.read_dir()? {
|
||||
for entry in walkdir::WalkDir::new(&root_path) {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
std::fs::copy(&path, self.build_path.join(path.strip_prefix(&root_path)?))?;
|
||||
if path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
let output_path = self.build_path.join(path.strip_prefix(&root_path)?);
|
||||
let parent_path = output_path.parent().expect("should never fail");
|
||||
std::fs::create_dir_all(parent_path)?;
|
||||
std::fs::copy(path, output_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,6 +135,10 @@ impl<'a> SiteBuilder<'a> {
|
|||
let mut rewriter = HtmlRewriter::new(
|
||||
Settings {
|
||||
element_content_handlers: vec![
|
||||
element!("body", |el| {
|
||||
el.set_attribute("class", "debug")?;
|
||||
Ok(())
|
||||
}),
|
||||
element!("head", |el| {
|
||||
el.prepend(r#"<meta charset="utf-8">"#, ContentType::Html);
|
||||
if self.serving {
|
||||
|
@ -211,12 +225,19 @@ impl<'a> SiteBuilder<'a> {
|
|||
embed.build()
|
||||
});
|
||||
|
||||
let head = page_metadata.embed.map(|mut embed| {
|
||||
embed.site_name.clone_from(&self.site.config.title);
|
||||
embed.build()
|
||||
});
|
||||
|
||||
let out = self.reg.render(
|
||||
&page_metadata.template.unwrap_or_else(|| "base".to_string()),
|
||||
&TemplateData {
|
||||
page: page_html,
|
||||
title: &title,
|
||||
head,
|
||||
scripts: &page_metadata.scripts,
|
||||
styles: &page_metadata.styles,
|
||||
extra_data,
|
||||
},
|
||||
)?;
|
||||
|
|
|
@ -71,6 +71,12 @@ pub struct PageMetadata {
|
|||
/// custom embed info for a template
|
||||
#[serde(default)]
|
||||
pub embed: Option<EmbedMetadata>,
|
||||
/// The page's custom scripts, if any.
|
||||
#[serde(default)]
|
||||
pub scripts: Vec<String>,
|
||||
/// the page's custom styles, if any.
|
||||
#[serde(default)]
|
||||
pub styles: Vec<String>,
|
||||
/// The extra stuff to run for the page, if any.
|
||||
pub extra: Option<String>,
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue