diff --git a/backend/controllers/adminController.js b/backend/controllers/adminController.js index 7443a24..2b722d9 100644 --- a/backend/controllers/adminController.js +++ b/backend/controllers/adminController.js @@ -389,13 +389,17 @@ class AdminController { try { const { userid: userId } = req.headers; const { regionIds, minAge, maxAge, minTitleId, maxTitleId, count } = req.body; + const countValue = parseInt(count) || 1; + if (countValue < 1 || countValue > 500) { + return res.status(400).json({ error: 'Count must be between 1 and 500' }); + } const result = await AdminService.createNPCs(userId, { regionIds: regionIds && regionIds.length > 0 ? regionIds : null, minAge: parseInt(minAge) || 0, maxAge: parseInt(maxAge) || 100, minTitleId: parseInt(minTitleId) || 1, maxTitleId: parseInt(maxTitleId) || 19, - count: parseInt(count) || 1 + count: countValue }); res.status(200).json(result); } catch (error) { diff --git a/backend/services/adminService.js b/backend/services/adminService.js index 35888da..44e067d 100644 --- a/backend/services/adminService.js +++ b/backend/services/adminService.js @@ -1156,75 +1156,78 @@ class AdminService { const genders = ['male', 'female']; const createdNPCs = []; + const totalNPCs = targetRegions.length * titles.length * count; // Erstelle NPCs in einer Transaktion + // Für jede Stadt-Titel-Kombination wird die angegebene Anzahl erstellt await sequelize.transaction(async (t) => { - for (let i = 0; i < count; i++) { - // Zufällige Region - const region = targetRegions[Math.floor(Math.random() * targetRegions.length)]; + for (const region of targetRegions) { + for (const title of titles) { + // Erstelle 'count' NPCs für diese Stadt-Titel-Kombination + for (let i = 0; i < count; i++) { + // Zufälliges Geschlecht + const gender = genders[Math.floor(Math.random() * genders.length)]; - // Zufälliges Geschlecht - const gender = genders[Math.floor(Math.random() * genders.length)]; + // Zufälliger Vorname + const firstName = await FalukantPredefineFirstname.findAll({ + where: { gender }, + order: sequelize.fn('RANDOM'), + limit: 1, + transaction: t + }); + if (firstName.length === 0) { + throw new Error(`No first names found for gender: ${gender}`); + } + const fnObj = firstName[0]; - // Zufälliger Vorname - const firstName = await FalukantPredefineFirstname.findAll({ - where: { gender }, - order: sequelize.fn('RANDOM'), - limit: 1, - transaction: t - }); - if (firstName.length === 0) { - throw new Error(`No first names found for gender: ${gender}`); + // Zufälliger Nachname + const lastName = await FalukantPredefineLastname.findAll({ + order: sequelize.fn('RANDOM'), + limit: 1, + transaction: t + }); + if (lastName.length === 0) { + throw new Error('No last names found'); + } + const lnObj = lastName[0]; + + // Zufälliges Alter (in Jahren, wird in Tage umgerechnet) + const randomAge = Math.floor(Math.random() * (maxAge - minAge + 1)) + minAge; + const birthdate = new Date(); + birthdate.setDate(birthdate.getDate() - randomAge); // 5 Tage = 5 Jahre alt + + // Erstelle den NPC-Charakter (ohne userId = NPC) + const npc = await FalukantCharacter.create({ + userId: null, // Wichtig: null = NPC + regionId: region.id, + firstName: fnObj.id, + lastName: lnObj.id, + gender: gender, + birthdate: birthdate, + titleOfNobility: title.id, + health: 100, + moodId: 1 + }, { transaction: t }); + + createdNPCs.push({ + id: npc.id, + firstName: fnObj.name, + lastName: lnObj.name, + gender: gender, + age: randomAge, + region: region.name, + title: title.labelTr + }); + } } - const fnObj = firstName[0]; - - // Zufälliger Nachname - const lastName = await FalukantPredefineLastname.findAll({ - order: sequelize.fn('RANDOM'), - limit: 1, - transaction: t - }); - if (lastName.length === 0) { - throw new Error('No last names found'); - } - const lnObj = lastName[0]; - - // Zufälliges Alter (in Jahren, wird in Tage umgerechnet) - const randomAge = Math.floor(Math.random() * (maxAge - minAge + 1)) + minAge; - const birthdate = new Date(); - birthdate.setDate(birthdate.getDate() - randomAge); // 5 Tage = 5 Jahre alt - - // Zufälliger Title - const title = titles[Math.floor(Math.random() * titles.length)]; - - // Erstelle den NPC-Charakter (ohne userId = NPC) - const npc = await FalukantCharacter.create({ - userId: null, // Wichtig: null = NPC - regionId: region.id, - firstName: fnObj.id, - lastName: lnObj.id, - gender: gender, - birthdate: birthdate, - titleOfNobility: title.id, - health: 100, - moodId: 1 - }, { transaction: t }); - - createdNPCs.push({ - id: npc.id, - firstName: fnObj.name, - lastName: lnObj.name, - gender: gender, - age: randomAge, - region: region.name, - title: title.labelTr - }); } }); return { success: true, count: createdNPCs.length, + countPerCombination: count, + totalCombinations: targetRegions.length * titles.length, npcs: createdNPCs }; } diff --git a/frontend/src/i18n/locales/de/admin.json b/frontend/src/i18n/locales/de/admin.json index 81db431..4c94ad0 100644 --- a/frontend/src/i18n/locales/de/admin.json +++ b/frontend/src/i18n/locales/de/admin.json @@ -122,18 +122,20 @@ "to": "bis", "years": "Jahre", "titleRange": "Titel-Bereich", - "count": "Anzahl", + "count": "Anzahl pro Stadt-Titel-Kombination", + "countHelp": "Diese Anzahl wird für jede Kombination aus gewählter Stadt und Titel erstellt.", "create": "NPCs erstellen", "creating": "Erstelle...", "result": "Ergebnis", "createdCount": "{count} NPCs wurden erstellt.", + "combinationInfo": "{perCombination} NPCs pro Kombination × {combinations} Kombinationen = {count} NPCs insgesamt", "age": "Alter", "errorLoadingRegions": "Fehler beim Laden der Städte.", "errorLoadingTitles": "Fehler beim Laden der Titel.", "errorCreating": "Fehler beim Erstellen der NPCs.", "invalidAgeRange": "Ungültiger Altersbereich.", "invalidTitleRange": "Ungültiger Titel-Bereich.", - "invalidCount": "Ungültige Anzahl (1-100)." + "invalidCount": "Ungültige Anzahl (1-500)." } }, "chatrooms": { diff --git a/frontend/src/i18n/locales/en/admin.json b/frontend/src/i18n/locales/en/admin.json index 43f823a..e1a4ff8 100644 --- a/frontend/src/i18n/locales/en/admin.json +++ b/frontend/src/i18n/locales/en/admin.json @@ -149,18 +149,20 @@ "to": "to", "years": "years", "titleRange": "Title Range", - "count": "Count", + "count": "Count per City-Title Combination", + "countHelp": "This count will be created for each combination of selected city and title.", "create": "Create NPCs", "creating": "Creating...", "result": "Result", "createdCount": "{count} NPCs have been created.", + "combinationInfo": "{perCombination} NPCs per combination × {combinations} combinations = {count} NPCs total", "age": "Age", "errorLoadingRegions": "Error loading cities.", "errorLoadingTitles": "Error loading titles.", "errorCreating": "Error creating NPCs.", "invalidAgeRange": "Invalid age range.", "invalidTitleRange": "Invalid title range.", - "invalidCount": "Invalid count (1-100)." + "invalidCount": "Invalid count (1-500)." } }, "chatrooms": { diff --git a/frontend/src/views/admin/falukant/CreateNPCView.vue b/frontend/src/views/admin/falukant/CreateNPCView.vue index 06fcc4e..ee7bba4 100644 --- a/frontend/src/views/admin/falukant/CreateNPCView.vue +++ b/frontend/src/views/admin/falukant/CreateNPCView.vue @@ -47,7 +47,8 @@
- + +
{{ $t('admin.falukant.createNPC.countHelp') }}
@@ -61,6 +62,13 @@

{{ $t('admin.falukant.createNPC.result') }}

{{ $t('admin.falukant.createNPC.createdCount', { count: result.count }) }}

+

+ {{ $t('admin.falukant.createNPC.combinationInfo', { + perCombination: result.countPerCombination, + combinations: result.totalCombinations, + total: result.count + }) }} +

{{ $t(`falukant.titles.${npc.gender}.${npc.title}`) }} {{ npc.firstName }} {{ npc.lastName }} @@ -142,7 +150,7 @@ export default { return; } - if (this.count < 1 || this.count > 100) { + if (this.count < 1 || this.count > 500) { this.error = this.$t('admin.falukant.createNPC.invalidCount'); return; } @@ -286,4 +294,17 @@ export default { border-radius: 4px; margin-top: 20px; } + +.help-text { + font-size: 0.9em; + color: #666; + margin-top: 5px; + font-style: italic; +} + +.info-text { + font-size: 0.9em; + color: #155724; + margin-top: 5px; +}