Workflow und Layout repariert.
Übersetzungen hinzugefügt
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="attributes-form character-creation-container">
|
||||
<h2>Character Attributes</h2>
|
||||
<p class="instruction">Set the basic attributes for your character (1-100)</p>
|
||||
<h2>{{ $t('characters.attributes.title') }}</h2>
|
||||
<p class="instruction">{{ $t('characters.attributes.instruction') }}</p>
|
||||
|
||||
<form @submit.prevent="handleSubmit" class="attributes-form-content">
|
||||
<div class="attributes-grid">
|
||||
<div class="attribute-group" v-for="attr in attributes" :key="attr.key">
|
||||
<div class="attribute-row">
|
||||
<label :for="attr.key" class="attribute-label">
|
||||
{{ attr.name }} ({{ attr.key.toUpperCase() }})
|
||||
{{ $t(`characters.attributes.${attr.key}`) }} ({{ attr.key.toUpperCase() }})
|
||||
</label>
|
||||
<div class="input-with-dice">
|
||||
<input
|
||||
@@ -19,23 +19,23 @@
|
||||
max="100"
|
||||
required
|
||||
class="attribute-input"
|
||||
@input="updateTotal"
|
||||
@input="handleAttributeChange"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="dice-btn"
|
||||
@click="rollAttribute(attr.key)"
|
||||
:title="attr.key === 'au' ? 'Roll AU: 1d100 with race restrictions (Elfen ≥81, Gnome/Zwerge ≤80)' :
|
||||
'Roll max(2d100) for ' + attr.name"
|
||||
:title="attr.key === 'au' ? $t('characters.attributes.rollTooltipAu') :
|
||||
$t('characters.attributes.rollTooltipOther') + ' ' + $t(`characters.attributes.${attr.key}`)"
|
||||
>
|
||||
🎲
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="attribute-description">{{ attr.description }}</span>
|
||||
<span class="attribute-description">{{ $t(`characters.attributes.${attr.key}Description`) }}</span>
|
||||
<!-- Race restriction warning for AU -->
|
||||
<div v-if="attr.key === 'au' && auRaceRestriction" class="race-restriction-warning">
|
||||
⚠️ {{ auRaceRestriction.message }}
|
||||
⚠️ {{ $t(`characters.attributes.raceRestriction${auRaceRestriction.raceKey}`) }}
|
||||
</div>
|
||||
<div v-if="lastAttributeRoll && lastAttributeRoll.attribute === attr.key" class="roll-result">
|
||||
{{ attr.name }}: {{ lastAttributeRoll.roll }}
|
||||
@@ -54,22 +54,22 @@
|
||||
|
||||
<div class="attribute-summary">
|
||||
<div class="total-points">
|
||||
<strong>Total Points: {{ totalPoints }}</strong>
|
||||
<strong>{{ $t('characters.attributes.totalPoints') }}: {{ totalPoints }}</strong>
|
||||
</div>
|
||||
<div class="average-points">
|
||||
<strong>Average: {{ averagePoints.toFixed(1) }}</strong>
|
||||
<strong>{{ $t('characters.attributes.averagePoints') }}: {{ averagePoints.toFixed(1) }}</strong>
|
||||
</div>
|
||||
<button type="button" @click="rollAllAttributes" class="roll-all-btn">
|
||||
🎲 Roll All Attributes
|
||||
🎲 {{ $t('characters.attributes.rollAllAttributes') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="button" @click="handlePrevious" class="prev-btn">
|
||||
← Previous: Basic Info
|
||||
← {{ $t('characters.attributes.previousBasicInfo') }}
|
||||
</button>
|
||||
<button type="submit" class="next-btn" :disabled="!isValid">
|
||||
Next: Derived Values →
|
||||
{{ $t('characters.attributes.nextDerivedValues') }} →
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -93,7 +93,7 @@
|
||||
<div class="overlay-result">
|
||||
→ {{ lastAttributeRoll.attributeName }}: {{ lastAttributeRoll.result }}
|
||||
</div>
|
||||
<div class="overlay-hint">Click to close</div>
|
||||
<div class="overlay-hint">{{ $t('characters.attributes.clickToClose') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,13 +112,13 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
st: 50, // Stärke
|
||||
gs: 50, // Geschicklichkeit
|
||||
gw: 50, // Gewandtheit
|
||||
ko: 50, // Konstitution
|
||||
in: 50, // Intelligenz
|
||||
zt: 50, // Zaubertalent
|
||||
au: 50, // Ausehen
|
||||
st: 0, // Stärke
|
||||
gs: 0, // Geschicklichkeit
|
||||
gw: 0, // Gewandtheit
|
||||
ko: 0, // Konstitution
|
||||
in: 0, // Intelligenz
|
||||
zt: 0, // Zaubertalent
|
||||
au: 0, // Ausehen
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
@@ -165,7 +165,26 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
isValid() {
|
||||
return Object.values(this.formData).every(val => val >= 1 && val <= 100)
|
||||
// Check basic value range (1-100) for only the defined attributes
|
||||
const definedKeys = this.attributes.map(attr => attr.key)
|
||||
const relevantValues = definedKeys.map(key => this.formData[key])
|
||||
const basicValid = relevantValues.every(val => val >= 1 && val <= 100)
|
||||
|
||||
if (!basicValid) return false
|
||||
|
||||
// Check race-specific AU restrictions
|
||||
const race = this.sessionData.rasse || ''
|
||||
const auValue = this.formData.au
|
||||
|
||||
if (race === 'Elfen' && auValue < 81) {
|
||||
return false // Elfen must have AU ≥ 81
|
||||
}
|
||||
|
||||
if ((race === 'Gnome' || race === 'Zwerge') && auValue > 80) {
|
||||
return false // Gnome/Zwerge must have AU ≤ 80
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
averagePoints() {
|
||||
return this.totalPoints / Object.keys(this.formData).length
|
||||
@@ -173,11 +192,11 @@ export default {
|
||||
auRaceRestriction() {
|
||||
const race = this.sessionData.rasse || ''
|
||||
if (race === 'Elfen') {
|
||||
return { type: 'minimum', value: 81, message: 'Elfen must have AU ≥ 81' }
|
||||
return { type: 'minimum', value: 81, raceKey: 'Elves' }
|
||||
} else if (race === 'Gnome') {
|
||||
return { type: 'maximum', value: 80, message: 'Gnome must have AU ≤ 80' }
|
||||
return { type: 'maximum', value: 80, raceKey: 'Gnomes' }
|
||||
} else if (race === 'Zwerge') {
|
||||
return { type: 'maximum', value: 80, message: 'Zwerge must have AU ≤ 80' }
|
||||
return { type: 'maximum', value: 80, raceKey: 'Dwarves' }
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -196,6 +215,11 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleAttributeChange(event) {
|
||||
// Simple update - Vue's reactivity should handle the rest
|
||||
this.updateTotal()
|
||||
},
|
||||
|
||||
updateTotal() {
|
||||
this.totalPoints = Object.values(this.formData).reduce((sum, val) => sum + (val || 0), 0)
|
||||
},
|
||||
@@ -317,7 +341,7 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.attributes-form {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
@@ -506,4 +530,5 @@ export default {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<h2>{{ $t('characters.basicInfo.title') }}</h2>
|
||||
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="form-row">
|
||||
<!-- 1. Name -->
|
||||
<div class="form-group">
|
||||
<label for="name">{{ $t('characters.basicInfo.characterName') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<input
|
||||
@@ -16,7 +18,46 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 2. Herkunft -->
|
||||
<div class="form-group">
|
||||
<label for="herkunft">{{ $t('characters.basicInfo.origin') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<select id="herkunft" v-model="formData.herkunft" required>
|
||||
<option value="">{{ $t('characters.basicInfo.selectOrigin') }}</option>
|
||||
<option v-for="origin in origins" :key="origin" :value="origin">{{ origin }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. Glaube -->
|
||||
<div class="form-group">
|
||||
<label for="glaube">{{ $t('characters.basicInfo.religion') }}</label>
|
||||
<div class="belief-search">
|
||||
<input
|
||||
id="glaube"
|
||||
v-model="beliefSearch"
|
||||
type="text"
|
||||
:placeholder="$t('characters.basicInfo.religionPlaceholder')"
|
||||
@input="searchBeliefs"
|
||||
/>
|
||||
<div v-if="beliefResults.length > 0" class="belief-dropdown">
|
||||
<div
|
||||
v-for="belief in beliefResults"
|
||||
:key="belief"
|
||||
class="belief-option"
|
||||
@click="selectBelief(belief)"
|
||||
>
|
||||
{{ belief }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="formData.glaube" class="selected-belief">
|
||||
{{ $t('characters.basicInfo.selected') }}: {{ formData.glaube }}
|
||||
<button type="button" @click="clearBelief" class="clear-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<!-- 4. Geschlecht -->
|
||||
<div class="form-group">
|
||||
<label for="geschlecht">{{ $t('characters.basicInfo.gender') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<select id="geschlecht" v-model="formData.geschlecht" required>
|
||||
@@ -26,6 +67,7 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 5. Rasse -->
|
||||
<div class="form-group">
|
||||
<label for="rasse">{{ $t('characters.basicInfo.race') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<select id="rasse" v-model="formData.rasse" required>
|
||||
@@ -36,6 +78,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<!-- 6. Charakterklasse -->
|
||||
<div class="form-group">
|
||||
<label for="typ">{{ $t('characters.basicInfo.characterClass') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<select id="typ" v-model="formData.typ" required>
|
||||
@@ -44,24 +87,7 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="herkunft">{{ $t('characters.basicInfo.origin') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<select id="herkunft" v-model="formData.herkunft" required>
|
||||
<option value="">{{ $t('characters.basicInfo.selectOrigin') }}</option>
|
||||
<option v-for="origin in origins" :key="origin" :value="origin">{{ origin }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="herkunft">{{ $t('characters.basicInfo.origin') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<select id="herkunft" v-model="formData.herkunft" required>
|
||||
<option value="">{{ $t('characters.basicInfo.selectOrigin') }}</option>
|
||||
<option v-for="origin in origins" :key="origin" :value="origin">{{ origin }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 7. Sozialschicht -->
|
||||
<div class="form-group">
|
||||
<label for="stand">{{ $t('characters.basicInfo.socialClass') }} {{ $t('characters.basicInfo.required') }}</label>
|
||||
<div class="input-with-dice">
|
||||
@@ -92,33 +118,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="glaube">{{ $t('characters.basicInfo.religion') }}</label>
|
||||
<div class="belief-search">
|
||||
<input
|
||||
id="glaube"
|
||||
v-model="beliefSearch"
|
||||
type="text"
|
||||
:placeholder="$t('characters.basicInfo.religionPlaceholder')"
|
||||
@input="searchBeliefs"
|
||||
/>
|
||||
<div v-if="beliefResults.length > 0" class="belief-dropdown">
|
||||
<div
|
||||
v-for="belief in beliefResults"
|
||||
:key="belief"
|
||||
class="belief-option"
|
||||
@click="selectBelief(belief)"
|
||||
>
|
||||
{{ belief }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="formData.glaube" class="selected-belief">
|
||||
{{ $t('characters.basicInfo.selected') }}: {{ formData.glaube }}
|
||||
<button type="button" @click="clearBelief" class="clear-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="next-btn" :disabled="!isValid">
|
||||
{{ $t('characters.basicInfo.nextAttributes') }}
|
||||
@@ -493,4 +492,118 @@ input:focus, select:focus {
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Social class roll styles */
|
||||
.input-with-dice {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input-with-dice select {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dice-btn {
|
||||
padding: 10px 12px;
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
transition: background-color 0.3s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dice-btn:hover:not(:disabled) {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.dice-btn:disabled {
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.roll-result {
|
||||
margin-top: 8px;
|
||||
padding: 8px;
|
||||
background-color: #e8f5e8;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
/* Roll overlay styles */
|
||||
.roll-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10000;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.roll-overlay-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
cursor: default;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.overlay-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 15px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.overlay-close:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.overlay-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.overlay-roll {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
color: #4caf50;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.roll-breakdown {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.overlay-result {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #2196f3;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.overlay-hint {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-top: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -251,6 +251,40 @@ export default {
|
||||
volk: 'Volk',
|
||||
unfrei: 'Unfrei'
|
||||
},
|
||||
attributes: {
|
||||
title: 'Charakterattribute',
|
||||
instruction: 'Setzen Sie die Grundattribute für Ihren Charakter (1-100)',
|
||||
totalPoints: 'Gesamtpunkte',
|
||||
averagePoints: 'Durchschnitt',
|
||||
rollAllAttributes: 'Alle Attribute würfeln',
|
||||
previousBasicInfo: 'Zurück: Grundinformationen',
|
||||
nextDerivedValues: 'Weiter: Abgeleitete Werte',
|
||||
enabled: 'AKTIVIERT',
|
||||
disabled: 'DEAKTIVIERT',
|
||||
clickToClose: 'Klicken zum Schließen',
|
||||
// Einzelne Attribute
|
||||
st: 'Stärke',
|
||||
stDescription: 'Körperliche Kraft und Stärke',
|
||||
gs: 'Geschicklichkeit',
|
||||
gsDescription: 'Geschicklichkeit und manuelle Fertigkeiten',
|
||||
gw: 'Gewandtheit',
|
||||
gwDescription: 'Beweglichkeit und schnelle Reaktionen',
|
||||
ko: 'Konstitution',
|
||||
koDescription: 'Gesundheit und Ausdauer',
|
||||
in: 'Intelligenz',
|
||||
inDescription: 'Lernfähigkeit und Logik',
|
||||
zt: 'Zaubertalent',
|
||||
ztDescription: 'Magisches Talent und Mana',
|
||||
au: 'Aussehen',
|
||||
auDescription: 'Schönheit und Aussehen (Rassenbeschränkungen: Elfen ≥81, Gnome/Zwerge ≤80)',
|
||||
// Rassenbeschränkungen
|
||||
raceRestrictionElves: 'Elfen müssen Aussehen ≥ 81 haben',
|
||||
raceRestrictionGnomes: 'Gnome müssen Aussehen ≤ 80 haben',
|
||||
raceRestrictionDwarves: 'Zwerge müssen Aussehen ≤ 80 haben',
|
||||
// Würfel-Tooltips
|
||||
rollTooltipAu: 'Würfle Aussehen: 1d100 mit Rassenbeschränkungen (Elfen ≥81, Gnome/Zwerge ≤80)',
|
||||
rollTooltipOther: 'Würfle max(2d100) für'
|
||||
},
|
||||
derivedValues: {
|
||||
title: 'Abgeleitete Werte',
|
||||
instruction: 'Diese Werte werden aus Ihren Attributen berechnet. Sie können sie nach Bedarf anpassen.',
|
||||
|
||||
@@ -157,6 +157,40 @@ export default {
|
||||
volk: 'Common Folk',
|
||||
unfrei: 'Unfree'
|
||||
},
|
||||
attributes: {
|
||||
title: 'Character Attributes',
|
||||
instruction: 'Set the basic attributes for your character (1-100)',
|
||||
totalPoints: 'Total Points',
|
||||
averagePoints: 'Average',
|
||||
rollAllAttributes: 'Roll All Attributes',
|
||||
previousBasicInfo: 'Previous: Basic Info',
|
||||
nextDerivedValues: 'Next: Derived Values',
|
||||
enabled: 'ENABLED',
|
||||
disabled: 'DISABLED',
|
||||
clickToClose: 'Click to close',
|
||||
// Individual attributes
|
||||
st: 'Strength',
|
||||
stDescription: 'Physical strength and power',
|
||||
gs: 'Dexterity',
|
||||
gsDescription: 'Dexterity and manual skill',
|
||||
gw: 'Agility',
|
||||
gwDescription: 'Agility and quick reactions',
|
||||
ko: 'Constitution',
|
||||
koDescription: 'Health and endurance',
|
||||
in: 'Intelligence',
|
||||
inDescription: 'Learning ability and logic',
|
||||
zt: 'Spell Talent',
|
||||
ztDescription: 'Magical talent and mana',
|
||||
au: 'Beauty',
|
||||
auDescription: 'Beauty and appearance (Race restrictions: Elves ≥81, Gnomes/Dwarves ≤80)',
|
||||
// Race restrictions
|
||||
raceRestrictionElves: 'Elves must have Beauty ≥ 81',
|
||||
raceRestrictionGnomes: 'Gnomes must have Beauty ≤ 80',
|
||||
raceRestrictionDwarves: 'Dwarves must have Beauty ≤ 80',
|
||||
// Roll tooltips
|
||||
rollTooltipAu: 'Roll Beauty: 1d100 with race restrictions (Elves ≥81, Gnomes/Dwarves ≤80)',
|
||||
rollTooltipOther: 'Roll max(2d100) for'
|
||||
},
|
||||
derivedValues: {
|
||||
title: 'Derived Values',
|
||||
instruction: 'These values are calculated from your attributes. You can adjust them as needed.',
|
||||
|
||||
Reference in New Issue
Block a user