CharakterCreator: Unterschied zwischen den Versionen
Aus Dunkelherzen Wiki
DRP (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung Markierung: Zurückgesetzt |
DRP (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| (17 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
< | <html> | ||
<head> | <head> | ||
<meta charset="UTF-8" | <meta charset="UTF-8" /> | ||
<style> | <style> | ||
.creator-form { | |||
max-width: 800px; | max-width: 800px; | ||
margin: auto; | margin: auto; | ||
font-family: sans-serif; | |||
} | } | ||
.creator-form label { | |||
label { | |||
font-weight: bold; | font-weight: bold; | ||
display: block; | display: block; | ||
margin-top: 10px; | margin-top: 10px; | ||
} | } | ||
.creator-form input, | |||
input, select { | .creator-form select { | ||
width: 100%; | width: 100%; | ||
padding: 5px; | padding: 5px; | ||
margin-bottom: 10px; | margin-bottom: 10px; | ||
} | } | ||
.creator-form button { | |||
margin-top: 15px; | |||
padding: 10px; | |||
width: 100%; | width: 100%; | ||
} | } | ||
.attribute-inputs { | |||
display: grid; | |||
grid-template-columns: 1fr 1fr; | |||
gap: 10px; | |||
} | } | ||
.output { | .output { | ||
margin-top: 20px; | margin-top: 20px; | ||
padding: 10px; | |||
background: #f8f8f8; | background: #f8f8f8; | ||
border: 1px solid #ccc; | border: 1px solid #ccc; | ||
white-space: pre-wrap; | |||
} | } | ||
.points-remaining { | |||
. | font-weight: bold; | ||
color: #b00; | |||
margin-top: 10px; | |||
} | } | ||
</style> | </style> | ||
</head> | </head> | ||
<body> | <body> | ||
<div class="creator-form"> | |||
<h2>Charakter Creator</h2> | |||
<label for="name">Name:</label> | |||
<input type="text" id="name" placeholder="Name des Charakters"> | |||
<label for="speziestyp">Speziestyp:</label> | |||
<select id="speziestyp"> | |||
<option value="">Keine</option> | |||
<option value="Humanoid">Humanoid</option> | |||
<option value="Ätherer">Ätherer</option> | |||
<option value="Mensch-Ätherer">Mensch-Ätherer</option> | |||
<option value="Andere Ätherer">Andere Ätherer</option> | |||
<option value="Non-Humanoide / Andere">Non-Humanoide / Andere</option> | |||
<option value="Xeutano">Xeutano</option> | |||
<option value="Androidenartige">Androidenartige</option> | |||
<option value="Androidenartige">Androiden</option> | |||
</select> | |||
<label for="rasse">Spezies:</label> | |||
<select id="rasse"> | |||
<option value="">Keine</option> | |||
</select> | |||
<label for="subspezies">Subspezies:</label> | |||
<select id="subspezies"> | |||
<option value="">Keine (+20 GP Ausgleich)</option> | |||
<option value="Waldelf">Waldelf</option> | |||
<option value="Stadelf">Stadelf</option> | |||
</select> | |||
<label for="klasse">Klasse:</label> | |||
<select id="klasse"> | |||
<option value="">Keine</option> | |||
<option value="Arbeiter">Arbeiter</option> | |||
<option value="Barde">Barde</option> | |||
<option value="Bote">Bote</option> | |||
<option value="Gelehrter">Gelehrter</option> | |||
<option value="Gläubiger">Gläubiger</option> | |||
<option value="Kind">Kind</option> | |||
<option value="Krieger">Krieger</option> | |||
<option value="Schurke">Schurke</option> | |||
<option value="Schütze">Schütze</option> | |||
<option value="Seelenkünstler">Seelenkünstler</option> | |||
<option value="Soldat">Soldat</option> | |||
<option value="Techniker">Techniker</option> | |||
<option value="Vagabunde">Vagabunde</option> | |||
</select> | |||
<label for="subklasse">Subklasse:</label> | |||
<select id="subklasse"> | |||
<option value="">Keine (+15 GP Ausgleich)</option> | |||
<option value="Auserwählter">Auserwählter</option> | |||
<option value="Diener">Diener</option> | |||
<option value="Drogenjunkie">Drogenjunkie</option> | |||
<option value="Dummkopf">Dummkopf</option> | |||
<option value="Dunkler Künstler">Dunkler Künstler</option> | |||
<option value="Gesetzloser">Gesetzloser</option> | |||
<option value="Glücksspieler">Glücksspieler</option> | |||
<option value="Händler">Händler</option> | |||
<option value="Koch">Koch</option> | |||
<option value="Kopfgeldjäger">Kopfgeldjäger</option> | |||
<option value="Ödländer">Ödländer</option> | |||
<option value="Okkultist">Okkultist</option> | |||
<option value="Pazifist">Pazifist</option> | |||
<option value="Politiker">Politiker</option> | |||
<option value="Revolutionär">Revolutionär</option> | |||
<option value="Seefahrer">Seefahrer</option> | |||
<option value="Spion">Spion</option> | |||
<option value="Mutant">Mutant</option> | |||
</select> | |||
<label for="gegenstaende">Gegenstände wählen:</label> | |||
<select id="gegenstaende"> | |||
<option value="0">Keine</option> | |||
<option value="1">1 Gegenstand (-10 GP)</option> | |||
<option value="2">2 Gegenstände (-20 GP)</option> | |||
<option value="3">3 Gegenstände (-30 GP)</option> | |||
</select> | |||
<div class="points-remaining" id="punkteInfo"></div> | |||
< | |||
<label>Attribute:</label> | |||
<div class="attribute-inputs" id="attributeInputs"></div> | |||
<button onclick="berechneCharakter()">Charakter berechnen</button> | |||
<button onclick="exportiereCharakter()">Exportieren</button> | |||
<div class="output" id="ausgabe"></div> | |||
</div> | |||
<script> | <script> | ||
const attributeListe = [ | const attributeListe = [ | ||
"Agilität", "Ausdauer", "Charisma", "Geschick", "Intelligenz", | "Agilität", "Ausdauer", "Charisma", "Geschick", | ||
"Intelligenz", "Konstitution", "Resistenz", | |||
"Stärke", "Wahrnehmung" | |||
]; | ]; | ||
const basisPunkte = 160; | |||
const zeroBoni = () => | |||
Object.fromEntries(attributeListe.map(attr => [attr, 0])); | |||
const klassenBoni = Object.fromEntries([ | |||
"Arbeiter", "Barde", "Bote", "Gelehrter", "Gläubiger", "Kind", "Krieger", "Schurke", | |||
"Schütze", "Seelenkünstler", "Soldat", "Techniker", "Vagabunde" | |||
].map(name => [name, zeroBoni()])); | |||
const | const subklassenBoni = Object.fromEntries([ | ||
"Auserwählter", "Diener", "Drogenjunkie", "Dummkopf", "Dunkler Künstler", "Gesetzloser", | |||
"Glücksspieler", "Händler", "Koch", "Kopfgeldjäger", "Ödländer", "Okkultist", | |||
"Pazifist", "Politiker", "Revolutionär", "Seefahrer", "Spion", "Mutant" | |||
].map(name => [name, zeroBoni()])); | |||
const | const speziestypBoni = Object.fromEntries([ | ||
"Humanoid", "Ätherer", "Mensch-Ätherer", "Andere Ätherer", | |||
"Non-Humanoide / Andere", "Xeutano", "Androidenartige", "Androiden" | |||
].map(name => [name, zeroBoni()])); | |||
Object.assign(speziestypBoni, { | |||
"Humanoid": { "Agilität": 0, "Ausdauer": 0, "Charisma": 1, "Geschick": 0, "Intelligenz": 0, "Konstitution": 0, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | |||
" | "Ätherer": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 0, "Intelligenz": 1, "Konstitution": 0, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | ||
" | "Mensch-Ätherer": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 0, "Intelligenz": 1, "Konstitution": 0, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | ||
" | "Andere Ätherer": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 0, "Intelligenz": 0, "Konstitution": 1, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | ||
" | "Andere": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 0, "Intelligenz": 0, "Konstitution": 1, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | ||
"Xeutano": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 0, "Intelligenz": 0, "Konstitution": 1, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | |||
"Androidenartige": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 0, "Intelligenz": 0, "Konstitution": 1, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | |||
"Androiden": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 0, "Intelligenz": 0, "Konstitution": 1, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 } | |||
}); | |||
}; | |||
const | const speziesNachTyp = { | ||
" | "Humanoid": [ | ||
"Arcadier / Byzantone", "Astroma", "Caesaren", "Fijen", "Floratia", | |||
"Kalani", "Lugier", "Nore", "Pendräa", "Rubinnia", "Sowi", "Varene", "Zarcore" | |||
], | |||
"Ätherer": ["Maggarn", "Sapiée"], | |||
"Mensch-Ätherer": ["Cilina", "Gaimane"], | |||
"Andere Ätherer": ["Matari"], | |||
"Non-Humanoide / Andere": [], | |||
"Xeutano": [], | |||
" | "Androidenartige": [], | ||
"Androiden": [] | |||
" | |||
" | |||
" | |||
" | |||
" | |||
}; | }; | ||
const rassenBoni = { | const rassenBoni = { | ||
"Mensch": | "Mensch": { "Agilität": 0, "Ausdauer": 0, "Charisma": 1, "Geschick": 0, "Intelligenz": 0, "Konstitution": 0, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 }, | ||
"Elf": | "Elf": { "Agilität": 1, "Ausdauer": 0, "Charisma": 0, "Geschick": 1, "Intelligenz": 0, "Konstitution": 0, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 } | ||
}; | }; | ||
const | const subspeziesBoni = { | ||
" | "Waldelf": { "Agilität": 0, "Ausdauer": 0, "Charisma": 0, "Geschick": 1, "Intelligenz": 0, "Konstitution": 0, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 1 }, | ||
" | "Stadelf": { "Agilität": 0, "Ausdauer": 0, "Charisma": 1, "Geschick": 0, "Intelligenz": 1, "Konstitution": 0, "Resistenz": 0, "Stärke": 0, "Wahrnehmung": 0 } | ||
}; | }; | ||
attributeListe.forEach(attr => { | |||
const | const input = document.createElement("input"); | ||
input.type = "number"; | |||
input.min = "0"; | |||
input.value = "0"; | |||
input.id = `attr_${attr}`; | |||
input.oninput = updateRemainingPoints; | |||
const label = document.createElement("label"); | |||
}); | label.textContent = attr; | ||
label.htmlFor = input.id; | |||
attributeInputs.appendChild(label); | |||
attributeInputs.appendChild(input); | |||
}); | |||
function getBonus(boni, key) { | |||
return boni[key] || zeroBoni(); | |||
} | |||
function sumUserInput() { | |||
return attributeListe.reduce((sum, attr) => { | |||
const val = parseInt(document.getElementById(`attr_${attr}`).value) || 0; | |||
return sum + val; | |||
}, 0); | |||
} | } | ||
function | function updateRemainingPoints() { | ||
let | let total = basisPunkte; | ||
if (!document.getElementById("subspezies").value) total += 20; | |||
if (!document.getElementById("subklasse").value) total += 15; | |||
total -= parseInt(document.getElementById("gegenstaende").value || "0") * 10; | |||
const used = sumUserInput(); | |||
document.getElementById("punkteInfo").textContent = `Verbleibende Punkte: ${total - used} / ${total}`; | |||
} | |||
function berechneCharakter() { | |||
const name = document.getElementById("name").value; | |||
const speziestyp = document.getElementById("speziestyp").value; | |||
const rasse = document.getElementById("rasse").value; | |||
const subspezies = document.getElementById("subspezies").value; | |||
const klasse = document.getElementById("klasse").value; | const klasse = document.getElementById("klasse").value; | ||
const subklasse = document.getElementById("subklasse").value; | const subklasse = document.getElementById("subklasse").value; | ||
const | const gegenstaende = parseInt(document.getElementById("gegenstaende").value) || 0; | ||
const basisAttribute = {}; | |||
attributeListe.forEach(attr => { | |||
basisAttribute[attr] = parseInt(document.getElementById(`attr_${attr}`).value) || 0; | |||
}); | }); | ||
const gesamt = {}; | |||
const | |||
attributeListe.forEach(attr => { | attributeListe.forEach(attr => { | ||
gesamt[attr] = | |||
basisAttribute[attr] + | |||
getBonus(speziestypBoni, speziestyp)[attr] + | |||
getBonus(rassenBoni, rasse)[attr] + | |||
getBonus(subspeziesBoni, subspezies)[attr] + | |||
getBonus(klassenBoni, klasse)[attr] + | |||
getBonus(subklassenBoni, subklasse)[attr]; | |||
}); | }); | ||
const daten = { | const daten = { | ||
Name: name, | Name: name, | ||
Speziestyp: speziestyp, | |||
Subklasse: | Spezies: rasse, | ||
Subspezies: subspezies || "Keine (20 Punkte erhalten)", | |||
Klasse: klasse, | |||
Subklasse: subklasse || "Keine (15 Punkte erhalten)", | |||
Attribute: | Gegenstände: `${gegenstaende} (${gegenstaende * 10} Punkte abgezogen)`, | ||
Verwendete_Punkte: sumUserInput(), | |||
Gesamt_Punkte: basisPunkte + (subklasse ? 0 : 15) + (subspezies ? 0 : 20) - (gegenstaende * 10), | |||
Attribute: gesamt | |||
}; | }; | ||
document.getElementById("ausgabe").textContent = JSON.stringify(daten, null, 2); | document.getElementById("ausgabe").textContent = JSON.stringify(daten, null, 2); | ||
} | } | ||
function | function exportiereCharakter() { | ||
const | const daten = document.getElementById("ausgabe").textContent; | ||
if (! | if (!daten) { | ||
const blob = new Blob([ | alert("Bitte zuerst berechnen!"); | ||
return; | |||
} | |||
const blob = new Blob([daten], { type: "application/json" }); | |||
const url = URL.createObjectURL(blob); | const url = URL.createObjectURL(blob); | ||
const a = document.createElement("a"); | const a = document.createElement("a"); | ||
| Zeile 282: | Zeile 286: | ||
URL.revokeObjectURL(url); | URL.revokeObjectURL(url); | ||
} | } | ||
document.getElementById("speziestyp").addEventListener("change", function () { | |||
const typ = this.value; | |||
const rasseSelect = document.getElementById("rasse"); | |||
rasseSelect.innerHTML = '<option value="">Keine</option>'; | |||
if (speziesNachTyp[typ]) { | |||
speziesNachTyp[typ].forEach(spezies => { | |||
const opt = document.createElement("option"); | |||
opt.value = spezies; | |||
opt.textContent = spezies; | |||
rasseSelect.appendChild(opt); | |||
}); | |||
} | |||
updateRemainingPoints(); | |||
}); | |||
document.addEventListener("DOMContentLoaded", () => { | document.addEventListener("DOMContentLoaded", () => { | ||
const inputs = document.querySelectorAll("select, input[type='number']"); | |||
inputs.forEach(el => { | |||
el.addEventListener("input", updateRemainingPoints); | |||
el.addEventListener("change", updateRemainingPoints); | el.addEventListener("change", updateRemainingPoints); | ||
}); | }); | ||
updateRemainingPoints(); | |||
}); | }); | ||
</script> | </script> | ||
</body> | </body> | ||
</html> | </html> | ||
Aktuelle Version vom 29. Juli 2025, 19:59 Uhr
