Compare commits

...

2 Commits

Author SHA1 Message Date
Wynd 7519ae9e9b Split the js and css into different files for readability 2025-02-09 23:51:54 +02:00
Wynd 438091d3b4 KH2 mats filtering 2025-02-09 13:51:00 +02:00
19 changed files with 802 additions and 697 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "khguide"
version = "1.1.0"
version = "1.2.0"
edition = "2021"
[dependencies]

View File

@ -5,6 +5,21 @@ use serde::Deserialize;
use crate::create_file;
pub const MATERIAL_KINDS: &[&str] = &[
"blazing",
"bright",
"dark",
"dense",
"energy",
"frost",
"lightning",
"lucid",
"power",
"remembrance",
"serenity",
"twilight",
];
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub struct MaterialDrops {
kind: String,

View File

@ -0,0 +1,126 @@
let charFilter = "";
let typeFilter = "";
let searchType = "commands";
document.addEventListener("DOMContentLoaded", (event) => {
const searchFilter = document.getElementById("filter");
let filterHandler = debounce(() => filter());
searchFilter.addEventListener("keyup", filterHandler);
searchFilter.placeholder = "Search commands...";
const searchInputs = document.querySelectorAll(
'input[type="radio"][name="search"]',
);
searchInputs.forEach(function (item, index) {
item.addEventListener("input", function () {
searchType = this.checked ? this.value : "";
searchFilter.placeholder = "Search " + this.value + "...";
filter();
});
});
const charFilters = document.querySelectorAll(
'input[type="radio"][name="charFilter"]',
);
charFilters.forEach(function (item, index) {
item.addEventListener("input", function () {
charFilter = this.checked ? this.value : "";
filter();
});
});
const typeFilters = document.querySelectorAll(
'input[type="radio"][name="typeFilter"]',
);
typeFilters.forEach(function (item, index) {
item.addEventListener("input", function () {
typeFilter = this.checked ? this.value : "";
filter();
});
});
});
function debounce(callback, wait = 300) {
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback(...args);
}, wait);
};
}
function filter() {
const table = document.querySelector("table tbody");
const search = document.getElementById("filter").value.toLowerCase();
for (const child of table.children) {
const tds = child.children;
resetStyle(child, tds);
if (search.length > 0) {
if (searchType === "commands") {
// Check for command name
if (!tds[1].innerText.toLowerCase().includes(search)) {
child.style.display = "none";
} else {
applyStyle(tds[1]);
}
} else if (searchType === "ingredients") {
// Ingredients
if (!tds[2].innerText.toLowerCase().includes(search)) {
if (!tds[3].innerText.toLowerCase().includes(search)) {
child.style.display = "none";
} else {
applyStyle(tds[3]);
}
} else {
applyStyle(tds[2]);
if (tds[3].innerText.toLowerCase().includes(search)) {
applyStyle(tds[3]);
}
}
} else if (searchType === "abilities") {
// Abilities
hasLine = false;
for (let i = 0; i < 7; i++) {
const id = i + 6;
const ablName = tds[id].innerText.toLowerCase();
if (ablName.includes(search)) {
applyStyle(tds[id]);
hasLine = true;
break;
}
}
if (!hasLine) {
child.style.display = "none";
}
}
}
const typeCheck = typeFilter === "" || tds[1].className === typeFilter;
const charCheck =
charFilter === "" || child.className.includes(charFilter);
if (child.style.display == "" && (!typeCheck || !charCheck)) {
child.style.display = "none";
}
}
}
function resetStyle(child, tds) {
child.style.display = "";
for (const td of tds) {
td.style.fontWeight = "inherit";
td.style.color = "#fff";
}
}
function applyStyle(el) {
el.style.fontWeight = "bold";
el.style.color = "red";
}

View File

@ -0,0 +1,30 @@
table {
.charlist {
display: inline-grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
.aqua {
color: #97c8ff;
}
.ventus {
color: #26ff62;
}
.terra {
color: #ff7400;
}
}
tbody tr:hover {
background-color: #4f4f4f;
}
& tr,
th,
td {
border: 1px solid #fff;
padding: 7px;
}
}

