Skip to content

Instantly share code, notes, and snippets.

@Oppodelldog
Last active December 19, 2020 18:50
Show Gist options
  • Save Oppodelldog/0bdde2885d7de5584ed6a9a3f8304377 to your computer and use it in GitHub Desktop.
Save Oppodelldog/0bdde2885d7de5584ed6a9a3f8304377 to your computer and use it in GitHub Desktop.
Phasmophobia Deduction Helper
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Phasmo-Praktikant</title>
<style>
* {
margin: 0;
padding: 0;
outline: none;
font-size: 18px;
box-sizing: border-box;
}
h1 {
font-size: 26px;
}
body {
color: white;
background-color: black;
margin-left: 20px;
margin-right: 20px;
}
h1 {
cursor: pointer;
}
.content {
margin-top: 40px;
display: flex;
flex-direction: column;
justify-items: center;
align-items: center;
}
.content > * + * {
margin-top: 40px;
}
.ghost {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
padding-left: 10px;
padding-right: 10px;
}
.ghost + .ghost {
margin-top: 8px;
}
.ghost > * + * {
margin-left: 10px;
}
.ghost-name {
font-weight: bold;
width: 100px;
}
.ghost-evidence {
font-size: 12px;
}
form, form > * + * {
margin-top: 10px;
}
.option-headline {
font-weight: bold;
}
.evidence {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.evidence-proven {
color: greenyellow;
}
.evidence-excluded {
color: #5d0000;
}
.ghost-proven {
border: 1px solid greenyellow;
background-color: darkgreen;
}
.ghost-excluded, ghost-excluded > * {
text-decoration: line-through;
color: #5d0000;
}
.label {
width: 120px;
}
.option {
margin-left: 30px;
}
</style>
</head>
<body>
<div class="content">
<h1 id="headline">Phasmo-Praktikant</h1>
<div id="overview" class="overview"></div>
<div id="controls" class="controls">
<div class="evidence">
<div class="label"></div>
<div class="option-headline">Nein</div>
<div class="option-headline">?</div>
<div class="option-headline">Ja</div>
</div>
<form id="form"></form>
</div>
</div>
<script type="application/ecmascript">
const evidence = {
"1": "Box",
"2": "Fingerabd.",
"3": "Buch",
"4": "Gefriertemp.",
"5": "EMF - 5",
"6": "Orb",
}
const kinds = [
{ name: "Spirit", evidence: ["1", "2", "3"] },
{ name: "Gespenst", evidence: ["2", "4", "1"] },
{ name: "Phantom", evidence: ["5", "6", "4"] },
{ name: "Poltergeist", evidence: ["1", "2", "6"] },
{ name: "Banshee", evidence: ["5", "2", "4"] },
{ name: "Dshinn", evidence: ["1", "6", "5"] },
{ name: "Mare", evidence: ["1", "6", "4"] },
{ name: "Revenant", evidence: ["5", "2", "3"] },
{ name: "Shade", evidence: ["5", "6", "3"] },
{ name: "Dämon", evidence: ["1", "3", "4"] },
{ name: "Yurei", evidence: ["6", "3", "4"] },
{ name: "Oni", evidence: ["5", "1", "3"] },
]
function getEvidences(sel, e) {
return e.evidence.map((evId) => {
const name = evidence[evId]
const ev = document.createElement("div")
const status = parseInt(sel[evId]);
let statusClass = status === -1 ? "evidence-excluded" : status === 1 ? "evidence-proven" : "tbd";
ev.classList.add("ghost-evidence")
ev.classList.add(statusClass)
ev.innerHTML = name
return ev
})
}
function createEvidenceControls(name, id) {
const div = document.createElement("div")
const label = document.createElement("div")
const rdo1 = document.createElement("input")
const rdo2 = document.createElement("input")
const rdo3 = document.createElement("input")
div.classList.add("evidence")
label.innerHTML = name
label.classList.add("label")
rdo1.setAttribute("type", "radio")
rdo1.setAttribute("name", "evidence_" + id)
rdo1.setAttribute("value", "-1")
rdo1.classList.add("option")
rdo2.setAttribute("type", "radio")
rdo2.setAttribute("name", "evidence_" + id)
rdo2.setAttribute("value", "0")
rdo2.setAttribute("checked", "checked")
rdo2.classList.add("option")
rdo3.setAttribute("type", "radio")
rdo3.setAttribute("name", "evidence_" + id)
rdo3.setAttribute("value", "1")
rdo3.classList.add("option")
div.appendChild(label)
div.appendChild(rdo1)
div.appendChild(rdo2)
div.appendChild(rdo3)
return div;
}
function getProofs(ghost, sel) {
return ghost.evidence.filter((ev) => parseInt(sel[ev]) > 0).length;
}
function getExcludes(ghost, sel) {
return ghost.evidence.filter((ev) => parseInt(sel[ev]) < 0).length;
}
function getScoreClass(e, sel, proofs) {
const scoredProofs = getProofs(e, sel);
const matchedExcluded = getExcludes(e, sel);
let scoreClass = "tbd"
if (matchedExcluded > 0) {
scoreClass = "ghost-excluded"
} else if (scoredProofs < proofs) {
scoreClass = "ghost-excluded"
}
if (scoredProofs === 3) {
scoreClass = "ghost-proven"
}
return scoreClass;
}
function renderOverview() {
const sel = getEvidenceSelections();
const proofs = Object.keys(sel).filter((e) => parseInt(sel[e]) === 1).length;
const overview = document.getElementById("overview");
while (overview.firstChild) {
overview.firstChild.remove()
}
kinds.map((e) => {
const ghost = document.createElement("div")
const name = document.createElement("div")
const scoreClass = getScoreClass(e, sel, proofs);
ghost.classList.add("ghost")
ghost.classList.add(scoreClass)
name.innerHTML = e.name
name.classList.add("ghost-name")
ghost.appendChild(name)
getEvidences(sel, e).map((ev) => ghost.appendChild(ev))
overview.appendChild(ghost)
})
}
function renderControls() {
const form = document.getElementById("form")
form.addEventListener("change", onChangeForm)
for (let k of Object.keys(evidence)) {
form.appendChild(createEvidenceControls(evidence[k], k))
}
}
function getEvidenceSelections() {
const form = document.getElementById("form")
const fd = new FormData(form)
const evidenceSelection = {};
Object.keys(evidence).map((k) => {
evidenceSelection[k] = fd.get("evidence_" + k)
})
return evidenceSelection;
}
function onChangeForm(_) {
renderOverview();
}
window.onload = () => {
document.getElementById("headline").addEventListener("click", () => location.reload())
renderControls()
renderOverview()
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment