Add reputation actions feature to Falukant module

- Introduced new endpoints for retrieving and executing reputation actions in FalukantController and falukantRouter.
- Implemented service methods in FalukantService to handle reputation actions, including daily limits and action execution logic.
- Updated the frontend ReputationView component to display available actions and their details, including cost and potential reputation gain.
- Added translations for reputation actions in both German and English locales.
- Enhanced initialization logic to set up reputation action types in the database.
This commit is contained in:
Torsten Schulz (local)
2025-12-21 21:09:31 +01:00
parent 38f23cc6ae
commit 38dd51f757
13 changed files with 594 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ import TitleOfNobility from "../../models/falukant/type/title_of_nobility.js";
import PartyType from "../../models/falukant/type/party.js";
import MusicType from "../../models/falukant/type/music.js";
import BanquetteType from "../../models/falukant/type/banquette.js";
import ReputationActionType from "../../models/falukant/type/reputation_action.js";
import VehicleType from "../../models/falukant/type/vehicle.js";
import LearnRecipient from "../../models/falukant/type/learn_recipient.js";
import PoliticalOfficeType from "../../models/falukant/type/political_office_type.js";
@@ -41,6 +42,7 @@ export const initializeFalukantTypes = async () => {
await initializeFalukantPartyTypes();
await initializeFalukantMusicTypes();
await initializeFalukantBanquetteTypes();
await initializeFalukantReputationActions();
await initializeLearnerTypes();
await initializePoliticalOfficeBenefitTypes();
await initializePoliticalOfficeTypes();
@@ -52,6 +54,55 @@ export const initializeFalukantTypes = async () => {
await initializeFalukantProductWeatherEffects();
};
const reputationActions = [
// Günstig / häufig: schnelle Abnutzung
{ tr: "soup_kitchen", cost: 500, baseGain: 2, decayFactor: 0.85, minGain: 0, decayWindowDays: 7 },
// Mittel: gesellschaftlich anerkannt
{ tr: "library_donation", cost: 5000, baseGain: 4, decayFactor: 0.88, minGain: 0, decayWindowDays: 7 },
{ tr: "scholarships", cost: 10000, baseGain: 5, decayFactor: 0.87, minGain: 0, decayWindowDays: 7 },
{ tr: "church_hospice", cost: 12000, baseGain: 5, decayFactor: 0.87, minGain: 0, decayWindowDays: 7 },
{ tr: "school_funding", cost: 15000, baseGain: 6, decayFactor: 0.88, minGain: 0, decayWindowDays: 7 },
// Großprojekte: teurer, langsamerer Rufverfall
{ tr: "orphanage_build", cost: 20000, baseGain: 7, decayFactor: 0.90, minGain: 0, decayWindowDays: 7 },
{ tr: "bridge_build", cost: 25000, baseGain: 7, decayFactor: 0.90, minGain: 0, decayWindowDays: 7 },
{ tr: "hospital_donation", cost: 30000, baseGain: 8, decayFactor: 0.90, minGain: 0, decayWindowDays: 7 },
{ tr: "patronage", cost: 40000, baseGain: 9, decayFactor: 0.91, minGain: 0, decayWindowDays: 7 },
{ tr: "statue_build", cost: 50000, baseGain: 10, decayFactor: 0.92, minGain: 0, decayWindowDays: 7 },
{ tr: "well_build", cost: 8000, baseGain: 4, decayFactor: 0.87, minGain: 0, decayWindowDays: 7 },
];
async function initializeFalukantReputationActions() {
// robustes Upsert ohne FK/Constraints-Ärger:
// - finde existierende nach tr
// - update bei Änderungen
// - create wenn fehlt
const existing = await ReputationActionType.findAll({ attributes: ['id', 'tr', 'cost', 'baseGain', 'decayFactor', 'minGain'] });
const existingByTr = new Map(existing.map(e => [e.tr, e]));
for (const a of reputationActions) {
const found = existingByTr.get(a.tr);
if (!found) {
await ReputationActionType.create(a);
continue;
}
const needsUpdate =
Number(found.cost) !== Number(a.cost) ||
Number(found.baseGain) !== Number(a.baseGain) ||
Number(found.decayFactor) !== Number(a.decayFactor) ||
Number(found.minGain) !== Number(a.minGain) ||
Number(found.decayWindowDays || 7) !== Number(a.decayWindowDays || 7);
if (needsUpdate) {
await found.update({
cost: a.cost,
baseGain: a.baseGain,
decayFactor: a.decayFactor,
minGain: a.minGain,
decayWindowDays: a.decayWindowDays ?? 7,
});
}
}
}
const regionTypes = [];
const regionTypeTrs = [
"country",