View File

@ -0,0 +1,213 @@
.blue {
background-color: #35a0a8;
}
.purple {
background-color: #992a9b;
}
.green {
background-color: #7ecf50;
}
.yellow {
background-color: #d3c949;
}
.secret1 {
background-color: #497331;
}
.secret2 {
background-color: #881a22;
}
div.abilities {
display: flex;
& div {
margin-right: 60px;
}
}
.dispositions {
display: flex;
flex-wrap: wrap;
div.route {
display: flex;
align-items: center;
width: 40%;
& div {
display: flex;
align-items: center;
}
& .disposition {
width: 32px;
height: 32px;
margin-right: 5px;
display: inline-block;
vertical-align: middle;
}
& span {
font-size: 18px;
}
& ul {
list-style: disclosure-closed;
line-height: 2.5;
& li {
display: list-item;
}
}
}
}
table.board {
width: inherit;
td {
width: 120px;
height: 100px;
position: relative;
& span {
position: inherit;
z-index: 10;
color: black;
}
& .slot {
width: 70%;
height: 70%;
position: relative;
left: 15px;
background-color: #cbf;
z-index: 10;
align-content: center;
font-size: 14px;
box-shadow: 1px 1px 5px black;
.help:after {
content: "?";
position: absolute;
color: rgba(0, 0, 0, 0.3);
font-size: 24px;
bottom: 0;
right: 5px;
}
}
.tooltip-wrapper {
.tooltip {
visibility: hidden;
background-color: #555;
max-width: 250px;
min-width: 150px;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 8px;
position: absolute;
z-index: 1;
bottom: 125%;
left: -50%;
opacity: 0;
transition: opacity 0.3s;
}
&:hover .tooltip {
visibility: visible;
opacity: 1;
}
}
&.slot-w {
height: 20px;
}
&.slot-h {
width: 20px;
}
&.start .slot {
background-color: #dcbf7e;
}
&.north.east.south.west .path::after {
content: "┼";
}
&.east.south.west .path::after {
content: "┬";
}
&.east.north.west .path::after {
content: "┴";
}
&.north.south.west .path::after {
content: "┤";
}
&.north.south.east .path::after {
content: "├";
}
&.south.east .path::after {
content: "┌";
}
&.south.west .path::after {
content: "┐";
}
&.north.west .path::after {
content: "┘";
}
&.north.east .path::after {
content: "└";
}
&.east.west .path::after {
content: "─";
}
&.north.south .path::after {
content: "│";
}
&.west .path::after {
content: "╴";
}
&.east .path::after {
content: "╶";
}
&.south .path::after {
content: "╷";
}
&.north .path::after {
content: "╵";
}
}
}
.path {
position: absolute;
top: -70px;
left: 0;
font-size: 200px;
width: 100%;
height: 100%;
z-index: 0;
/*color: #3c3c3c;*/
color: #ccbbff;
}

View File

@ -0,0 +1,13 @@
{% for kind in MATERIAL_KINDS %}
<input
type="checkbox"
id="{{ kind }}Filter"
name="kindFilter"
autocomplete="off"
value="{{ kind }}"
/>
<label for="{{ kind }}Filter">{{ kind|capitalize }}</label>
{% if loop.index0 == 6 %}
<br />
{% endif %}
{% endfor %}

View File

@ -0,0 +1,8 @@
<input
type="checkbox"
id="onlyTracked"
name="onlyTracked"
autocomplete="off"
value=""
/>
<label for="onlyTracked">Show only tracked</label>

View File

