Komplexe berechnungen am Frontend und backend
This commit is contained in:
@@ -18,17 +18,14 @@
|
||||
required
|
||||
/>
|
||||
<button
|
||||
v-if="value.key === 'pa' || value.key === 'wk' || value.key === 'lp_max'"
|
||||
v-if="value.key === 'pa' || value.key === 'wk' || value.key === 'lp_max' || value.key === 'ap_max' || value.key === 'b_max'"
|
||||
type="button"
|
||||
class="dice-btn"
|
||||
@click="value.key === 'pa' ? rollPA() :
|
||||
value.key === 'wk' ? rollWK() :
|
||||
value.key === 'lp_max' ? rollLP() : null"
|
||||
:title="value.key === 'pa' ? 'Roll PA: 1d100 + 4×(In/10) - 20' :
|
||||
value.key === 'wk' ? 'Roll WK: 1d100 + 2×(Ko/10 + In/10) - 20' :
|
||||
value.key === 'lp_max' ? 'Roll LP: 1d3 + 7 + (Ko/10)' : ''"
|
||||
@click="rollField(value.key)"
|
||||
:title="getDiceTooltip(value.key)"
|
||||
:disabled="isCalculating"
|
||||
>
|
||||
🎲
|
||||
{{ isCalculating ? '⏳' : '🎲' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="value-info">
|
||||
@@ -61,8 +58,8 @@
|
||||
<button type="button" @click="handlePrevious" class="prev-btn">
|
||||
← {{ $t('characters.derivedValues.previousAttributes') }}
|
||||
</button>
|
||||
<button type="button" @click="recalculate" class="calc-btn">
|
||||
{{ $t('characters.derivedValues.recalculate') }}
|
||||
<button type="button" @click="calculateAllStatic" class="calc-btn" :disabled="isCalculating">
|
||||
{{ isCalculating ? $t('characters.derivedValues.calculating') : $t('characters.derivedValues.recalculate') }}
|
||||
</button>
|
||||
<button type="submit" class="next-btn" :disabled="!isValid">
|
||||
{{ $t('characters.derivedValues.nextSkills') }} →
|
||||
@@ -73,6 +70,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import API from '../../utils/api'
|
||||
import { rollDie, rollDice } from '../../utils/randomUtils'
|
||||
|
||||
export default {
|
||||
name: 'CharacterDerivedValues',
|
||||
props: {
|
||||
@@ -85,27 +85,28 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
pa: 50, // Persönliche Ausstrahlung
|
||||
wk: 50, // Willenskraft
|
||||
lp_max: 20,
|
||||
ap_max: 20,
|
||||
b_max: 50,
|
||||
resistenz_koerper: 50, // Resistenz Körper
|
||||
resistenz_geist: 50, // Resistenz Geist
|
||||
pa: 0, // Persönliche Ausstrahlung
|
||||
wk: 0, // Willenskraft
|
||||
lp_max: 0,
|
||||
ap_max: 0,
|
||||
b_max: 0,
|
||||
resistenz_koerper: 0, // Resistenz Körper
|
||||
resistenz_geist: 0, // Resistenz Geist
|
||||
resistenz_bonus_koerper: 0, // Resistenz Bonus Körper
|
||||
resistenz_bonus_geist: 0, // Resistenz Bonus Geist
|
||||
abwehr: 50, // Abwehr
|
||||
abwehr: 0, // Abwehr
|
||||
abwehr_bonus: 0, // Abwehr Bonus
|
||||
ausdauer_bonus: 0, // Ausdauer Bonus
|
||||
angriffs_bonus: 0, // Angriffs Bonus
|
||||
zaubern: 50, // Zaubern
|
||||
zaubern: 0, // Zaubern
|
||||
zauber_bonus: 0, // Zauber Bonus
|
||||
raufen: 50, // Raufen
|
||||
raufen: 0, // Raufen
|
||||
schadens_bonus: 0, // Schadens Bonus
|
||||
sg: 1, // Schicksalsgunst
|
||||
gg: 1, // Göttliche Gnade
|
||||
gp: 1, // Glückspunkte
|
||||
sg: 0, // Schicksalsgunst
|
||||
gg: 0, // Göttliche Gnade
|
||||
gp: 0, // Glückspunkte
|
||||
},
|
||||
isCalculating: false,
|
||||
derivedValues: [
|
||||
{
|
||||
key: 'pa',
|
||||
@@ -126,7 +127,7 @@ export default {
|
||||
name: 'characters.derivedValues.lpMax',
|
||||
description: 'characters.derivedValues.lpMaxDescription',
|
||||
min: 1,
|
||||
max: 200
|
||||
max: 50
|
||||
},
|
||||
{
|
||||
key: 'ap_max',
|
||||
@@ -140,49 +141,49 @@ export default {
|
||||
name: 'characters.derivedValues.bMax',
|
||||
description: 'characters.derivedValues.bMaxDescription',
|
||||
min: 1,
|
||||
max: 500
|
||||
max: 50
|
||||
},
|
||||
{
|
||||
key: 'resistenz_koerper',
|
||||
name: 'characters.derivedValues.resistenzKoerper',
|
||||
description: 'characters.derivedValues.resistenzKoerperDescription',
|
||||
min: 1,
|
||||
max: 100
|
||||
max: 20
|
||||
},
|
||||
{
|
||||
key: 'resistenz_geist',
|
||||
name: 'characters.derivedValues.resistenzGeist',
|
||||
description: 'characters.derivedValues.resistenzGeistDescription',
|
||||
min: 1,
|
||||
max: 100
|
||||
max: 20
|
||||
},
|
||||
{
|
||||
key: 'resistenz_bonus_koerper',
|
||||
name: 'characters.derivedValues.resistenzBonusKoerper',
|
||||
description: 'characters.derivedValues.resistenzBonusKoerperDescription',
|
||||
min: -50,
|
||||
max: 50
|
||||
min: -5,
|
||||
max: 5
|
||||
},
|
||||
{
|
||||
key: 'resistenz_bonus_geist',
|
||||
name: 'characters.derivedValues.resistenzBonusGeist',
|
||||
description: 'characters.derivedValues.resistenzBonusGeistDescription',
|
||||
min: -50,
|
||||
max: 50
|
||||
min: -5,
|
||||
max: 5
|
||||
},
|
||||
{
|
||||
key: 'abwehr',
|
||||
name: 'characters.derivedValues.abwehr',
|
||||
description: 'characters.derivedValues.abwehrDescription',
|
||||
min: 1,
|
||||
max: 100
|
||||
max: 20
|
||||
},
|
||||
{
|
||||
key: 'abwehr_bonus',
|
||||
name: 'characters.derivedValues.abwehrBonus',
|
||||
description: 'characters.derivedValues.abwehrBonusDescription',
|
||||
min: -50,
|
||||
max: 50
|
||||
min: -5,
|
||||
max: 5
|
||||
},
|
||||
{
|
||||
key: 'ausdauer_bonus',
|
||||
@@ -195,57 +196,57 @@ export default {
|
||||
key: 'angriffs_bonus',
|
||||
name: 'characters.derivedValues.angriffsBonus',
|
||||
description: 'characters.derivedValues.angriffsBonusDescription',
|
||||
min: -50,
|
||||
max: 50
|
||||
min: -5,
|
||||
max: 5
|
||||
},
|
||||
{
|
||||
key: 'zaubern',
|
||||
name: 'characters.derivedValues.zaubern',
|
||||
description: 'characters.derivedValues.zaubernDescription',
|
||||
min: 1,
|
||||
max: 100
|
||||
max: 20
|
||||
},
|
||||
{
|
||||
key: 'zauber_bonus',
|
||||
name: 'characters.derivedValues.zauberBonus',
|
||||
description: 'characters.derivedValues.zauberBonusDescription',
|
||||
min: -50,
|
||||
max: 50
|
||||
min: -5,
|
||||
max: 5
|
||||
},
|
||||
{
|
||||
key: 'raufen',
|
||||
name: 'characters.derivedValues.raufen',
|
||||
description: 'characters.derivedValues.raufenDescription',
|
||||
min: 1,
|
||||
max: 100
|
||||
max: 20
|
||||
},
|
||||
{
|
||||
key: 'schadens_bonus',
|
||||
name: 'characters.derivedValues.schadensBonus',
|
||||
description: 'characters.derivedValues.schadensBonusDescription',
|
||||
min: -50,
|
||||
max: 50
|
||||
min: -10,
|
||||
max: 10
|
||||
},
|
||||
{
|
||||
key: 'sg',
|
||||
name: 'characters.derivedValues.sg',
|
||||
description: 'characters.derivedValues.sgDescription',
|
||||
min: 0,
|
||||
max: 10
|
||||
max: 50
|
||||
},
|
||||
{
|
||||
key: 'gg',
|
||||
name: 'characters.derivedValues.gg',
|
||||
description: 'characters.derivedValues.ggDescription',
|
||||
min: 0,
|
||||
max: 10
|
||||
max: 50
|
||||
},
|
||||
{
|
||||
key: 'gp',
|
||||
name: 'characters.derivedValues.gp',
|
||||
description: 'characters.derivedValues.gpDescription',
|
||||
min: 0,
|
||||
max: 10
|
||||
max: 50
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -259,43 +260,161 @@ export default {
|
||||
},
|
||||
|
||||
calculatedValues() {
|
||||
const attrs = this.sessionData.attributes || {}
|
||||
const wkValue = this.formData?.wk || this.calculateWK(attrs.ko || 50, attrs.in || 50)
|
||||
|
||||
return {
|
||||
pa: this.calculatePA(attrs.in || 50),
|
||||
wk: this.calculateWK(attrs.ko || 50, attrs.in || 50),
|
||||
lp_max: this.calculateLP(attrs.ko || 50),
|
||||
ap_max: Math.floor(((attrs.au || 50) + wkValue) / 2) + 5,
|
||||
b_max: (attrs.st || 50) + 10,
|
||||
resistenz_koerper: attrs.ko || 50, // Resistenz Körper = Konstitution
|
||||
resistenz_geist: wkValue, // Resistenz Geist = Willenskraft
|
||||
resistenz_bonus_koerper: Math.floor((attrs.ko || 50) / 20) - 2, // Bonus basierend auf Ko
|
||||
resistenz_bonus_geist: Math.floor(wkValue / 20) - 2, // Bonus basierend auf WK
|
||||
abwehr: Math.floor(((attrs.gw || 50) + (attrs.gs || 50)) / 2), // Abwehr = (Gewandtheit + Geschicklichkeit) / 2
|
||||
abwehr_bonus: Math.floor(((attrs.gw || 50) + (attrs.gs || 50)) / 40) - 2, // Abwehr Bonus
|
||||
ausdauer_bonus: Math.floor((attrs.ko || 50) / 20) - 2, // Ausdauer Bonus basierend auf Ko
|
||||
angriffs_bonus: Math.floor((attrs.gs || 50) / 20) - 2, // Angriffs Bonus basierend auf Gs
|
||||
zaubern: attrs.zt || 50, // Zaubern = Zaubertalent
|
||||
zauber_bonus: Math.floor((attrs.zt || 50) / 20) - 2, // Zauber Bonus
|
||||
raufen: Math.floor(((attrs.st || 50) + (attrs.gw || 50)) / 2), // Raufen = (Stärke + Gewandtheit) / 2
|
||||
schadens_bonus: Math.floor((attrs.st || 50) / 20) - 2, // Schadens Bonus basierend auf St
|
||||
sg: this.getClassBonnie('sg'),
|
||||
gg: this.getClassBonnie('gg'),
|
||||
gp: this.getClassBonnie('gp'),
|
||||
}
|
||||
// Return currently loaded values or defaults
|
||||
// The actual calculation happens via API calls
|
||||
return this.formData
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
formData: {
|
||||
handler(newValue) {
|
||||
// Save changes automatically when form data changes
|
||||
this.$emit('save', { derived_values: newValue })
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Initialize with calculated values first
|
||||
this.formData = { ...this.calculatedValues }
|
||||
|
||||
// Then override with session data if available
|
||||
// Initialize with existing session data if available
|
||||
if (this.sessionData.derived_values && Object.keys(this.sessionData.derived_values).length > 0) {
|
||||
this.formData = { ...this.formData, ...this.sessionData.derived_values }
|
||||
} else {
|
||||
// Calculate initial values using new API
|
||||
this.calculateAllStatic()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async calculateAllStatic() {
|
||||
if (this.isCalculating) return
|
||||
|
||||
this.isCalculating = true
|
||||
try {
|
||||
const attrs = this.sessionData.attributes || {}
|
||||
const basic = this.sessionData.basic_info || {}
|
||||
const token = localStorage.getItem('token')
|
||||
|
||||
const response = await API.post('/api/characters/calculate-static-fields', {
|
||||
st: attrs.st || 0,
|
||||
gs: attrs.gs || 0,
|
||||
gw: attrs.gw || 0,
|
||||
ko: attrs.ko || 0,
|
||||
in: attrs.in || 0,
|
||||
zt: attrs.zt || 0,
|
||||
au: attrs.au || 0,
|
||||
rasse: basic.rasse || 'Menschen',
|
||||
typ: basic.typ || 'Barbar'
|
||||
}, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
|
||||
const staticValues = response.data
|
||||
|
||||
// Update form data with calculated static values
|
||||
this.formData = {
|
||||
...this.formData,
|
||||
ausdauer_bonus: staticValues.ausdauer_bonus,
|
||||
schadens_bonus: staticValues.schadens_bonus,
|
||||
angriffs_bonus: staticValues.angriffs_bonus,
|
||||
abwehr_bonus: staticValues.abwehr_bonus,
|
||||
zauber_bonus: staticValues.zauber_bonus,
|
||||
resistenz_bonus_koerper: staticValues.resistenz_bonus_koerper,
|
||||
resistenz_bonus_geist: staticValues.resistenz_bonus_geist,
|
||||
resistenz_koerper: staticValues.resistenz_koerper,
|
||||
resistenz_geist: staticValues.resistenz_geist,
|
||||
abwehr: staticValues.abwehr,
|
||||
zaubern: staticValues.zaubern,
|
||||
raufen: staticValues.raufen
|
||||
}
|
||||
|
||||
// Save the updated values to session
|
||||
this.$emit('save', { derived_values: this.formData })
|
||||
} catch (error) {
|
||||
console.error('Error calculating static values:', error)
|
||||
} finally {
|
||||
this.isCalculating = false
|
||||
}
|
||||
},
|
||||
|
||||
async rollField(fieldName) {
|
||||
if (this.isCalculating) return
|
||||
|
||||
this.isCalculating = true
|
||||
try {
|
||||
const attrs = this.sessionData.attributes || {}
|
||||
const basic = this.sessionData.basic_info || {}
|
||||
const token = localStorage.getItem('token')
|
||||
|
||||
// Generate dice roll based on field type
|
||||
let roll
|
||||
switch (fieldName) {
|
||||
case 'pa':
|
||||
case 'wk':
|
||||
roll = rollDie(100) // 1d100
|
||||
break
|
||||
case 'lp_max':
|
||||
roll = rollDie(3) // 1d3 - single number
|
||||
break
|
||||
case 'ap_max':
|
||||
roll = rollDie(3) // 1d3 - array of 3 values
|
||||
break
|
||||
case 'b_max':
|
||||
// B Max depends on race: Gnome/Halblinge=2d3, Zwerge=3d3, others=4d3
|
||||
let diceCount = 4 // default for most races
|
||||
if (basic.rasse === 'Gnome' || basic.rasse === 'Halblinge') {
|
||||
diceCount = 2
|
||||
} else if (basic.rasse === 'Zwerge') {
|
||||
diceCount = 3
|
||||
}
|
||||
roll = rollDice(diceCount, 3) // XdY where X depends on race, Y=3
|
||||
break
|
||||
}
|
||||
|
||||
const response = await API.post('/api/characters/calculate-rolled-field', {
|
||||
st: attrs.st || 0,
|
||||
gs: attrs.gs || 0,
|
||||
gw: attrs.gw || 0,
|
||||
ko: attrs.ko || 0,
|
||||
in: attrs.in || 0,
|
||||
zt: attrs.zt || 0,
|
||||
au: attrs.au || 0,
|
||||
rasse: basic.rasse || 'Menschen',
|
||||
typ: basic.typ || 'Barbar',
|
||||
field: fieldName,
|
||||
roll: roll
|
||||
}, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
|
||||
const result = response.data
|
||||
this.formData[fieldName] = result.value
|
||||
|
||||
// Save the updated values to session
|
||||
this.$emit('save', { derived_values: this.formData })
|
||||
} catch (error) {
|
||||
console.error('Error calculating rolled field:', error)
|
||||
} finally {
|
||||
this.isCalculating = false
|
||||
}
|
||||
},
|
||||
|
||||
getDiceTooltip(fieldName) {
|
||||
switch (fieldName) {
|
||||
case 'pa':
|
||||
return this.$t('characters.derivedValues.paRollTooltip')
|
||||
case 'wk':
|
||||
return this.$t('characters.derivedValues.wkRollTooltip')
|
||||
case 'lp_max':
|
||||
return this.$t('characters.derivedValues.lpRollTooltip')
|
||||
case 'ap_max':
|
||||
return this.$t('characters.derivedValues.apRollTooltip')
|
||||
case 'b_max':
|
||||
return this.$t('characters.derivedValues.bRollTooltip')
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
},
|
||||
|
||||
// Legacy methods for backward compatibility
|
||||
calculateLP(constitution) {
|
||||
// LP = 1d3 + 7 + (Ko/10)
|
||||
const diceRoll = Math.floor(Math.random() * 3) + 1 // 1d3
|
||||
@@ -323,33 +442,30 @@ export default {
|
||||
},
|
||||
|
||||
rollLP() {
|
||||
const attrs = this.sessionData.attributes || {}
|
||||
this.formData.lp_max = this.calculateLP(attrs.ko || 50)
|
||||
this.rollField('lp_max')
|
||||
},
|
||||
|
||||
rollPA() {
|
||||
const attrs = this.sessionData.attributes || {}
|
||||
this.formData.pa = this.calculatePA(attrs.in || 50)
|
||||
this.rollField('pa')
|
||||
},
|
||||
|
||||
rollWK() {
|
||||
const attrs = this.sessionData.attributes || {}
|
||||
this.formData.wk = this.calculateWK(attrs.ko || 50, attrs.in || 50)
|
||||
this.rollField('wk')
|
||||
},
|
||||
|
||||
getClassBonnie(type) {
|
||||
// TODO: Implement class-specific bonnie calculations
|
||||
// For now, return base values
|
||||
const bonnieMap = {
|
||||
'sg': 1,
|
||||
'gg': 1,
|
||||
'gp': 1,
|
||||
'sg': 0,
|
||||
'gg': 0,
|
||||
'gp': 0,
|
||||
}
|
||||
return bonnieMap[type] || 1
|
||||
},
|
||||
|
||||
recalculate() {
|
||||
this.formData = { ...this.calculatedValues }
|
||||
this.calculateAllStatic()
|
||||
},
|
||||
|
||||
handlePrevious() {
|
||||
|
||||
+10
-4
@@ -294,10 +294,10 @@ export default {
|
||||
wkDescription: 'Mentale Widerstandsfähigkeit (Berechnung: 1d100 + 2×(Ko/10 + In/10) - 20)',
|
||||
lpMax: 'Lebenspunkte (LP) Maximum',
|
||||
lpMaxDescription: 'Maximale Lebens-/Gesundheitspunkte (Berechnung: 1d3 + 7 + Ko/10)',
|
||||
apMax: 'Abenteuerpunkte (AP) Maximum',
|
||||
apMax: 'Ausdauerpunkte (AP) Maximum',
|
||||
apMaxDescription: 'Maximale Abenteuerpunkte für spezielle Aktionen',
|
||||
bMax: 'Belastung (B) Maximum',
|
||||
bMaxDescription: 'Maximale Tragekapazität',
|
||||
bMax: 'Bewegungsweite (B)',
|
||||
bMaxDescription: 'Maximale Bewegungsweite (Berechnung: 1d6 + Modifikator je nach Rasse)',
|
||||
resistenzKoerper: 'Resistenz Körper',
|
||||
resistenzKoerperDescription: 'Körperliche Widerstandsfähigkeit (= Konstitution)',
|
||||
resistenzGeist: 'Resistenz Geist',
|
||||
@@ -340,7 +340,13 @@ export default {
|
||||
benniesDescription: 'Grundwerte basierend auf Charakterklasse',
|
||||
previousAttributes: 'Zurück: Attribute',
|
||||
recalculate: 'Aus Attributen neu berechnen',
|
||||
nextSkills: 'Weiter: Fertigkeiten & Zauber'
|
||||
calculating: 'Berechne...',
|
||||
nextSkills: 'Weiter: Fertigkeiten & Zauber',
|
||||
paRollTooltip: 'PA würfeln: 1d100 + 4×(In/10) - 20',
|
||||
wkRollTooltip: 'WK würfeln: 1d100 + 2×(Ko/10 + In/10) - 20',
|
||||
lpRollTooltip: 'LP würfeln: 1d3 + 7 + (Ko/10)',
|
||||
apRollTooltip: 'AP würfeln: 3d6 + Modifikator je nach Klasse',
|
||||
bRollTooltip: 'B würfeln: 1d6 + Modifikator je nach Rasse'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,7 +246,13 @@ export default {
|
||||
benniesDescription: 'Base values based on character class',
|
||||
previousAttributes: 'Previous: Attributes',
|
||||
recalculate: 'Recalculate from Attributes',
|
||||
nextSkills: 'Next: Skills & Spells'
|
||||
calculating: 'Calculating...',
|
||||
nextSkills: 'Next: Skills & Spells',
|
||||
paRollTooltip: 'Roll PA: 1d100 + 4×(In/10) - 20',
|
||||
wkRollTooltip: 'Roll WK: 1d100 + 2×(Ko/10 + In/10) - 20',
|
||||
lpRollTooltip: 'Roll LP: 1d3 + 7 + (Ko/10)',
|
||||
apRollTooltip: 'Roll AP: 3d6 + modifier based on class',
|
||||
bRollTooltip: 'Roll B: 1d6 + modifier based on race'
|
||||
}
|
||||
},
|
||||
common: {
|
||||
|
||||
Reference in New Issue
Block a user