feat(politics): add new political office benefits and enhance database migration
All checks were successful
Deploy to production / deploy (push) Successful in 2m54s

- Introduced new benefits including 'reputation_periodic', 'appoint_politicians', 'set_regional_tax', 'free_lover_slots', 'guard_protection', and 'court_immunity' to the political office system.
- Updated database migration to add and remove the 'last_political_daily_salary_on' column using SQL queries for better performance.
- Enhanced localization files for multiple languages to support new benefits, improving user experience across the application.
- Updated UI components to display new benefits correctly in the PoliticsView, ensuring accurate representation of political office functionalities.
This commit is contained in:
Torsten Schulz (local)
2026-04-02 15:27:05 +02:00
parent 49713d957d
commit 5d06d97737
10 changed files with 303 additions and 19 deletions

View File

@@ -2,17 +2,10 @@
module.exports = { module.exports = {
up: async (queryInterface, Sequelize) => { up: async (queryInterface, Sequelize) => {
await queryInterface.addColumn( await queryInterface.sequelize.query(`
{ ALTER TABLE falukant_data.falukant_user
tableName: 'falukant_user', ADD COLUMN IF NOT EXISTS last_political_daily_salary_on date NULL;
schema: 'falukant_data' `);
},
'last_political_daily_salary_on',
{
type: Sequelize.DATEONLY,
allowNull: true
}
);
await queryInterface.sequelize.query(` await queryInterface.sequelize.query(`
DO $$ DO $$
@@ -51,13 +44,10 @@ module.exports = {
}, },
down: async (queryInterface, Sequelize) => { down: async (queryInterface, Sequelize) => {
await queryInterface.removeColumn( await queryInterface.sequelize.query(`
{ ALTER TABLE falukant_data.falukant_user
tableName: 'falukant_user', DROP COLUMN IF EXISTS last_political_daily_salary_on;
schema: 'falukant_data' `);
},
'last_political_daily_salary_on'
);
await queryInterface.sequelize.query(` await queryInterface.sequelize.query(`
DO $$ DO $$

View File

@@ -6101,6 +6101,25 @@ class FalukantService extends BaseService {
if (amount > 0) { if (amount > 0) {
out.push({ tr: 'daily_salary', params: { amount } }); out.push({ tr: 'daily_salary', params: { amount } });
} }
} else if (tr === 'reputation_periodic' || (tr === 'reputation' && (v.intervalDays != null || v.everyDays != null))) {
const intervalDays = Math.max(1, Number(v.intervalDays ?? v.everyDays ?? 7));
const gain = Math.max(1, Number(v.gain ?? v.reputationGain ?? 1));
out.push({ tr: 'reputation_periodic', params: { intervalDays, gain } });
} else if (tr === 'appoint_politicians' || (tr === 'influence' && Array.isArray(v.officeTrs) && v.officeTrs.length)) {
const officeTrs = Array.isArray(v.officeTrs) ? v.officeTrs.filter((x) => typeof x === 'string') : [];
if (officeTrs.length) {
out.push({ tr: 'appoint_politicians', params: { officeTrs } });
}
} else if (tr === 'set_regional_tax' || tr === 'set_regionl_tax') {
const scope = typeof v.scope === 'string' && v.scope ? v.scope : 'local';
out.push({ tr: 'set_regional_tax', params: { scope } });
} else if (tr === 'free_lover_slots') {
const count = Math.max(1, Number(v.count ?? 1));
out.push({ tr: 'free_lover_slots', params: { count } });
} else if (tr === 'guard_protection') {
out.push({ tr: 'guard_protection', params: {} });
} else if (tr === 'court_immunity') {
out.push({ tr: 'court_immunity', params: {} });
} else if (tr) { } else if (tr) {
out.push({ tr: 'generic_benefit', params: { code: tr } }); out.push({ tr: 'generic_benefit', params: { code: tr } });
} }

View File

@@ -0,0 +1,9 @@
-- Spalte für tägliches Politik-Gehalt (Sequelize: FalukantUser.lastPoliticalDailySalaryOn).
-- Entspricht Migration: backend/migrations/20260401120000-politics-benefits-and-daily-salary.cjs
--
-- Bevorzugt: Migration per CLI ausführen (führt auch die political_office_benefit-Anpassung aus).
-- Nur diese Spalte ohne CLI: dieses Skript einmal ausführen; die Migration nutzt ADD COLUMN IF NOT EXISTS
-- und kann danach trotzdem noch sauber durchlaufen.
ALTER TABLE falukant_data.falukant_user
ADD COLUMN IF NOT EXISTS last_political_daily_salary_on date NULL;

View File

@@ -0,0 +1,108 @@
-- =============================================================================
-- Zusätzliche politische Amtsvorteile (reputation_periodic, Ernennungen, Steuerkompetenz, …)
-- =============================================================================
-- Voraussetzung: falukant_political_office_benefits.sql (oder gleichwertiges Schema) ist angelegt.
-- Idempotent: mehrfach ausführbar.
--
-- Hinweis: Frische Dev-DBs bekommen dieselben Zeilen über initializePoliticalOfficeBenefits (Node).
INSERT INTO falukant_type.political_office_benefit_type (tr)
SELECT 'reputation_periodic' WHERE NOT EXISTS (SELECT 1 FROM falukant_type.political_office_benefit_type t WHERE t.tr = 'reputation_periodic');
INSERT INTO falukant_type.political_office_benefit_type (tr)
SELECT 'appoint_politicians' WHERE NOT EXISTS (SELECT 1 FROM falukant_type.political_office_benefit_type t WHERE t.tr = 'appoint_politicians');
INSERT INTO falukant_type.political_office_benefit_type (tr)
SELECT 'set_regional_tax' WHERE NOT EXISTS (SELECT 1 FROM falukant_type.political_office_benefit_type t WHERE t.tr = 'set_regional_tax');
INSERT INTO falukant_type.political_office_benefit_type (tr)
SELECT 'free_lover_slots' WHERE NOT EXISTS (SELECT 1 FROM falukant_type.political_office_benefit_type t WHERE t.tr = 'free_lover_slots');
INSERT INTO falukant_type.political_office_benefit_type (tr)
SELECT 'guard_protection' WHERE NOT EXISTS (SELECT 1 FROM falukant_type.political_office_benefit_type t WHERE t.tr = 'guard_protection');
INSERT INTO falukant_type.political_office_benefit_type (tr)
SELECT 'court_immunity' WHERE NOT EXISTS (SELECT 1 FROM falukant_type.political_office_benefit_type t WHERE t.tr = 'court_immunity');
-- reputation_periodic
INSERT INTO falukant_predefine.political_office_benefit (office_type_id, benefit_type_id, value)
SELECT ot.id, bt.id, v::jsonb FROM falukant_type.political_office_type ot
JOIN falukant_type.political_office_benefit_type bt ON bt.tr = 'reputation_periodic'
CROSS JOIN (VALUES
('assessor', '{"intervalDays":28,"gain":1}'::text),
('master-builder', '{"intervalDays":21,"gain":1}'::text),
('village-major', '{"intervalDays":21,"gain":1}'::text),
('councillor', '{"intervalDays":28,"gain":1}'::text),
('council', '{"intervalDays":21,"gain":1}'::text),
('mayor', '{"intervalDays":14,"gain":2}'::text),
('town-clerk', '{"intervalDays":21,"gain":1}'::text),
('judge', '{"intervalDays":14,"gain":2}'::text),
('bailif', '{"intervalDays":21,"gain":1}'::text),
('sheriff', '{"intervalDays":14,"gain":2}'::text),
('taxman', '{"intervalDays":21,"gain":2}'::text),
('treasurer', '{"intervalDays":14,"gain":3}'::text),
('consultant', '{"intervalDays":21,"gain":2}'::text),
('hangman', '{"intervalDays":21,"gain":1}'::text),
('territorial-council', '{"intervalDays":14,"gain":2}'::text),
('territorial-council-speaker', '{"intervalDays":10,"gain":3}'::text),
('ruler-consultant', '{"intervalDays":10,"gain":3}'::text),
('state-administrator', '{"intervalDays":10,"gain":3}'::text),
('super-state-administrator', '{"intervalDays":7,"gain":4}'::text),
('governor', '{"intervalDays":7,"gain":4}'::text),
('minister', '{"intervalDays":10,"gain":3}'::text),
('ministry-helper', '{"intervalDays":14,"gain":2}'::text),
('chancellor', '{"intervalDays":7,"gain":5}'::text)
) AS s(office_name, v)
WHERE ot.name = s.office_name
AND NOT EXISTS (SELECT 1 FROM falukant_predefine.political_office_benefit x WHERE x.office_type_id = ot.id AND x.benefit_type_id = bt.id);
-- appoint_politicians
INSERT INTO falukant_predefine.political_office_benefit (office_type_id, benefit_type_id, value)
SELECT ot.id, bt.id, v::jsonb FROM falukant_type.political_office_type ot
JOIN falukant_type.political_office_benefit_type bt ON bt.tr = 'appoint_politicians'
CROSS JOIN (VALUES
('mayor', '{"officeTrs":["beadle","town-clerk"]}'::text),
('judge', '{"officeTrs":["bailif"]}'::text),
('governor', '{"officeTrs":["state-administrator","consultant"]}'::text),
('super-state-administrator', '{"officeTrs":["territorial-council","hangman"]}'::text),
('chancellor', '{"officeTrs":["minister","ministry-helper","super-state-administrator"]}'::text)
) AS s(office_name, v)
WHERE ot.name = s.office_name
AND NOT EXISTS (SELECT 1 FROM falukant_predefine.political_office_benefit x WHERE x.office_type_id = ot.id AND x.benefit_type_id = bt.id);
-- set_regional_tax
INSERT INTO falukant_predefine.political_office_benefit (office_type_id, benefit_type_id, value)
SELECT ot.id, bt.id, v::jsonb FROM falukant_type.political_office_type ot
JOIN falukant_type.political_office_benefit_type bt ON bt.tr = 'set_regional_tax'
CROSS JOIN (VALUES
('taxman', '{"scope":"local"}'::text),
('treasurer', '{"scope":"shire"}'::text),
('super-state-administrator', '{"scope":"duchy"}'::text),
('chancellor', '{"scope":"national"}'::text)
) AS s(office_name, v)
WHERE ot.name = s.office_name
AND NOT EXISTS (SELECT 1 FROM falukant_predefine.political_office_benefit x WHERE x.office_type_id = ot.id AND x.benefit_type_id = bt.id);
-- free_lover_slots
INSERT INTO falukant_predefine.political_office_benefit (office_type_id, benefit_type_id, value)
SELECT ot.id, bt.id, v::jsonb FROM falukant_type.political_office_type ot
JOIN falukant_type.political_office_benefit_type bt ON bt.tr = 'free_lover_slots'
CROSS JOIN (VALUES
('councillor', '{"count":1}'::text),
('mayor', '{"count":1}'::text),
('minister', '{"count":1}'::text),
('governor', '{"count":2}'::text),
('chancellor', '{"count":3}'::text)
) AS s(office_name, v)
WHERE ot.name = s.office_name
AND NOT EXISTS (SELECT 1 FROM falukant_predefine.political_office_benefit x WHERE x.office_type_id = ot.id AND x.benefit_type_id = bt.id);
-- guard_protection / court_immunity
INSERT INTO falukant_predefine.political_office_benefit (office_type_id, benefit_type_id, value)
SELECT ot.id, bt.id, '{}'::jsonb FROM falukant_type.political_office_type ot
JOIN falukant_type.political_office_benefit_type bt ON bt.tr = 'guard_protection'
CROSS JOIN (VALUES ('sheriff'), ('hangman'), ('minister')) AS s(office_name)
WHERE ot.name = s.office_name
AND NOT EXISTS (SELECT 1 FROM falukant_predefine.political_office_benefit x WHERE x.office_type_id = ot.id AND x.benefit_type_id = bt.id);
INSERT INTO falukant_predefine.political_office_benefit (office_type_id, benefit_type_id, value)
SELECT ot.id, bt.id, '{}'::jsonb FROM falukant_type.political_office_type ot
JOIN falukant_type.political_office_benefit_type bt ON bt.tr = 'court_immunity'
CROSS JOIN (VALUES ('judge'), ('councillor'), ('chancellor')) AS s(office_name)
WHERE ot.name = s.office_name
AND NOT EXISTS (SELECT 1 FROM falukant_predefine.political_office_benefit x WHERE x.office_type_id = ot.id AND x.benefit_type_id = bt.id);

View File

@@ -356,6 +356,7 @@ const politicalOfficeBenefitTypes = [
{ tr: 'salary' }, { tr: 'salary' },
{ tr: 'daily_salary' }, { tr: 'daily_salary' },
{ tr: 'reputation' }, { tr: 'reputation' },
{ tr: 'reputation_periodic' },
{ tr: 'influence' }, { tr: 'influence' },
{ tr: 'access_level' }, { tr: 'access_level' },
{ tr: 'housing_allowance' }, { tr: 'housing_allowance' },
@@ -363,6 +364,60 @@ const politicalOfficeBenefitTypes = [
{ tr: 'guard_protection' }, { tr: 'guard_protection' },
{ tr: 'court_immunity' }, { tr: 'court_immunity' },
{ tr: 'set_regionl_tax' }, { tr: 'set_regionl_tax' },
{ tr: 'set_regional_tax' },
{ tr: 'appoint_politicians' },
{ tr: 'free_lover_slots' },
];
/** Zusätzliche Amtsvorteile (Anzeige; Spielmechanik z. T. noch offen). SQL-Pendant: backend/sql/falukant_political_office_extra_benefits.sql */
const politicalOfficeExtraBenefitSeeds = [
{ officeTr: 'assessor', benefitTr: 'reputation_periodic', value: { intervalDays: 28, gain: 1 } },
{ officeTr: 'master-builder', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 1 } },
{ officeTr: 'village-major', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 1 } },
{ officeTr: 'councillor', benefitTr: 'reputation_periodic', value: { intervalDays: 28, gain: 1 } },
{ officeTr: 'council', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 1 } },
{ officeTr: 'mayor', benefitTr: 'reputation_periodic', value: { intervalDays: 14, gain: 2 } },
{ officeTr: 'town-clerk', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 1 } },
{ officeTr: 'judge', benefitTr: 'reputation_periodic', value: { intervalDays: 14, gain: 2 } },
{ officeTr: 'bailif', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 1 } },
{ officeTr: 'sheriff', benefitTr: 'reputation_periodic', value: { intervalDays: 14, gain: 2 } },
{ officeTr: 'taxman', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 2 } },
{ officeTr: 'treasurer', benefitTr: 'reputation_periodic', value: { intervalDays: 14, gain: 3 } },
{ officeTr: 'consultant', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 2 } },
{ officeTr: 'hangman', benefitTr: 'reputation_periodic', value: { intervalDays: 21, gain: 1 } },
{ officeTr: 'territorial-council', benefitTr: 'reputation_periodic', value: { intervalDays: 14, gain: 2 } },
{ officeTr: 'territorial-council-speaker', benefitTr: 'reputation_periodic', value: { intervalDays: 10, gain: 3 } },
{ officeTr: 'ruler-consultant', benefitTr: 'reputation_periodic', value: { intervalDays: 10, gain: 3 } },
{ officeTr: 'state-administrator', benefitTr: 'reputation_periodic', value: { intervalDays: 10, gain: 3 } },
{ officeTr: 'super-state-administrator', benefitTr: 'reputation_periodic', value: { intervalDays: 7, gain: 4 } },
{ officeTr: 'governor', benefitTr: 'reputation_periodic', value: { intervalDays: 7, gain: 4 } },
{ officeTr: 'minister', benefitTr: 'reputation_periodic', value: { intervalDays: 10, gain: 3 } },
{ officeTr: 'ministry-helper', benefitTr: 'reputation_periodic', value: { intervalDays: 14, gain: 2 } },
{ officeTr: 'chancellor', benefitTr: 'reputation_periodic', value: { intervalDays: 7, gain: 5 } },
{ officeTr: 'mayor', benefitTr: 'appoint_politicians', value: { officeTrs: ['beadle', 'town-clerk'] } },
{ officeTr: 'judge', benefitTr: 'appoint_politicians', value: { officeTrs: ['bailif'] } },
{ officeTr: 'governor', benefitTr: 'appoint_politicians', value: { officeTrs: ['state-administrator', 'consultant'] } },
{ officeTr: 'super-state-administrator', benefitTr: 'appoint_politicians', value: { officeTrs: ['territorial-council', 'hangman'] } },
{ officeTr: 'chancellor', benefitTr: 'appoint_politicians', value: { officeTrs: ['minister', 'ministry-helper', 'super-state-administrator'] } },
{ officeTr: 'taxman', benefitTr: 'set_regional_tax', value: { scope: 'local' } },
{ officeTr: 'treasurer', benefitTr: 'set_regional_tax', value: { scope: 'shire' } },
{ officeTr: 'super-state-administrator', benefitTr: 'set_regional_tax', value: { scope: 'duchy' } },
{ officeTr: 'chancellor', benefitTr: 'set_regional_tax', value: { scope: 'national' } },
{ officeTr: 'councillor', benefitTr: 'free_lover_slots', value: { count: 1 } },
{ officeTr: 'mayor', benefitTr: 'free_lover_slots', value: { count: 1 } },
{ officeTr: 'minister', benefitTr: 'free_lover_slots', value: { count: 1 } },
{ officeTr: 'governor', benefitTr: 'free_lover_slots', value: { count: 2 } },
{ officeTr: 'chancellor', benefitTr: 'free_lover_slots', value: { count: 3 } },
{ officeTr: 'sheriff', benefitTr: 'guard_protection', value: {} },
{ officeTr: 'hangman', benefitTr: 'guard_protection', value: {} },
{ officeTr: 'minister', benefitTr: 'guard_protection', value: {} },
{ officeTr: 'judge', benefitTr: 'court_immunity', value: {} },
{ officeTr: 'councillor', benefitTr: 'court_immunity', value: {} },
{ officeTr: 'chancellor', benefitTr: 'court_immunity', value: {} },
]; ];
const politicalOffices = [ const politicalOffices = [
@@ -1092,8 +1147,24 @@ export const initializePoliticalOfficeBenefits = async () => {
if (wasCreated) dailyCreated += 1; if (wasCreated) dailyCreated += 1;
} }
let extraCreated = 0;
for (const { officeTr, benefitTr, value } of politicalOfficeExtraBenefitSeeds) {
const office = await PoliticalOfficeType.findOne({ where: { name: officeTr } });
const bType = await PoliticalOfficeBenefitType.findOne({ where: { tr: benefitTr } });
if (!office || !bType) continue;
const [, wasCreated] = await PoliticalOfficeBenefit.findOrCreate({
where: { officeTypeId: office.id, benefitTypeId: bType.id },
defaults: {
officeTypeId: office.id,
benefitTypeId: bType.id,
value: value && typeof value === 'object' ? value : {}
}
});
if (wasCreated) extraCreated += 1;
}
console.log( console.log(
`[Falukant] PoliticalOfficeBenefits: Steuer neu=${taxCreated}, Tageslohn neu=${dailyCreated} (gesamt Ämter=${allOffices.length})` `[Falukant] PoliticalOfficeBenefits: Steuer neu=${taxCreated}, Tageslohn neu=${dailyCreated}, weitere Vorteile neu=${extraCreated} (Ämter gesamt=${allOffices.length})`
); );
}; };