@ -0,0 +1,61 @@
let showOnlyTracked = false;
let kindFilter = new Set();
document.addEventListener("DOMContentLoaded", (event) => {
const onlyTrackedFilter = document.querySelector(
'input[name="onlyTracked"]',
);
onlyTrackedFilter.addEventListener("input", function () {
showOnlyTracked = this.checked ? true : false;
filter();
});
const kindFilters = document.querySelectorAll(
'input[type="checkbox"][name="kindFilter"]',
);
kindFilters.forEach(function (item, index) {
item.addEventListener("input", function () {
if (this.checked) {
kindFilter.add(this.value);
} else {
kindFilter.delete(this.value);
}
console.log(kindFilter);
filter();
});
});
});
function track(element) {
let parent = element.parentElement.parentElement;
let isTracked = parent.dataset["isTracked"] ?? false;
isTracked = isTracked === "true" ? false : true;
parent.dataset["isTracked"] = isTracked;
element.innerHTML = isTracked ? "Stop tracking" : "Start tracking";
element.style["border-bottom-color"] = isTracked ? "#a00" : "#0a0";
filter();
}
function filter() {
const categories = document.querySelectorAll(".category-wrapper");
for (const category of categories) {
let isTracked = category.dataset["isTracked"] == "true";
let kind = category.dataset["matKind"];
let type = category.dataset["matType"];
category.style.display = "";
if (showOnlyTracked && !isTracked) {
category.style.display = "none";
}
if (kindFilter.size > 0) {
if (!kindFilter.has(kind)) {
category.style.display = "none";
}
}
}
}

View File

@ -0,0 +1,41 @@
.category {
display: flex;
align-items: center;
}
.enemies {
display: flex;
.drop {
display: flex;
flex-direction: column;
text-align: center;
margin-right: 8px;
line-height: 30px;
font-size: 18px;
text-shadow: black 2px 2px;
transition: all 0.2s ease;
div {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
width: 256px;
height: 256px;
background-size: 384px;
transition: all 0.2s ease;
box-shadow: inset rgb(51, 51, 51) 0px 0px 10px 15px;
}
/* &:hover { */
/* background-color: #333; */
/* box-shadow: 0 0 10px 1px rgba(0, 255, 0, 0.5); */
/* transform: scale(1.5); */
/**/
/* & > div { */
/* padding: 32px; */
/* margin: -32px; */
/* } */
/* } */
}
}

View File

