feat: 죽음 연도에 따른 killturn 계산 로직 추가 및 관련 메타 데이터 수정

This commit is contained in:
2026-01-25 06:17:27 +00:00
parent 46759022fd
commit 21d8507fc5
4 changed files with 99 additions and 13 deletions
+39 -6
View File
@@ -1,6 +1,6 @@
import { createGamePostgresConnector, type InputJsonValue, type TurnEngineEventCreateManyInput } from '@sammo-ts/infra'; import { createGamePostgresConnector, type InputJsonValue, type TurnEngineEventCreateManyInput } from '@sammo-ts/infra';
import { asRecord } from '@sammo-ts/common'; import { asRecord } from '@sammo-ts/common';
import { buildScenarioBootstrap, type ScenarioBootstrapWarning, type WorldSeedPayload } from '@sammo-ts/logic'; import { buildScenarioBootstrap, type GeneralMeta, type ScenarioBootstrapWarning, type WorldSeedPayload } from '@sammo-ts/logic';
import type { MapLoaderOptions } from './mapLoader.js'; import type { MapLoaderOptions } from './mapLoader.js';
import { loadMapDefinitionByName } from './mapLoader.js'; import { loadMapDefinitionByName } from './mapLoader.js';
@@ -143,6 +143,20 @@ const resolveGeneralAge = (startYear: number | null, birthYear: number): number
return Math.max(startYear - birthYear, 0); return Math.max(startYear - birthYear, 0);
}; };
const resolveKillturnFromDeathYear = (
currentYear: number,
currentMonth: number,
deathYear: number,
fallback: number
): number => {
if (!Number.isFinite(deathYear) || deathYear <= 0) {
return fallback;
}
const deathMonth = Math.floor(Math.random() * 12) + 1;
const diff = (deathYear - currentYear) * 12 + (deathMonth - currentMonth);
return Math.max(diff, 0);
};
const buildEventRows = (rows: unknown[], targetOverride?: string): TurnEngineEventCreateManyInput[] => { const buildEventRows = (rows: unknown[], targetOverride?: string): TurnEngineEventCreateManyInput[] => {
const result: TurnEngineEventCreateManyInput[] = []; const result: TurnEngineEventCreateManyInput[] = [];
@@ -369,11 +383,30 @@ export const seedScenarioToDatabase = async (options: ScenarioSeedOptions): Prom
specialCode: general.special ?? 'None', specialCode: general.special ?? 'None',
special2Code: general.specialWar ?? 'None', special2Code: general.specialWar ?? 'None',
lastTurn: asJson({}), lastTurn: asJson({}),
meta: asJson({ meta: asJson(
npcType: general.npcType, (() => {
crewTypeId: general.crewTypeId, const meta = { ...general.meta } as Record<string, unknown>;
...general.meta, if (typeof meta.birthYear !== 'number' || !Number.isFinite(meta.birthYear)) {
}), meta.birthYear = general.birthYear;
}
delete meta.deathYear;
delete meta.deadYear;
const fallbackKillturn =
typeof meta.killturn === 'number' && Number.isFinite(meta.killturn) ? meta.killturn : 0;
const killturn = resolveKillturnFromDeathYear(
startState.currentYear,
startState.currentMonth,
general.deathYear,
fallbackKillturn
);
return {
...meta,
killturn,
npcType: general.npcType,
crewTypeId: general.crewTypeId,
} satisfies GeneralMeta;
})()
),
penalty: asJson({}), penalty: asJson({}),
})), })),
}); });
@@ -48,6 +48,7 @@ export interface TalentScoutResolveContext<
TriggerState extends GeneralTriggerState = GeneralTriggerState, TriggerState extends GeneralTriggerState = GeneralTriggerState,
> extends GeneralActionResolveContext<TriggerState> { > extends GeneralActionResolveContext<TriggerState> {
currentYear: number; currentYear: number;
currentMonth: number;
worldSummary: TalentScoutWorldSummary; worldSummary: TalentScoutWorldSummary;
generalPool?: TalentScoutCandidate[]; generalPool?: TalentScoutCandidate[];
cityPool?: City[]; cityPool?: City[];
@@ -86,6 +87,20 @@ const DEFAULT_MAX_AGE = 25;
const DEFAULT_DEATH_MIN = 10; const DEFAULT_DEATH_MIN = 10;
const DEFAULT_DEATH_MAX = 50; const DEFAULT_DEATH_MAX = 50;
const resolveKillturnFromDeathYear = (
currentYear: number,
currentMonth: number,
deathYear: number,
rng: RandomGenerator
): number => {
if (!Number.isFinite(deathYear) || deathYear <= 0) {
return 0;
}
const deathMonth = randomRangeInt(rng, 1, 12);
const diff = (deathYear - currentYear) * 12 + (deathMonth - currentMonth);
return Math.max(diff, 0);
};
const addMetaValue = ( const addMetaValue = (
meta: Record<string, TriggerValue>, meta: Record<string, TriggerValue>,
key: string, key: string,
@@ -302,14 +317,18 @@ export class ActionResolver<
? this.env.decorateName(resolvedCandidate.name, NPC_TYPE) ? this.env.decorateName(resolvedCandidate.name, NPC_TYPE)
: resolvedCandidate.name; : resolvedCandidate.name;
const meta: GeneralMeta = { const meta: GeneralMeta = {
killturn: context.general.meta.killturn, killturn: resolveKillturnFromDeathYear(
context.currentYear,
context.currentMonth,
deathYear,
context.rng
),
npcType: NPC_TYPE, npcType: NPC_TYPE,
crewTypeId: this.env.defaultCrewTypeId, crewTypeId: this.env.defaultCrewTypeId,
}; };
addMetaValue(meta, 'affinity', resolvedCandidate.affinity ?? null); addMetaValue(meta, 'affinity', resolvedCandidate.affinity ?? null);
addMetaValue(meta, 'picture', resolvedCandidate.picture ?? null); addMetaValue(meta, 'picture', resolvedCandidate.picture ?? null);
addMetaValue(meta, 'birthYear', birthYear); addMetaValue(meta, 'birthYear', birthYear);
addMetaValue(meta, 'deathYear', deathYear);
addMetaValue(meta, 'text', resolvedCandidate.text ?? null); addMetaValue(meta, 'text', resolvedCandidate.text ?? null);
const newGeneral = buildRecruitmentGeneral<TriggerState>({ const newGeneral = buildRecruitmentGeneral<TriggerState>({
@@ -393,6 +412,7 @@ export class ActionDefinition<
export const actionContextBuilder: ActionContextBuilder = (base, options) => ({ export const actionContextBuilder: ActionContextBuilder = (base, options) => ({
...base, ...base,
currentYear: options.world.currentYear, currentYear: options.world.currentYear,
currentMonth: options.world.currentMonth,
worldSummary: buildWorldSummary(options.worldRef), worldSummary: buildWorldSummary(options.worldRef),
createGeneralId: options.createGeneralId, createGeneralId: options.createGeneralId,
}); });
@@ -46,6 +46,7 @@ export interface VolunteerRecruitResolveContext<
TriggerState extends GeneralTriggerState = GeneralTriggerState, TriggerState extends GeneralTriggerState = GeneralTriggerState,
> extends GeneralActionResolveContext<TriggerState> { > extends GeneralActionResolveContext<TriggerState> {
currentYear: number; currentYear: number;
currentMonth: number;
startYear: number; startYear: number;
averageNationGeneralCount: number; averageNationGeneralCount: number;
nationAverageStats?: StatBlock; nationAverageStats?: StatBlock;
@@ -91,6 +92,20 @@ const DEFAULT_KILLTURN_MIN = 64;
const DEFAULT_KILLTURN_MAX = 70; const DEFAULT_KILLTURN_MAX = 70;
const DEFAULT_SPEC_AGE = 19; const DEFAULT_SPEC_AGE = 19;
const resolveKillturnFromDeathYear = (
currentYear: number,
currentMonth: number,
deathYear: number,
rng: RandomGenerator
): number => {
if (!Number.isFinite(deathYear) || deathYear <= 0) {
return 0;
}
const deathMonth = randomRangeInt(rng, 1, 12);
const diff = (deathYear - currentYear) * 12 + (deathMonth - currentMonth);
return Math.max(diff, 0);
};
const addMetaValue = ( const addMetaValue = (
meta: Record<string, TriggerValue>, meta: Record<string, TriggerValue>,
key: string, key: string,
@@ -269,17 +284,21 @@ export class ActionResolver<
const deathYear = context.currentYear + deathYears; const deathYear = context.currentYear + deathYears;
const stats = resolveStats(context, context.rng, this.env, candidate); const stats = resolveStats(context, context.rng, this.env, candidate);
const meta: GeneralMeta = { const meta: GeneralMeta = {
killturn: randomRangeInt(context.rng, killTurnMin, killTurnMax), killturn: resolveKillturnFromDeathYear(
context.currentYear,
context.currentMonth,
deathYear,
context.rng
),
npcType: NPC_TYPE, npcType: NPC_TYPE,
crewTypeId: this.env.defaultCrewTypeId, crewTypeId: this.env.defaultCrewTypeId,
}; };
addMetaValue(meta, 'affinity', candidate.affinity ?? null); addMetaValue(meta, 'affinity', candidate.affinity ?? null);
addMetaValue(meta, 'picture', candidate.picture ?? null); addMetaValue(meta, 'picture', candidate.picture ?? null);
addMetaValue(meta, 'birthYear', birthYear); addMetaValue(meta, 'birthYear', birthYear);
addMetaValue(meta, 'deathYear', deathYear);
addMetaValue(meta, 'specAge', DEFAULT_SPEC_AGE); addMetaValue(meta, 'specAge', DEFAULT_SPEC_AGE);
addMetaValue(meta, 'specAge2', DEFAULT_SPEC_AGE); addMetaValue(meta, 'specAge2', DEFAULT_SPEC_AGE);
addMetaValue(meta, 'killturn', meta.killturn); addMetaValue(meta, 'killturn', meta.killturn || randomRangeInt(context.rng, killTurnMin, killTurnMax));
addMetaValue(meta, 'text', candidate.text ?? null); addMetaValue(meta, 'text', candidate.text ?? null);
const newGeneral = buildRecruitmentGeneral<TriggerState>({ const newGeneral = buildRecruitmentGeneral<TriggerState>({
@@ -357,6 +376,7 @@ export const actionContextBuilder: ActionContextBuilder = (base, options) => {
return { return {
...base, ...base,
currentYear: options.world.currentYear, currentYear: options.world.currentYear,
currentMonth: options.world.currentMonth,
startYear: resolveStartYear(options.world, options.scenarioMeta), startYear: resolveStartYear(options.world, options.scenarioMeta),
averageNationGeneralCount: buildAverageNationGeneralCount(options.worldRef), averageNationGeneralCount: buildAverageNationGeneralCount(options.worldRef),
nationAverageStats: nationSummary.averageStats, nationAverageStats: nationSummary.averageStats,
+15 -2
View File
@@ -140,6 +140,20 @@ const resolveDeathYear = (deathYear: number, birthYear: number, startYear: numbe
return 0; return 0;
}; };
const resolveKillturnFromDeathYear = (
currentYear: number | null,
currentMonth: number,
deathYear: number,
fallback: number
): number => {
if (currentYear === null || !Number.isFinite(deathYear) || deathYear <= 0) {
return fallback;
}
const deathMonth = Math.floor(Math.random() * 12) + 1;
const diff = (deathYear - currentYear) * 12 + (deathMonth - currentMonth);
return Math.max(diff, 0);
};
const resolveAge = (startYear: number | null, birthYear: number): number => { const resolveAge = (startYear: number | null, birthYear: number): number => {
if (startYear === null || birthYear <= 0) { if (startYear === null || birthYear <= 0) {
return 20; return 20;
@@ -299,7 +313,7 @@ const buildGeneralSeeds = (
seeds.push(seed); seeds.push(seed);
const generalMeta: GeneralMeta = { const generalMeta: GeneralMeta = {
killturn: DEFAULT_GENERAL_KILLTURN, killturn: resolveKillturnFromDeathYear(scenario.startYear, 1, deathYear, DEFAULT_GENERAL_KILLTURN),
npcType, npcType,
crewTypeId: defaultCrewTypeId, crewTypeId: defaultCrewTypeId,
}; };
@@ -313,7 +327,6 @@ const buildGeneralSeeds = (
addTriggerMeta(generalMeta, 'book', row.book ?? undefined); addTriggerMeta(generalMeta, 'book', row.book ?? undefined);
addTriggerMeta(generalMeta, 'item', row.item ?? undefined); addTriggerMeta(generalMeta, 'item', row.item ?? undefined);
addTriggerMeta(generalMeta, 'birthYear', birthYear); addTriggerMeta(generalMeta, 'birthYear', birthYear);
addTriggerMeta(generalMeta, 'deathYear', deathYear);
addTriggerMeta(generalMeta, 'text', row.text ?? undefined); addTriggerMeta(generalMeta, 'text', row.text ?? undefined);
generals.push({ generals.push({