내무부, 금/쌀수입, 감찰부 구현
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export * from './nationIncome.js';
|
||||
@@ -0,0 +1,275 @@
|
||||
import type { General, Nation } from '../domain/entities.js';
|
||||
import type { GeneralActionContext } from '../triggers/general.js';
|
||||
import type { TriggerNationalIncomeType } from '../triggers/types.js';
|
||||
|
||||
export type NationIncomeModifier = (type: TriggerNationalIncomeType, amount: number) => number;
|
||||
|
||||
export interface NationIncomeContext {
|
||||
rate: number;
|
||||
modifyIncome?: NationIncomeModifier;
|
||||
}
|
||||
|
||||
export interface CityIncomeSource {
|
||||
id: number;
|
||||
population: number;
|
||||
populationMax: number;
|
||||
agriculture: number;
|
||||
agricultureMax: number;
|
||||
commerce: number;
|
||||
commerceMax: number;
|
||||
security: number;
|
||||
securityMax: number;
|
||||
trust: number;
|
||||
supplyState: number;
|
||||
defence: number;
|
||||
defenceMax: number;
|
||||
wall: number;
|
||||
wallMax: number;
|
||||
meta: Record<string, unknown>;
|
||||
}
|
||||
|
||||
const MAX_DED_LEVEL = 30;
|
||||
|
||||
const readMetaNumber = (meta: Record<string, unknown>, key: string, fallback = 0): number => {
|
||||
const value = meta[key];
|
||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
return fallback;
|
||||
};
|
||||
|
||||
const applyNationIncome = (context: NationIncomeContext, type: TriggerNationalIncomeType, amount: number): number => {
|
||||
if (!context.modifyIncome) {
|
||||
return amount;
|
||||
}
|
||||
return context.modifyIncome(type, amount);
|
||||
};
|
||||
|
||||
export const createIncomeActionContext = (nation: Nation): GeneralActionContext => {
|
||||
const general: General = {
|
||||
id: 0,
|
||||
name: 'SYSTEM',
|
||||
nationId: nation.id,
|
||||
cityId: 0,
|
||||
troopId: 0,
|
||||
stats: { leadership: 0, strength: 0, intelligence: 0 },
|
||||
experience: 0,
|
||||
dedication: 0,
|
||||
officerLevel: 0,
|
||||
role: {
|
||||
personality: null,
|
||||
specialDomestic: null,
|
||||
specialWar: null,
|
||||
items: {
|
||||
horse: null,
|
||||
weapon: null,
|
||||
book: null,
|
||||
item: null,
|
||||
},
|
||||
},
|
||||
injury: 0,
|
||||
gold: 0,
|
||||
rice: 0,
|
||||
crew: 0,
|
||||
crewTypeId: 0,
|
||||
train: 0,
|
||||
atmos: 0,
|
||||
age: 0,
|
||||
npcState: 0,
|
||||
triggerState: {
|
||||
flags: {},
|
||||
counters: {},
|
||||
modifiers: {},
|
||||
meta: {},
|
||||
},
|
||||
meta: {},
|
||||
};
|
||||
return { general, nation };
|
||||
};
|
||||
|
||||
export const calcCityGoldIncomeBase = (
|
||||
context: NationIncomeContext,
|
||||
city: CityIncomeSource,
|
||||
officerCnt: number,
|
||||
isCapital: boolean,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
if (city.supplyState === 0) {
|
||||
return 0;
|
||||
}
|
||||
const trustRatio = city.trust / 200 + 0.5;
|
||||
const commMax = Math.max(1, city.commerceMax);
|
||||
const secuMax = Math.max(1, city.securityMax);
|
||||
|
||||
let income = (city.population * city.commerce * trustRatio) / commMax / 30;
|
||||
income *= 1 + city.security / secuMax / 10;
|
||||
income *= Math.pow(1.05, officerCnt);
|
||||
if (isCapital && nationLevel > 0) {
|
||||
income *= 1 + 1 / (3 * nationLevel);
|
||||
}
|
||||
|
||||
const adjusted = applyNationIncome(context, 'gold', income);
|
||||
return Math.round(adjusted);
|
||||
};
|
||||
|
||||
export const calcCityRiceIncomeBase = (
|
||||
context: NationIncomeContext,
|
||||
city: CityIncomeSource,
|
||||
officerCnt: number,
|
||||
isCapital: boolean,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
if (city.supplyState === 0) {
|
||||
return 0;
|
||||
}
|
||||
const trustRatio = city.trust / 200 + 0.5;
|
||||
const agriMax = Math.max(1, city.agricultureMax);
|
||||
const secuMax = Math.max(1, city.securityMax);
|
||||
|
||||
let income = (city.population * city.agriculture * trustRatio) / agriMax / 30;
|
||||
income *= 1 + city.security / secuMax / 10;
|
||||
income *= Math.pow(1.05, officerCnt);
|
||||
if (isCapital && nationLevel > 0) {
|
||||
income *= 1 + 1 / (3 * nationLevel);
|
||||
}
|
||||
|
||||
const adjusted = applyNationIncome(context, 'rice', income);
|
||||
return Math.round(adjusted);
|
||||
};
|
||||
|
||||
export const calcCityWallIncomeBase = (
|
||||
context: NationIncomeContext,
|
||||
city: CityIncomeSource,
|
||||
officerCnt: number,
|
||||
isCapital: boolean,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
if (city.supplyState === 0) {
|
||||
return 0;
|
||||
}
|
||||
const wallMax = Math.max(1, city.wallMax);
|
||||
const secuMax = Math.max(1, city.securityMax);
|
||||
|
||||
let income = (city.defence * city.wall) / wallMax / 3;
|
||||
income *= 1 + city.security / secuMax / 10;
|
||||
income *= Math.pow(1.05, officerCnt);
|
||||
if (isCapital && nationLevel > 0) {
|
||||
income *= 1 + 1 / (3 * nationLevel);
|
||||
}
|
||||
|
||||
const adjusted = applyNationIncome(context, 'rice', income);
|
||||
return Math.round(adjusted);
|
||||
};
|
||||
|
||||
export const calcCityWarGoldIncome = (context: NationIncomeContext, city: CityIncomeSource): number => {
|
||||
if (city.supplyState === 0) {
|
||||
return 0;
|
||||
}
|
||||
const dead = readMetaNumber(city.meta as Record<string, unknown>, 'dead', 0);
|
||||
const income = dead / 10;
|
||||
const adjusted = applyNationIncome(context, 'gold', income);
|
||||
return Math.round(adjusted);
|
||||
};
|
||||
|
||||
export const calcCityGoldIncome = (
|
||||
context: NationIncomeContext,
|
||||
city: CityIncomeSource,
|
||||
officerCnt: number,
|
||||
isCapital: boolean,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
const base = calcCityGoldIncomeBase(context, city, officerCnt, isCapital, nationLevel);
|
||||
return Math.round(base * (context.rate / 20));
|
||||
};
|
||||
|
||||
export const calcCityRiceIncome = (
|
||||
context: NationIncomeContext,
|
||||
city: CityIncomeSource,
|
||||
officerCnt: number,
|
||||
isCapital: boolean,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
const base = calcCityRiceIncomeBase(context, city, officerCnt, isCapital, nationLevel);
|
||||
return Math.round(base * (context.rate / 20));
|
||||
};
|
||||
|
||||
export const calcCityWallIncome = (
|
||||
context: NationIncomeContext,
|
||||
city: CityIncomeSource,
|
||||
officerCnt: number,
|
||||
isCapital: boolean,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
const base = calcCityWallIncomeBase(context, city, officerCnt, isCapital, nationLevel);
|
||||
return Math.round(base * (context.rate / 20));
|
||||
};
|
||||
|
||||
export const getGoldIncome = (
|
||||
context: NationIncomeContext,
|
||||
cities: CityIncomeSource[],
|
||||
officerCounts: Map<number, number>,
|
||||
capitalCityId: number | null,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
let total = 0;
|
||||
for (const city of cities) {
|
||||
const officerCnt = officerCounts.get(city.id) ?? 0;
|
||||
total += calcCityGoldIncomeBase(context, city, officerCnt, capitalCityId === city.id, nationLevel);
|
||||
}
|
||||
return total * (context.rate / 20);
|
||||
};
|
||||
|
||||
export const getRiceIncome = (
|
||||
context: NationIncomeContext,
|
||||
cities: CityIncomeSource[],
|
||||
officerCounts: Map<number, number>,
|
||||
capitalCityId: number | null,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
let total = 0;
|
||||
for (const city of cities) {
|
||||
const officerCnt = officerCounts.get(city.id) ?? 0;
|
||||
total += calcCityRiceIncomeBase(context, city, officerCnt, capitalCityId === city.id, nationLevel);
|
||||
}
|
||||
return total * (context.rate / 20);
|
||||
};
|
||||
|
||||
export const getWallIncome = (
|
||||
context: NationIncomeContext,
|
||||
cities: CityIncomeSource[],
|
||||
officerCounts: Map<number, number>,
|
||||
capitalCityId: number | null,
|
||||
nationLevel: number
|
||||
): number => {
|
||||
let total = 0;
|
||||
for (const city of cities) {
|
||||
const officerCnt = officerCounts.get(city.id) ?? 0;
|
||||
total += calcCityWallIncomeBase(context, city, officerCnt, capitalCityId === city.id, nationLevel);
|
||||
}
|
||||
return total * (context.rate / 20);
|
||||
};
|
||||
|
||||
export const getWarGoldIncome = (context: NationIncomeContext, cities: CityIncomeSource[]): number => {
|
||||
let total = 0;
|
||||
for (const city of cities) {
|
||||
total += calcCityWarGoldIncome(context, city);
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
export const resolveDedLevel = (dedication: number): number => {
|
||||
const level = Math.ceil(Math.sqrt(Math.max(0, dedication)) / 10);
|
||||
return Math.max(0, Math.min(MAX_DED_LEVEL, level));
|
||||
};
|
||||
|
||||
export const getBillByLevel = (dedicationLevel: number): number => dedicationLevel * 200 + 400;
|
||||
|
||||
export const getBill = (dedication: number): number => getBillByLevel(resolveDedLevel(dedication));
|
||||
|
||||
export const getOutcome = (billRate: number, generals: Array<{ dedication: number }>): number => {
|
||||
let total = 0;
|
||||
for (const general of generals) {
|
||||
total += getBill(general.dedication);
|
||||
}
|
||||
return Math.round(total * (billRate / 100));
|
||||
};
|
||||
Reference in New Issue
Block a user