@ -0,0 +1,162 @@
let globalStats = { str: 0, mag: 0, def: 0, hp: 0, mp: 0 };
const types = ["starters", "soups", "fish", "meat", "deserts"];
let typeItem = [];
let hasSelection = [false, false, false, false, false];
document.addEventListener("DOMContentLoaded", (event) => {
updateStats();
types.forEach(function (type, typeIdx) {
const recipes = document.querySelectorAll(
"div.recipes." + type + " .recipe",
);
recipes.forEach(function (item, index) {
item.addEventListener("click", function () {
if (!hasSelection[typeIdx]) {
hasSelection[typeIdx] = true;
selectRecipe(item, typeIdx);
} else {
if (typeItem[typeIdx] != item) {
unselectRecipe(typeIdx);
selectRecipe(item, typeIdx);
} else {
hasSelection[typeIdx] = false;
unselectRecipe(typeIdx);
updateStats();
}
}
});
});
});
document
.getElementById("hearty-meal")
.addEventListener("click", function () {
console.log(this);
if (this.checked) {
let bonusStr = Math.ceil(globalStats.str * 0.25);
let bonusMag = Math.ceil(globalStats.mag * 0.25);
let bonusDef = Math.ceil(globalStats.def * 0.25);
let bonusHP = Math.ceil(globalStats.hp * 0.25);
let bonusMP = Math.ceil(globalStats.mp * 0.25);
let stats = {
str: bonusStr,
mag: bonusMag,
def: bonusDef,
hp: bonusHP,
mp: bonusMP,
};
addStats(stats);
} else {
let bonusStr = Math.ceil(globalStats.str * 0.2);
let bonusMag = Math.ceil(globalStats.mag * 0.2);
let bonusDef = Math.ceil(globalStats.def * 0.2);
let bonusHP = Math.ceil(globalStats.hp * 0.2);
let bonusMP = Math.ceil(globalStats.mp * 0.2);
let stats = {
str: bonusStr,
mag: bonusMag,
def: bonusDef,
hp: bonusHP,
mp: bonusMP,
};
removeStats(stats);
updateStats();
}
});
});
function unselectRecipe(index) {
typeItem[index].style["box-shadow"] = "0px 0px 10px rgba(0, 0, 0, 0.4)";
let stats = JSON.parse(typeItem[index].dataset["stats"]);
removeStats(stats);
}
function selectRecipe(item, index) {
typeItem[index] = item;
item.style["box-shadow"] = "0px 0px 10px rgba(0, 255, 0, 0.8)";
let stats = JSON.parse(item.dataset["stats"]);
addStats(stats);
}
function addStats(stats) {
globalStats.str += stats.str;
globalStats.mag += stats.mag;
globalStats.def += stats.def;
globalStats.hp += stats.hp;
globalStats.mp += stats.mp;
updateStats();
}
function removeStats(stats) {
globalStats.str -= stats.str;
globalStats.mag -= stats.mag;
globalStats.def -= stats.def;
globalStats.hp -= stats.hp;
globalStats.mp -= stats.mp;
}
const STR_MAX = 5;
const MAG_MAX = 5;
const DEF_MAX = 5;
const HP_MAX = 63;
const MP_MAX = 50;
const CENTER_POINT = [150, 120];
const STR_MAX_POINT = [150, 20];
const MAG_MAX_POINT = [50, 100];
const DEF_MAX_POINT = [250, 100];
const HP_MAX_POINT = [210, 210];
const MP_MAX_POINT = [90, 210];
function updateStats() {
let strProgress = globalStats.str / STR_MAX;
let magProgress = globalStats.mag / MAG_MAX;
let defProgress = globalStats.def / DEF_MAX;
let hpProgress = globalStats.hp / HP_MAX;
let mpProgress = globalStats.mp / MP_MAX;
let poly = document.getElementById("stats-mod");
updatePoint(
poly,
0,
STR_MAX_POINT,
strProgress,
globalStats.str,
"stat-str",
);
updatePoint(
poly,
4,
MAG_MAX_POINT,
magProgress,
globalStats.mag,
"stat-mag",
);
updatePoint(
poly,
1,
DEF_MAX_POINT,
defProgress,
globalStats.def,
"stat-def",
);
updatePoint(poly, 2, HP_MAX_POINT, hpProgress, globalStats.hp, "stat-hp");
updatePoint(poly, 3, MP_MAX_POINT, mpProgress, globalStats.mp, "stat-mp");
}
function updatePoint(poly, statId, max, progress, value, statElem) {
poly.points[statId].x =
CENTER_POINT[0] + (max[0] - CENTER_POINT[0]) * progress;
poly.points[statId].y =
CENTER_POINT[1] + (max[1] - CENTER_POINT[1]) * progress;
document.getElementById(statElem).innerHTML = "+" + value;
}

View File

@ -0,0 +1,62 @@
#content > h1 {
text-align: center;
width: 80%;
margin-left: auto;
}
.recipes {
font-size: 12px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: baseline;
gap: 16px;
width: 80%;
margin-right: 0;
margin-left: auto;
}
.recipe {
width: 20%;
align-self: stretch;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.4);
padding: 16px;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: space-between;
.ingredients {
margin-left: 16px;
}
.stats {
table {
tr.plus {
color: gold;
}
th {
padding: 8px;
}
td {
background-color: #4d4d4d;
}
}
}
}
#stats {
position: fixed;
}
svg > text {
stroke-width: 0;
fill: white;
}
#hearty-meal-wrapper {
text-align: center;
width: 80%;
}

View File

