CharakterCreator: Unterschied zwischen den Versionen
Aus Dunkelherzen Wiki
DRP (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung Markierung: Manuelle Zurücksetzung |
DRP (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| Zeile 1: | Zeile 1: | ||
<!DOCTYPE html> | |||
<html> | <html> | ||
<head> | <head> | ||
| Zeile 8: | Zeile 9: | ||
font-family: sans-serif; | font-family: sans-serif; | ||
} | } | ||
.creator-form label { | .creator-form label { | ||
font-weight: bold; | font-weight: bold; | ||
| Zeile 14: | Zeile 14: | ||
margin-top: 10px; | margin-top: 10px; | ||
} | } | ||
.creator-form input, | .creator-form input, | ||
.creator-form select { | .creator-form select { | ||
| Zeile 21: | Zeile 20: | ||
margin-bottom: 10px; | margin-bottom: 10px; | ||
} | } | ||
.creator-form button { | .creator-form button { | ||
margin-top: 15px; | margin-top: 15px; | ||
| Zeile 27: | Zeile 25: | ||
width: 100%; | width: 100%; | ||
} | } | ||
.attribute-inputs { | .attribute-inputs { | ||
display: grid; | display: grid; | ||
| Zeile 33: | Zeile 30: | ||
gap: 10px; | gap: 10px; | ||
} | } | ||
.output { | .output { | ||
margin-top: 20px; | margin-top: 20px; | ||
| Zeile 41: | Zeile 37: | ||
white-space: pre-wrap; | white-space: pre-wrap; | ||
} | } | ||
.points-remaining { | .points-remaining { | ||
font-weight: bold; | font-weight: bold; | ||
| Zeile 50: | Zeile 45: | ||
</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> | |||
</select> | |||
<label for="rasse">Rasse:</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> | |||
const attributeListe = [ | |||
"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 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 speziestypBoni = Object.fromEntries([ | |||
"Humanoid", "Ätherer", "Mensch-Ätherer", "Andere Ätherer", | |||
"Non-Humanoide / Andere", "Xeutano", "Androidenartige" | |||
].map(name => [name, zeroBoni()])); | |||
const speciesByType = { | |||
" | "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": [] | |||
}; | |||
const rassenBoni = Object.fromEntries( | |||
Object.values(speciesByType).flat().map(name => [name, zeroBoni()]) | |||
); | |||
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 } | |||
}; | |||
// Dynamisches Umschalten der Rassen je nach Speziestyp | |||
document.getElementById("speziestyp").addEventListener("change", function () { | |||
const typ = this.value; | |||
const rasseSelect = document.getElementById("rasse"); | |||
rasseSelect.innerHTML = "<option value=''>Keine</option>"; | |||
if (speciesByType[typ]) { | |||
speciesByType[typ].forEach(rasse => { | |||
const opt = document.createElement("option"); | |||
opt.value = rasse; | |||
opt.textContent = rasse; | |||
rasseSelect.appendChild(opt); | |||
}); | |||
} | } | ||
}); | |||
const attributeInputs = document.getElementById("attributeInputs"); | |||
attributeListe.forEach(attr => { | |||
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 updateRemainingPoints() { | |||
let total = basisPunkte; | |||
if (!document.getElementById("subspezies").value) total += 20; | |||
if (!document.getElementById("subklasse").value) total += 15; | |||
const gegenstaende = parseInt(document.getElementById("gegenstaende").value) || 0; | |||
total -= gegenstaende * 10; | |||
const used = sumUserInput(); | |||
const remaining = total - used; | |||
document.getElementById("punkteInfo").textContent = `Verbleibende Punkte: ${remaining} / ${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 subklasse = document.getElementById("subklasse").value; | |||
const gegenstaende = parseInt(document.getElementById("gegenstaende").value) || 0; | |||
const basisAttribute = {}; | |||
attributeListe.forEach(attr => { | |||
basisAttribute[attr] = parseInt(document.getElementById(`attr_${attr}`).value) || 0; | |||
}); | |||
const gesamt = {}; | |||
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 = { | |||
Name: name, | |||
Speziestyp: speziestyp, | |||
Rasse: rasse, | |||
Subspezies: subspezies || "Keine (20 Punkte erhalten)", | |||
Klasse: klasse, | |||
Subklasse: subklasse || "Keine (15 Punkte erhalten)", | |||
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); | |||
} | |||
function exportiereCharakter() { | |||
const daten = document.getElementById("ausgabe").textContent; | |||
if (!daten) { | |||
alert("Bitte zuerst berechnen!"); | |||
return; | |||
} | } | ||
const blob = new Blob([daten], { type: "application/json" }); | |||
const url = URL.createObjectURL(blob); | |||
const a = document.createElement("a"); | |||
a.href = url; | |||
a.download = "charakter.json"; | |||
a.click(); | |||
URL.revokeObjectURL(url); | |||
} | |||
document.addEventListener("DOMContentLoaded", function () { | |||
const inputs = document.querySelectorAll("select, input[type='number']"); | |||
inputs.forEach(el => { | |||
el.addEventListener("input", updateRemainingPoints); | |||
el.addEventListener("change", updateRemainingPoints); | |||
}); | }); | ||
</script> | updateRemainingPoints(); | ||
}); | |||
</script> | |||
</body> | </body> | ||
</html> | </html> | ||
Version vom 29. Juli 2025, 16:16 Uhr
<!DOCTYPE html>