View File

@@ -438,6 +438,18 @@
"daily_salary": "Adlaw-adlaw nga suhol (usa ra kada adlaw): mga {amount}", "daily_salary": "Adlaw-adlaw nga suhol (usa ra kada adlaw): mga {amount}",
"tax_exemption": "Way buhis: {regions}", "tax_exemption": "Way buhis: {regions}",
"tax_exemption_all": "Way buhis: tanang lebel sa rehiyon", "tax_exemption_all": "Way buhis: tanang lebel sa rehiyon",
"reputation_periodic": "+{gain} reputasyon matag {days} ka adlaw (benepisyo sa opisina)",
"appoint_politicians": "Katungod sa pagtudlo: {offices}",
"set_regional_tax": "Maka-set sa mga rate sa buhis ({scope})",
"tax_scope": {
"local": "lokal sa hurisdiksyon",
"shire": "lebel sa shire",
"duchy": "lebel sa duchy",
"national": "tibuok nasud"
},
"free_lover_slots": "{count} dugang relasyon nga walay bulan nga gasto",
"guard_protection": "Opisyal nga panalipod / escort",
"court_immunity": "Limitado nga immune sa korte sa opisina",
"generic": "Benepisyo ({code})" "generic": "Benepisyo ({code})"
}, },
"regionLevels": { "regionLevels": {

View File

@@ -1357,6 +1357,18 @@
"daily_salary": "Tagesamtshonorar (einmal pro Tag): ca. {amount}", "daily_salary": "Tagesamtshonorar (einmal pro Tag): ca. {amount}",
"tax_exemption": "Steuerbefreiung: {regions}", "tax_exemption": "Steuerbefreiung: {regions}",
"tax_exemption_all": "Steuerbefreiung: alle Regionsebenen", "tax_exemption_all": "Steuerbefreiung: alle Regionsebenen",
"reputation_periodic": "+{gain} Ansehen alle {days} Tage (Amtsbonus)",
"appoint_politicians": "Ernennungsrecht für folgende Ämter: {offices}",
"set_regional_tax": "Darf Steuersätze festlegen ({scope})",
"tax_scope": {
"local": "lokal im Amtsgebiet",
"shire": "auf Grafschaftsebene",
"duchy": "auf Herzogtumsebene",
"national": "reichsweit"
},
"free_lover_slots": "{count} zusätzliche Liebschaft(en) ohne monatlichen Unterhalt",
"guard_protection": "Amtsschutz / Eskorte",
"court_immunity": "Eingeschränkte gerichtliche Immunität im Amtsbereich",
"generic": "Vorteil ({code})" "generic": "Vorteil ({code})"
}, },
"regionLevels": { "regionLevels": {

View File

@@ -578,6 +578,18 @@
"daily_salary": "Daily office stipend (once per day): about {amount}", "daily_salary": "Daily office stipend (once per day): about {amount}",
"tax_exemption": "Tax exemption: {regions}", "tax_exemption": "Tax exemption: {regions}",
"tax_exemption_all": "Tax exemption: all regional levels", "tax_exemption_all": "Tax exemption: all regional levels",
"reputation_periodic": "+{gain} reputation every {days} days (office bonus)",
"appoint_politicians": "Power to appoint: {offices}",
"set_regional_tax": "May set tax rates ({scope})",
"tax_scope": {
"local": "locally in jurisdiction",
"shire": "shire level",
"duchy": "duchy level",
"national": "nationwide"
},
"free_lover_slots": "{count} additional affair(s) with no monthly upkeep",
"guard_protection": "Official guard / escort",
"court_immunity": "Limited judicial immunity in office matters",
"generic": "Benefit ({code})" "generic": "Benefit ({code})"
}, },
"regionLevels": { "regionLevels": {

View File

@@ -1265,6 +1265,18 @@
"daily_salary": "Estipendio diario (una vez al día): unos {amount}", "daily_salary": "Estipendio diario (una vez al día): unos {amount}",
"tax_exemption": "Exención fiscal: {regions}", "tax_exemption": "Exención fiscal: {regions}",
"tax_exemption_all": "Exención fiscal: todos los niveles regionales", "tax_exemption_all": "Exención fiscal: todos los niveles regionales",
"reputation_periodic": "+{gain} reputación cada {days} días (bono de cargo)",
"appoint_politicians": "Derecho a nombrar: {offices}",
"set_regional_tax": "Puede fijar tipos impositivos ({scope})",
"tax_scope": {
"local": "localmente en la jurisdicción",
"shire": "nivel de condado (shire)",
"duchy": "nivel de ducado",
"national": "ámbito nacional"
},
"free_lover_slots": "{count} relación(es) adicional(es) sin mantenimiento mensual",
"guard_protection": "Protección oficial / escolta",
"court_immunity": "Inmunidad judicial limitada en asuntos del cargo",
"generic": "Ventaja ({code})" "generic": "Ventaja ({code})"
}, },
"regionLevels": { "regionLevels": {

View File

@@ -198,6 +198,19 @@ export default {
return t !== path ? t : k; return t !== path ? t : k;
}, },
formatPoliticsAppointOfficeLabels(officeTrs) {
if (!Array.isArray(officeTrs) || !officeTrs.length) {
return '';
}
return officeTrs
.map((tr) => {
const path = `falukant.politics.offices.${tr}`;
const t = this.$t(path);
return t !== path ? t : String(tr);
})
.join(', ');
},
formatPoliticsBenefitItem(b) { formatPoliticsBenefitItem(b) {
if (b == null) { if (b == null) {
return ''; return '';
@@ -216,6 +229,32 @@ export default {
if (b.tr === 'daily_salary') { if (b.tr === 'daily_salary') {
return this.$t('falukant.politics.benefits.daily_salary', { amount: b.params?.amount ?? '—' }); return this.$t('falukant.politics.benefits.daily_salary', { amount: b.params?.amount ?? '—' });
} }
if (b.tr === 'reputation_periodic') {
return this.$t('falukant.politics.benefits.reputation_periodic', {
days: b.params?.intervalDays ?? '—',
gain: b.params?.gain ?? '—'
});
}
if (b.tr === 'appoint_politicians' && Array.isArray(b.params?.officeTrs)) {
const labels = this.formatPoliticsAppointOfficeLabels(b.params.officeTrs);
return this.$t('falukant.politics.benefits.appoint_politicians', { offices: labels });
}
if (b.tr === 'set_regional_tax') {
const sk = String(b.params?.scope || 'local');
const scopePath = `falukant.politics.benefits.tax_scope.${sk}`;
const st = this.$t(scopePath);
const scopeLabel = st !== scopePath ? st : sk;
return this.$t('falukant.politics.benefits.set_regional_tax', { scope: scopeLabel });
}
if (b.tr === 'free_lover_slots') {
return this.$t('falukant.politics.benefits.free_lover_slots', { count: b.params?.count ?? 1 });
}
if (b.tr === 'guard_protection') {
return this.$t('falukant.politics.benefits.guard_protection');
}
if (b.tr === 'court_immunity') {
return this.$t('falukant.politics.benefits.court_immunity');
}
if (b.tr === 'generic_benefit') { if (b.tr === 'generic_benefit') {
return this.$t('falukant.politics.benefits.generic', { code: b.params?.code || '' }); return this.$t('falukant.politics.benefits.generic', { code: b.params?.code || '' });
} }