@ -58,6 +58,32 @@
}
}
}
button {
margin-left: 16px;
background: #444;
color: #fff;
padding: 8px;
border-color: #555;
border-bottom-color: rgb(85, 85, 85);
border-style: groove;
border-bottom-color: #0a0;
transition-duration: 0.1s;
&:hover {
background: #4f4f4f;
}
&:active {
background: #3f3f3f;
transform: translateY(1px);
}
&.disabled {
opacity: 0.6;
cursor: not-allowed;
}
}
</style>
{% block head %}{% endblock %}

View File

@ -1,21 +1,28 @@
{% macro drop(label) %}
<div class="category">
<img
src="../assets/materials/{{ category.kind }}/{{ label }}.webp"
width="64"
height="64"
/>
<h1>{{ category.kind|capitalize +}} {{+ label|capitalize }}</h1>
</div>
<div class="enemies">
{% for drop in category.drops(label) %}
<div class="drop">
<div
style="background-image: url('../assets/enemies/{{ drop.texture() }}.webp');"
></div>
<span>{{ drop.from +}}</span>
<span>{{+ drop.chance }}%</span>
</div>
{% endfor %}
<div
class="category-wrapper"
data-mat-kind="{{ category.kind }}"
data-mat-type="{{ label }}"
>
<div class="category">
<img
src="../assets/materials/{{ category.kind }}/{{ label }}.webp"
width="64"
height="64"
/>
<h1>{{ category.kind|capitalize +}} {{+ label|capitalize }}</h1>
<button onclick="track(this)">Start tracking</button>
</div>
<div class="enemies">
{% for drop in category.drops(label) %}
<div class="drop">
<div
style="background-image: url('../assets/enemies/{{ drop.texture() }}.webp');"
></div>
<span>{{ drop.from +}}</span>
<span>{{+ drop.chance }}%</span>
</div>
{% endfor %}
</div>
</div>
{% endmacro %}

View File

@ -3,173 +3,8 @@
{% block title %}BBS - Command Melding{% endblock %}
{% block head %}
<style>
table {
.charlist {
display: inline-grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
.aqua {
color: #97c8ff;
}
.ventus {
color: #26ff62;
}
.terra {
color: #ff7400;
}
}
tbody tr:hover {
background-color: #4f4f4f;
}
& tr,
th,
td {
border: 1px solid #fff;
padding: 7px;
}
}
</style>
<script>
let charFilter = "";
let typeFilter = "";
let searchType = "commands";
document.addEventListener("DOMContentLoaded", (event) => {
const searchFilter = document.getElementById("filter");
let filterHandler = debounce(() => filter());
searchFilter.addEventListener("keyup", filterHandler);
searchFilter.placeholder = "Search commands...";
const searchInputs = document.querySelectorAll(
'input[type="radio"][name="search"]',
);
searchInputs.forEach(function (item, index) {
item.addEventListener("input", function () {
searchType = this.checked ? this.value : "";
searchFilter.placeholder = "Search " + this.value + "...";
filter();
});
});
const charFilters = document.querySelectorAll(
'input[type="radio"][name="charFilter"]',
);
charFilters.forEach(function (item, index) {
item.addEventListener("input", function () {
charFilter = this.checked ? this.value : "";
filter();
});
});
const typeFilters = document.querySelectorAll(
'input[type="radio"][name="typeFilter"]',
);
typeFilters.forEach(function (item, index) {
item.addEventListener("input", function () {
typeFilter = this.checked ? this.value : "";
filter();
});
});
});
function debounce(callback, wait = 300) {
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback(...args);
}, wait);
};
}
function filter() {
const table = document.querySelector("table tbody");
const search = document
.getElementById("filter")
.value.toLowerCase();
for (const child of table.children) {
const tds = child.children;
resetStyle(child, tds);
if (search.length > 0) {
if (searchType === "commands") {
// Check for command name
if (!tds[1].innerText.toLowerCase().includes(search)) {
child.style.display = "none";
} else {
applyStyle(tds[1]);
}
} else if (searchType === "ingredients") {
// Ingredients
if (!tds[2].innerText.toLowerCase().includes(search)) {
if (
!tds[3].innerText.toLowerCase().includes(search)
) {
child.style.display = "none";
} else {
applyStyle(tds[3]);
}
} else {
applyStyle(tds[2]);
if (
tds[3].innerText.toLowerCase().includes(search)
) {
applyStyle(tds[3]);
}
}
} else if (searchType === "abilities") {
// Abilities
hasLine = false;
for (let i = 0; i < 7; i++) {
const id = i + 6;
const ablName = tds[id].innerText.toLowerCase();
if (ablName.includes(search)) {
applyStyle(tds[id]);
hasLine = true;
break;
}
}
if (!hasLine) {
child.style.display = "none";
}
}
}
const typeCheck =
typeFilter === "" || tds[1].className === typeFilter;
const charCheck =
charFilter === "" || child.className.includes(charFilter);
if (child.style.display == "" && (!typeCheck || !charCheck)) {
child.style.display = "none";
}
}
}
function resetStyle(child, tds) {
child.style.display = "";
for (const td of tds) {
td.style.fontWeight = "inherit";
td.style.color = "#fff";
}
}
function applyStyle(el) {
el.style.fontWeight = "bold";
el.style.color = "red";
}
</script>
<style> {% include "components/bbs/style.css" %}</style>
<script> {% include "components/bbs/script.js" %}</script>
{% endblock %}
{% block content %}

View File

@ -3,232 +3,8 @@
{% block title %}DDD - Spirit Boards{% endblock %}
{% block head %}
<style>
.blue {
background-color: #35a0a8;
}
.purple {
background-color: #992a9b;
}
.green {
background-color: #7ecf50;
}
.yellow {
background-color: #d3c949;
}
.secret1 {
background-color: #497331;
}
.secret2 {
background-color: #881a22;
}
div.abilities {
display: flex;
& div {
margin-right: 60px;
}
}
.dispositions {
display: flex;
flex-wrap: wrap;
div.route {
display: flex;
align-items: center;
width: 40%;
& div {
display: flex;
align-items: center;
}
& .disposition {
width: 32px;
height: 32px;
margin-right: 5px;
display: inline-block;
vertical-align: middle;
}
& span {
font-size: 18px;
}
& ul {
list-style: disclosure-closed;
line-height: 2.5;
& li {
display: list-item;
}
}
}
}
table.board {
width: inherit;
td {
width: 120px;
height: 100px;
position: relative;
& span {
position: inherit;
z-index: 10;
color: black;
}
& .slot {
width: 70%;
height: 70%;
position: relative;
left: 15px;
background-color: #cbf;
z-index: 10;
align-content: center;
font-size: 14px;
box-shadow: 1px 1px 5px black;
.help:after {
content: "?";
position: absolute;
color: rgba(0, 0, 0, 0.3);
font-size: 24px;
bottom: 0;
right: 5px;
}
}
.tooltip-wrapper {
.tooltip {
visibility: hidden;
background-color: #555;
max-width: 250px;
min-width: 150px;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 8px;
position: absolute;
z-index: 1;
bottom: 125%;
left: -50%;
opacity: 0;
transition: opacity 0.3s;
}
&:hover .tooltip {
visibility: visible;
opacity: 1;
}
}
&.slot-w {
height: 20px;
}
&.slot-h {
width: 20px;
}
&.start .slot {
background-color: #dcbf7e;
}
&.north.east.south.west .path::after {
content: "┼";
}
&.east.south.west .path::after {
content: "┬";
}
&.east.north.west .path::after {
content: "┴";
}
&.north.south.west .path::after {
content: "┤";
}
&.north.south.east .path::after {
content: "├";
}
&.south.east .path::after {
content: "┌";
}
&.south.west .path::after {
content: "┐";
}
&.north.west .path::after {
content: "┘";
}
&.north.east .path::after {
content: "└";
}
&.east.west .path::after {
content: "─";
}
&.north.south .path::after {
content: "│";
}
&.west .path::after {
content: "╴";
}
&.east .path::after {
content: "╶";
}
&.south .path::after {
content: "╷";
}
&.north .path::after {
content: "╵";
}
}
}
.path {
position: absolute;
top: -70px;
left: 0;
font-size: 200px;
width: 100%;
height: 100%;
z-index: 0;
/*color: #3c3c3c;*/
color: #ccbbff;
}
</style>
<script>
function debounce(callback, wait = 300) {
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback(...args);
}, wait);
};
}
</script>
<style>{% include "components/ddd/style.css" %}</style>
<script>{% include "components/ddd/script.js" %}</script>
{% endblock %}
{% block content %}

View File

@ -26,4 +26,11 @@
<li><a href="./kh3/food-sim.html">Food Simulator</a></li>
</ul>
{% endif %}
{% if cfg!(feature = "kh2") %}
<h1>Kingdom Hearts II</h1>
<ul>
<li><a href="./kh2/drops.html">Material Drops</a></li>
</ul>
{% endif %}
{% endblock %}

View File

@ -4,51 +4,15 @@
{% block title %}KH2 - Drops{% endblock %}
{% block head %}
<style>
.category {
display: flex;
align-items: center;
}
.enemies {
display: flex;
.drop {
display: flex;
flex-direction: column;
text-align: center;
margin-right: 8px;
line-height: 30px;
font-size: 18px;
text-shadow: black 2px 2px;
transition: all 0.2s ease;
div {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
width: 256px;
height: 256px;
background-size: 384px;
transition: all 0.2s ease;
}
/* &:hover { */
/* background-color: #333; */
/* box-shadow: 0 0 10px 1px rgba(0, 255, 0, 0.5); */
/* transform: scale(1.5); */
/**/
/* & > div { */
/* padding: 32px; */
/* margin: -32px; */
/* } */
/* } */
}
}
</style>
<style>{% include "components/kh2/style.css" %}</style>
<script>{% include "components/kh2/script.js" %}</script>
{% endblock %}
{% block content %}
{% include "components/kh2/only-tracked-filter.html" %}
<br />
{% include "components/kh2/kind-filters.html" %}
<br />
{% for category in drops %}
{% call macros::drop("shard") %}

View File

@ -3,249 +3,8 @@
{% block title %}KH3 - Food Simulator{% endblock %}
{% block head %}
<style>
#content > h1 {
text-align: center;
width: 80%;
margin-left: auto;
}
.recipes {
font-size: 12px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: baseline;
gap: 16px;
width: 80%;
margin-right: 0;
margin-left: auto;
}
.recipe {
width: 20%;
align-self: stretch;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.4);
padding: 16px;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: space-between;
.ingredients {
margin-left: 16px;
}
.stats {
table {
tr.plus {
color: gold;
}
th {
padding: 8px;
}
td {
background-color: #4d4d4d;
}
}
}
}
#stats {
position: fixed;
}
svg > text {
stroke-width: 0;
fill: white;
}
#hearty-meal-wrapper {
text-align: center;
width: 80%;
}
</style>
<script>
let globalStats = { str: 0, mag: 0, def: 0, hp: 0, mp: 0 };
const types = ["starters", "soups", "fish", "meat", "deserts"];
let typeItem = [];
let hasSelection = [false, false, false, false, false];
document.addEventListener("DOMContentLoaded", (event) => {
updateStats();
types.forEach(function (type, typeIdx) {
const recipes = document.querySelectorAll(
"div.recipes." + type + " .recipe",
);
recipes.forEach(function (item, index) {
item.addEventListener("click", function () {
if (!hasSelection[typeIdx]) {
hasSelection[typeIdx] = true;
selectRecipe(item, typeIdx);
} else {
if (typeItem[typeIdx] != item) {
unselectRecipe(typeIdx);
selectRecipe(item, typeIdx);
} else {
hasSelection[typeIdx] = false;
unselectRecipe(typeIdx);
updateStats();
}
}
});
});
});
document
.getElementById("hearty-meal")
.addEventListener("click", function () {
console.log(this);
if (this.checked) {
let bonusStr = Math.ceil(globalStats.str * 0.25);
let bonusMag = Math.ceil(globalStats.mag * 0.25);
let bonusDef = Math.ceil(globalStats.def * 0.25);
let bonusHP = Math.ceil(globalStats.hp * 0.25);
let bonusMP = Math.ceil(globalStats.mp * 0.25);
let stats = {
str: bonusStr,
mag: bonusMag,
def: bonusDef,
hp: bonusHP,
mp: bonusMP,
};
addStats(stats);
} else {
let bonusStr = Math.ceil(globalStats.str * 0.2);
let bonusMag = Math.ceil(globalStats.mag * 0.2);
let bonusDef = Math.ceil(globalStats.def * 0.2);
let bonusHP = Math.ceil(globalStats.hp * 0.2);
let bonusMP = Math.ceil(globalStats.mp * 0.2);
let stats = {
str: bonusStr,
mag: bonusMag,
def: bonusDef,
hp: bonusHP,
mp: bonusMP,
};
removeStats(stats);
updateStats();
}
});
});
function unselectRecipe(index) {
typeItem[index].style["box-shadow"] =
"0px 0px 10px rgba(0, 0, 0, 0.4)";
let stats = JSON.parse(typeItem[index].dataset["stats"]);
removeStats(stats);
}
function selectRecipe(item, index) {
typeItem[index] = item;
item.style["box-shadow"] = "0px 0px 10px rgba(0, 255, 0, 0.8)";
let stats = JSON.parse(item.dataset["stats"]);
addStats(stats);
}
function addStats(stats) {
globalStats.str += stats.str;
globalStats.mag += stats.mag;
globalStats.def += stats.def;
globalStats.hp += stats.hp;
globalStats.mp += stats.mp;
updateStats();
}
function removeStats(stats) {
globalStats.str -= stats.str;
globalStats.mag -= stats.mag;
globalStats.def -= stats.def;
globalStats.hp -= stats.hp;
globalStats.mp -= stats.mp;
}
const STR_MAX = 5;
const MAG_MAX = 5;
const DEF_MAX = 5;
const HP_MAX = 63;
const MP_MAX = 50;
const CENTER_POINT = [150, 120];
const STR_MAX_POINT = [150, 20];
const MAG_MAX_POINT = [50, 100];
const DEF_MAX_POINT = [250, 100];
const HP_MAX_POINT = [210, 210];
const MP_MAX_POINT = [90, 210];
function updateStats() {
let strProgress = globalStats.str / STR_MAX;
let magProgress = globalStats.mag / MAG_MAX;
let defProgress = globalStats.def / DEF_MAX;
let hpProgress = globalStats.hp / HP_MAX;
let mpProgress = globalStats.mp / MP_MAX;
let poly = document.getElementById("stats-mod");
updatePoint(
poly,
0,
STR_MAX_POINT,
strProgress,
globalStats.str,
"stat-str",
);
updatePoint(
poly,
4,
MAG_MAX_POINT,
magProgress,
globalStats.mag,
"stat-mag",
);
updatePoint(
poly,
1,
DEF_MAX_POINT,
defProgress,
globalStats.def,
"stat-def",
);
updatePoint(
poly,
2,
HP_MAX_POINT,
hpProgress,
globalStats.hp,
"stat-hp",
);
updatePoint(
poly,
3,
MP_MAX_POINT,
mpProgress,
globalStats.mp,
"stat-mp",
);
}
function updatePoint(poly, statId, max, progress, value, statElem) {
poly.points[statId].x =
CENTER_POINT[0] + (max[0] - CENTER_POINT[0]) * progress;
poly.points[statId].y =
CENTER_POINT[1] + (max[1] - CENTER_POINT[1]) * progress;
document.getElementById(statElem).innerHTML = "+" + value;
}
</script>
<style>{% include "components/kh3/style.css" %}</style>
<script>{% include "components/kh3/script.js" %}</script>
{% endblock %}
{% block content %}