feat: integrate unique lottery system into general actions
- Added `tryApplyUniqueLottery` function to various action definitions to apply unique item rewards based on specific actions. - Enhanced the `uniqueLottery.ts` module to handle unique item acquisition and logging. - Created unit tests for the unique lottery feature to ensure proper functionality during general commands. - Updated action definitions to include unique item acquisition for actions such as training, technology research, and item procurement.
This commit is contained in:
@@ -20,6 +20,15 @@ import {
|
||||
defaultActionContextBuilder,
|
||||
evaluateConstraints,
|
||||
resolveGeneralAction,
|
||||
ITEM_KEYS,
|
||||
buildGenericUniqueSeed,
|
||||
countOccupiedUniqueItems,
|
||||
createItemModuleRegistry,
|
||||
loadItemModules,
|
||||
resolveUniqueConfig,
|
||||
rollUniqueLottery,
|
||||
type ItemModule,
|
||||
type UniqueLotteryRunner,
|
||||
} from '@sammo-ts/logic';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic';
|
||||
import { asRecord, LiteHashDRBG, RandUtil } from '@sammo-ts/common';
|
||||
@@ -76,6 +85,122 @@ const serializeSeed = (...values: Array<string | number>): string =>
|
||||
.map((value) => (typeof value === 'string' ? `str(${value.length},${value})` : `int(${Math.floor(value)})`))
|
||||
.join('|');
|
||||
|
||||
const joinYearMonth = (year: number, month: number): number => year * 12 + month - 1;
|
||||
|
||||
const readMetaNumber = (meta: Record<string, unknown>, key: string, fallback: number): number => {
|
||||
const value = meta[key];
|
||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||
return Math.floor(value);
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
const parsed = Number(value);
|
||||
if (Number.isFinite(parsed)) {
|
||||
return Math.floor(parsed);
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
};
|
||||
|
||||
const readMetaBool = (meta: Record<string, unknown>, key: string, fallback = false): boolean => {
|
||||
const value = meta[key];
|
||||
if (typeof value === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
return value !== 0;
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
const lowered = value.toLowerCase();
|
||||
if (lowered === 'true' || lowered === '1') {
|
||||
return true;
|
||||
}
|
||||
if (lowered === 'false' || lowered === '0') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
};
|
||||
|
||||
const resolveStartYear = (world: TurnWorldState, scenarioMeta?: ScenarioMeta): number => {
|
||||
if (typeof scenarioMeta?.startYear === 'number') {
|
||||
return scenarioMeta.startYear;
|
||||
}
|
||||
const worldMeta = asRecord(world.meta);
|
||||
const scenarioMetaRecord = asRecord(worldMeta.scenarioMeta);
|
||||
return readMetaNumber(scenarioMetaRecord, 'startYear', world.currentYear);
|
||||
};
|
||||
|
||||
const buildUniqueLotteryRunner = (options: {
|
||||
world: TurnWorldState;
|
||||
worldView: WorldView | null;
|
||||
scenarioMeta?: ScenarioMeta;
|
||||
seedBase: string;
|
||||
itemRegistry: Map<string, ItemModule>;
|
||||
uniqueConfig: ReturnType<typeof resolveUniqueConfig>;
|
||||
}): UniqueLotteryRunner => {
|
||||
if (!options.worldView) {
|
||||
return () => null;
|
||||
}
|
||||
const worldView = options.worldView;
|
||||
const world = options.world;
|
||||
const worldMeta = asRecord(world.meta);
|
||||
const startYear = resolveStartYear(world, options.scenarioMeta);
|
||||
const initYear = readMetaNumber(worldMeta, 'initYear', startYear);
|
||||
const initMonth = readMetaNumber(worldMeta, 'initMonth', 1);
|
||||
const scenarioId = readMetaNumber(worldMeta, 'scenarioId', 0);
|
||||
const minMonthToAllowInherit = options.uniqueConfig.minMonthToAllowInheritItem;
|
||||
|
||||
return ({ acquireType, reason, general }) => {
|
||||
if (general.npcState >= 2) {
|
||||
return null;
|
||||
}
|
||||
const allGenerals = worldView.listGenerals();
|
||||
const userCount = allGenerals.filter((entry) => entry.npcState < 2).length;
|
||||
if (userCount <= 0) {
|
||||
return null;
|
||||
}
|
||||
const generalItemsList = allGenerals.map((entry) =>
|
||||
entry.id === general.id ? general.role.items : entry.role.items
|
||||
);
|
||||
const occupiedUniqueCounts = countOccupiedUniqueItems(generalItemsList, options.itemRegistry);
|
||||
const rngSeed = buildGenericUniqueSeed(
|
||||
options.seedBase,
|
||||
world.currentYear,
|
||||
world.currentMonth,
|
||||
general.id,
|
||||
reason
|
||||
);
|
||||
const rng = new RandUtil(LiteHashDRBG.build(rngSeed));
|
||||
const inheritRandomUnique = readMetaBool(asRecord(general.meta), 'inheritRandomUnique', false);
|
||||
const relMonthByInit =
|
||||
joinYearMonth(world.currentYear, world.currentMonth) - joinYearMonth(initYear, initMonth);
|
||||
const availableBuyUnique = relMonthByInit >= minMonthToAllowInherit;
|
||||
const itemKey = rollUniqueLottery({
|
||||
rng,
|
||||
config: options.uniqueConfig,
|
||||
itemRegistry: options.itemRegistry,
|
||||
generalItems: general.role.items,
|
||||
occupiedUniqueCounts,
|
||||
scenarioId,
|
||||
userCount,
|
||||
currentYear: world.currentYear,
|
||||
currentMonth: world.currentMonth,
|
||||
startYear,
|
||||
initYear,
|
||||
initMonth,
|
||||
acquireType,
|
||||
inheritRandomUnique,
|
||||
});
|
||||
if (!itemKey) {
|
||||
return null;
|
||||
}
|
||||
if (inheritRandomUnique && availableBuyUnique) {
|
||||
delete asRecord(general.meta).inheritRandomUnique;
|
||||
}
|
||||
return options.itemRegistry.get(itemKey) ?? null;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
type WorldView = {
|
||||
getGeneralById(id: number): TurnGeneral | null;
|
||||
@@ -349,6 +474,8 @@ export const createReservedTurnHandler = async (options: {
|
||||
}) => void;
|
||||
}): Promise<GeneralTurnHandler> => {
|
||||
const env = buildCommandEnv(options.scenarioConfig, options.unitSet);
|
||||
const itemRegistry = createItemModuleRegistry(await loadItemModules([...ITEM_KEYS]));
|
||||
const uniqueConfig = resolveUniqueConfig(asRecord(options.scenarioConfig.const));
|
||||
const commandProfile = options.commandProfile ?? DEFAULT_TURN_COMMAND_PROFILE;
|
||||
const { general: generalDefinitions, nation: nationDefinitions } = await buildReservedTurnDefinitions({
|
||||
env,
|
||||
@@ -518,11 +645,20 @@ export const createReservedTurnHandler = async (options: {
|
||||
};
|
||||
|
||||
const actionArgsRecord = extractArgsRecord(actionArgs);
|
||||
const uniqueLottery = buildUniqueLotteryRunner({
|
||||
world: context.world,
|
||||
worldView,
|
||||
scenarioMeta: options.scenarioMeta,
|
||||
seedBase,
|
||||
itemRegistry,
|
||||
uniqueConfig,
|
||||
});
|
||||
let baseContext: ActionContextBase = {
|
||||
general: currentGeneral,
|
||||
city: currentCity,
|
||||
nation: currentNation,
|
||||
rng: buildRng(actionKey),
|
||||
uniqueLottery,
|
||||
};
|
||||
let specificContext = buildActionContext(
|
||||
actionKey,
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { InMemoryTurnWorld } from '../src/turn/inMemoryWorld.js';
|
||||
import type { TurnGeneral, TurnWorldSnapshot, TurnWorldState } from '../src/turn/types.js';
|
||||
import { createReservedTurnHandler } from '../src/turn/reservedTurnHandler.js';
|
||||
import { InMemoryReservedTurnStore } from '../src/turn/reservedTurnStore.js';
|
||||
import type { TurnSchedule } from '@sammo-ts/logic';
|
||||
|
||||
const buildGeneral = (id: number): TurnGeneral => ({
|
||||
id,
|
||||
name: `General_${id}`,
|
||||
nationId: 1,
|
||||
cityId: 1,
|
||||
troopId: 0,
|
||||
stats: { leadership: 50, strength: 50, intelligence: 50 },
|
||||
turnTime: new Date('0180-01-01T00:00:00Z'),
|
||||
role: {
|
||||
items: { horse: null, weapon: null, book: null, item: null },
|
||||
personality: null,
|
||||
specialDomestic: null,
|
||||
specialWar: null,
|
||||
},
|
||||
triggerState: { flags: {}, counters: {}, modifiers: {}, meta: {} },
|
||||
meta: { killturn: 24 },
|
||||
officerLevel: 1,
|
||||
experience: 0,
|
||||
dedication: 0,
|
||||
injury: 0,
|
||||
gold: 1000,
|
||||
rice: 1000,
|
||||
crew: 100,
|
||||
crewTypeId: 0,
|
||||
train: 0,
|
||||
atmos: 0,
|
||||
age: 30,
|
||||
npcState: 0,
|
||||
});
|
||||
|
||||
describe('unique lottery on general commands', () => {
|
||||
it('awards a unique item for eligible commands', async () => {
|
||||
const schedule: TurnSchedule = { entries: [{ startMinute: 0, tickMinutes: 10 }] };
|
||||
const generals = [buildGeneral(1)];
|
||||
const snapshot: TurnWorldSnapshot = {
|
||||
generals: generals as any,
|
||||
cities: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'City_1',
|
||||
nationId: 1,
|
||||
viewName: 'City_1',
|
||||
agriculture: 100,
|
||||
agricultureMax: 2000,
|
||||
commerce: 100,
|
||||
commerceMax: 2000,
|
||||
security: 100,
|
||||
securityMax: 100,
|
||||
def: 100,
|
||||
defMax: 100,
|
||||
wall: 100,
|
||||
wallMax: 100,
|
||||
pop: 10000,
|
||||
popMax: 50000,
|
||||
trust: 50,
|
||||
supplyState: 1,
|
||||
frontState: 0,
|
||||
tradepoint: 0,
|
||||
level: 1,
|
||||
meta: {},
|
||||
},
|
||||
] as any,
|
||||
nations: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'TestNation',
|
||||
color: '#FF0000',
|
||||
capitalCityId: 1,
|
||||
chiefGeneralId: 1,
|
||||
gold: 10000,
|
||||
rice: 10000,
|
||||
power: 0,
|
||||
level: 1,
|
||||
typeCode: 'che_def',
|
||||
meta: {},
|
||||
},
|
||||
] as any,
|
||||
troops: [],
|
||||
diplomacy: [],
|
||||
events: [],
|
||||
initialEvents: [],
|
||||
map: {
|
||||
id: 'test_map',
|
||||
name: 'TestMap',
|
||||
cities: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'City_1',
|
||||
level: 1,
|
||||
region: 1,
|
||||
position: { x: 0, y: 0 },
|
||||
connections: [],
|
||||
max: {} as any,
|
||||
initial: {} as any,
|
||||
},
|
||||
],
|
||||
defaults: { trust: 50, trade: 100, supplyState: 1, frontState: 0 },
|
||||
} as any,
|
||||
scenarioConfig: {
|
||||
stat: { total: 300, min: 10, max: 100, npcTotal: 150, npcMax: 50, npcMin: 10, chiefMin: 70 },
|
||||
iconPath: '',
|
||||
map: {},
|
||||
const: {
|
||||
allItems: {
|
||||
weapon: {
|
||||
che_무기_12_칠성검: 1,
|
||||
},
|
||||
},
|
||||
maxUniqueItemLimit: [[-1, 1]],
|
||||
uniqueTrialCoef: 10,
|
||||
maxUniqueTrialProb: 10,
|
||||
minMonthToAllowInheritItem: 0,
|
||||
},
|
||||
environment: { mapName: 'test_map', unitSet: 'default' },
|
||||
},
|
||||
scenarioMeta: {
|
||||
startYear: 180,
|
||||
} as any,
|
||||
unitSet: {} as any,
|
||||
};
|
||||
|
||||
const state: TurnWorldState = {
|
||||
id: 1,
|
||||
currentYear: 180,
|
||||
currentMonth: 1,
|
||||
tickSeconds: 3600,
|
||||
lastTurnTime: new Date('0180-01-01T00:00:00Z'),
|
||||
meta: {
|
||||
hiddenSeed: 'seed',
|
||||
scenarioId: 200,
|
||||
initYear: 180,
|
||||
initMonth: 1,
|
||||
scenarioMeta: { startYear: 180 },
|
||||
},
|
||||
};
|
||||
|
||||
const world = new InMemoryTurnWorld(state, snapshot, { schedule });
|
||||
const reservedTurns = new InMemoryReservedTurnStore(
|
||||
{
|
||||
generalTurn: { findMany: async () => [] },
|
||||
nationTurn: { findMany: async () => [] },
|
||||
} as any,
|
||||
{ maxGeneralTurns: 30, maxNationTurns: 12 }
|
||||
);
|
||||
reservedTurns.getGeneralTurns(1)[0] = { action: 'che_훈련', args: {} };
|
||||
|
||||
const handler = await createReservedTurnHandler({
|
||||
reservedTurns,
|
||||
scenarioConfig: snapshot.scenarioConfig,
|
||||
scenarioMeta: snapshot.scenarioMeta,
|
||||
map: snapshot.map,
|
||||
unitSet: snapshot.unitSet,
|
||||
getWorld: () => world,
|
||||
});
|
||||
|
||||
const result = handler.execute({
|
||||
general: world.getGeneralById(1)!,
|
||||
city: world.getCityById(1)!,
|
||||
nation: world.getNationById(1)!,
|
||||
world: world.getState(),
|
||||
schedule,
|
||||
});
|
||||
|
||||
expect(result.general?.role.items.weapon).toBe('che_무기_12_칠성검');
|
||||
const logTexts = (result.logs ?? []).map((entry) => entry.text);
|
||||
expect(logTexts.some((text) => text.includes('【아이템】'))).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { City, General, Nation, Troop } from '@sammo-ts/logic/domain/entities.js';
|
||||
import type { UniqueLotteryRunner } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { ScenarioConfig } from '@sammo-ts/logic/scenario/types.js';
|
||||
import type { ScenarioMeta } from '@sammo-ts/logic/world/types.js';
|
||||
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
@@ -18,6 +19,7 @@ export type ActionContextBase = {
|
||||
city?: City;
|
||||
nation?: Nation | null;
|
||||
rng: ActionRandomSource;
|
||||
uniqueLottery?: UniqueLotteryRunner;
|
||||
};
|
||||
|
||||
export type ActionResolveContext = ActionContextBase & Record<string, unknown>;
|
||||
|
||||
@@ -19,6 +19,7 @@ import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
@@ -101,6 +102,8 @@ export class ActionResolver<
|
||||
const nextLeadershipExp =
|
||||
(typeof general.meta.leadership_exp === 'number' ? general.meta.leadership_exp : 0) + 1;
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
effects.push(
|
||||
createGeneralPatchEffect(
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import type { ActionContextBuilder, ActionContextBase } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
|
||||
export interface UprisingArgs { }
|
||||
@@ -115,6 +116,8 @@ export class ActionDefinition<
|
||||
format: LogFormat.PLAIN,
|
||||
});
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
const effects = [
|
||||
createNationAddEffect(newNation),
|
||||
createGeneralPatchEffect<TriggerState>({
|
||||
|
||||
@@ -20,6 +20,7 @@ import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||
|
||||
@@ -131,6 +132,8 @@ export class ActionDefinition<
|
||||
format: LogFormat.PLAIN,
|
||||
});
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '건국', reason: ACTION_NAME });
|
||||
|
||||
const effects = [
|
||||
createNationPatchEffect(
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { increaseMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||
|
||||
@@ -218,6 +219,7 @@ export class ActionDefinition<
|
||||
general.experience += exp;
|
||||
|
||||
context.addLog(message);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||
|
||||
@@ -112,6 +113,8 @@ export class ActionDefinition<
|
||||
general.experience += 30;
|
||||
general.dedication += 50;
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
|
||||
export interface ReturnArgs {}
|
||||
@@ -115,6 +116,8 @@ export class ActionResolver<
|
||||
const exp = 70;
|
||||
const ded = 100;
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
effects.push(
|
||||
createGeneralPatchEffect(
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
|
||||
export interface TechResearchArgs {}
|
||||
@@ -79,6 +80,7 @@ export class ActionDefinition<
|
||||
general.gold = Math.max(0, general.gold - costGold);
|
||||
|
||||
context.addLog(`${ACTION_NAME}로 기술이 ${applied} 상승했습니다.`);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
@@ -156,6 +157,7 @@ export class ActionDefinition<
|
||||
general.rice = Math.max(0, general.rice - cost);
|
||||
|
||||
context.addLog(logText);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { LogCategory, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||
|
||||
@@ -99,6 +100,8 @@ export class ActionResolver<
|
||||
|
||||
const effects: GeneralActionEffect<TriggerState>[] = [];
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
effects.push(
|
||||
createGeneralPatchEffect(
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import { createGeneralPatchEffect, createLogEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { resolveStartYear } from '@sammo-ts/logic/actions/turn/actionContextHelpers.js';
|
||||
@@ -226,6 +227,8 @@ export class ActionDefinition<
|
||||
)
|
||||
);
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '랜덤 임관', reason: ACTION_NAME });
|
||||
|
||||
return { effects };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/log
|
||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
|
||||
export interface ProcureArgs {}
|
||||
@@ -131,6 +132,8 @@ export class ActionResolver<
|
||||
});
|
||||
}
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return {
|
||||
effects: [
|
||||
createGeneralPatchEffect(
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { clamp } from 'es-toolkit';
|
||||
|
||||
@@ -70,6 +71,7 @@ export class ActionDefinition<
|
||||
general.gold = Math.max(0, general.gold - costGold);
|
||||
|
||||
context.addLog(`${ACTION_NAME}로 사기가 ${applied} 증가했습니다.`);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import type {
|
||||
} from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { clamp } from 'es-toolkit';
|
||||
|
||||
@@ -255,6 +256,7 @@ export class ActionResolver<
|
||||
const pickLabel = result.pick === 'success' ? '성공' : result.pick === 'fail' ? '실패' : '완료';
|
||||
const logMessage = `${ACTION_NAME} ${pickLabel}: +${Math.round(result.score)}`;
|
||||
context.addLog(logMessage);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
@@ -80,6 +81,7 @@ export class ActionDefinition<
|
||||
increaseMetaNumber(general.meta, 'leadership_exp', 2);
|
||||
|
||||
context.addLog(`${srcName} 숙련 ${cutDex}${cutJosa} ${destName} 숙련 ${addDex}${addJosa} 전환했습니다.`);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
|
||||
export interface RetireArgs {}
|
||||
@@ -73,6 +74,8 @@ export class ActionResolver<
|
||||
|
||||
const effects: GeneralActionEffect<TriggerState>[] = [];
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
effects.push(
|
||||
createGeneralPatchEffect(
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@ import { JosaUtil } from '@sammo-ts/common';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import type { MapDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||
@@ -106,6 +107,8 @@ export class ActionResolver<
|
||||
format: LogFormat.MONTH,
|
||||
});
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
for (const target of moveTargets) {
|
||||
const isSelf = target.id === general.id;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import { JosaUtil } from '@sammo-ts/common';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { buildWorldSummary } from '@sammo-ts/logic/actions/turn/actionContextHelpers.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
|
||||
export interface TalentScoutArgs {}
|
||||
@@ -292,6 +293,7 @@ export class ActionResolver<
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
});
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -369,6 +371,8 @@ export class ActionResolver<
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return {
|
||||
effects: [createGeneralAddEffect(newGeneral)],
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||
|
||||
@@ -59,6 +60,8 @@ export class ActionDefinition<
|
||||
format: LogFormat.MONTH,
|
||||
});
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
const effects = [
|
||||
createGeneralPatchEffect<TriggerState>({
|
||||
nationId: args.destNationId,
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { setMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||
|
||||
@@ -54,6 +55,7 @@ export class ActionDefinition<
|
||||
general.role.specialWar = null;
|
||||
setMetaNumber(general.meta, 'specAge2', general.age + 1);
|
||||
context.addLog('새로운 전투 특기를 가질 준비가 되었습니다.');
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
return { effects: [] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import { clamp } from 'es-toolkit';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
|
||||
@@ -68,6 +69,7 @@ export class ActionDefinition<
|
||||
general.rice = Math.max(0, general.rice - costRice);
|
||||
|
||||
context.addLog(`인구가 ${nextValue - current} 증가했습니다.`);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: '정착 장려' });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { clamp } from 'es-toolkit';
|
||||
|
||||
@@ -165,6 +166,7 @@ export class ActionDefinition<
|
||||
general.meta = { ...addMetaNumber(general.meta, STAT_EXP_KEY, 1), max_domestic_critical: 0 };
|
||||
|
||||
context.addLog(`민심이 ${result.trustDelta.toFixed(1)} 상승했습니다.`);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
return { effects: [] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
import { createGeneralPatchEffect, createLogEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||
import { JosaUtil } from '@sammo-ts/common';
|
||||
@@ -78,6 +79,7 @@ export class ActionDefinition<
|
||||
general.experience += 70;
|
||||
general.dedication += 100;
|
||||
increaseMetaNumber(general.meta, 'leadership_exp', 1);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects };
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import type {
|
||||
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { resolveStartYear } from '@sammo-ts/logic/actions/turn/actionContextHelpers.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
@@ -392,6 +393,7 @@ export class ActionResolver<
|
||||
general.meta = addMetaNumber(general.meta, 'leadership_exp', 1);
|
||||
|
||||
context.addLog(logMessage);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||
import { increaseMetaNumber, simpleSerialize } from '@sammo-ts/logic/war/utils.js';
|
||||
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import {
|
||||
buildWarAftermathConfig,
|
||||
buildWarConfig,
|
||||
@@ -509,6 +510,8 @@ export class ActionDefinition<
|
||||
);
|
||||
}
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { LogCategory, LogFormat } from '@sammo-ts/logic/logging/types.js';
|
||||
import { z } from 'zod';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||
|
||||
@@ -60,6 +61,8 @@ export class ActionResolver<
|
||||
format: LogFormat.MONTH,
|
||||
});
|
||||
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return {
|
||||
effects: [
|
||||
createGeneralPatchEffect(
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition
|
||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||
import type { GeneralTurnCommandSpec } from './index.js';
|
||||
import { clamp } from 'es-toolkit';
|
||||
|
||||
@@ -64,6 +65,7 @@ export class ActionDefinition<
|
||||
general.gold = Math.max(0, general.gold - costGold);
|
||||
|
||||
context.addLog(`${ACTION_NAME}을 통해 훈련도가 ${applied} 증가했습니다.`);
|
||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||
|
||||
return { effects: [] };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { asRecord, parseJson, type RandUtil } from '@sammo-ts/common';
|
||||
import type { GeneralItemSlots } from '../domain/entities.js';
|
||||
import { asRecord, JosaUtil, parseJson, type RandUtil } from '@sammo-ts/common';
|
||||
import type { General, GeneralItemSlots, GeneralTriggerState } from '../domain/entities.js';
|
||||
import type { GeneralActionResolveContext } from '../actions/engine.js';
|
||||
import { LogCategory, LogFormat, LogScope } from '../logging/types.js';
|
||||
import type { ItemModule } from '../items/types.js';
|
||||
|
||||
export type UniqueItemPool = Record<string, Record<string, number>>;
|
||||
@@ -7,6 +9,15 @@ export type UniqueItemPool = Record<string, Record<string, number>>;
|
||||
export const UNIQUE_ACQUIRE_TYPES = ['아이템', '설문조사', '랜덤 임관', '건국'] as const;
|
||||
export type UniqueAcquireType = typeof UNIQUE_ACQUIRE_TYPES[number];
|
||||
|
||||
export type UniqueLotteryRequest = {
|
||||
acquireType: UniqueAcquireType;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
export type UniqueLotteryRunner = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
|
||||
request: UniqueLotteryRequest & { general: General<TriggerState> }
|
||||
) => ItemModule | null;
|
||||
|
||||
export type UniqueLotteryConfig = {
|
||||
allItems: UniqueItemPool;
|
||||
maxUniqueItemLimit: Array<[number, number]>;
|
||||
@@ -139,6 +150,17 @@ const serializeSeed = (...values: Array<string | number>): string =>
|
||||
.map((value) => (typeof value === 'string' ? `str(${value.length},${value})` : `int(${Math.floor(value)})`))
|
||||
.join('|');
|
||||
|
||||
export const buildGenericUniqueSeed = (
|
||||
hiddenSeed: string | number,
|
||||
year: number,
|
||||
month: number,
|
||||
generalId: number,
|
||||
reason?: string
|
||||
): string =>
|
||||
reason !== undefined
|
||||
? serializeSeed(hiddenSeed, 'unique', year, month, generalId, reason)
|
||||
: serializeSeed(hiddenSeed, 'unique', year, month, generalId);
|
||||
|
||||
export const buildVoteUniqueSeed = (hiddenSeed: string | number, voteId: number, generalId: number): string =>
|
||||
serializeSeed(hiddenSeed, 'voteUnique', voteId, generalId);
|
||||
|
||||
@@ -280,3 +302,59 @@ export const rollUniqueLottery = (input: UniqueLotteryInput): string | null => {
|
||||
|
||||
return rng.choiceUsingWeightPair(availableUnique);
|
||||
};
|
||||
|
||||
export const applyUniqueItemGain = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
|
||||
context: GeneralActionResolveContext<TriggerState>,
|
||||
itemModule: ItemModule,
|
||||
acquireType: UniqueAcquireType
|
||||
): void => {
|
||||
const general = context.general;
|
||||
const nationName = context.nation?.name ?? '재야';
|
||||
const generalName = general.name;
|
||||
const itemName = itemModule.name;
|
||||
const itemRawName = itemModule.rawName;
|
||||
const josaYi = JosaUtil.pick(generalName, '이');
|
||||
const josaUl = JosaUtil.pick(itemRawName, '을');
|
||||
|
||||
general.role.items[itemModule.slot] = itemModule.key;
|
||||
|
||||
context.addLog(`<C>${itemName}</>${josaUl} 습득했습니다!`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
format: LogFormat.MONTH,
|
||||
});
|
||||
context.addLog(`<C>${itemName}</>${josaUl} 습득`, {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
});
|
||||
context.addLog(`<Y>${generalName}</>${josaYi} <C>${itemName}</>${josaUl} 습득했습니다!`, {
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.SUMMARY,
|
||||
format: LogFormat.MONTH,
|
||||
});
|
||||
context.addLog(
|
||||
`<C><b>【${acquireType}】</b></><D><b>${nationName}</b></>의 <Y>${generalName}</>${josaYi} <C>${itemName}</>${josaUl} 습득했습니다!`,
|
||||
{
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.HISTORY,
|
||||
format: LogFormat.YEAR_MONTH,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const tryApplyUniqueLottery = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
|
||||
context: GeneralActionResolveContext<TriggerState> & { uniqueLottery?: UniqueLotteryRunner },
|
||||
request: UniqueLotteryRequest
|
||||
): boolean => {
|
||||
const runner = context.uniqueLottery;
|
||||
if (!runner) {
|
||||
return false;
|
||||
}
|
||||
const itemModule = runner({ ...request, general: context.general });
|
||||
if (!itemModule) {
|
||||
return false;
|
||||
}
|
||||
applyUniqueItemGain(context, itemModule, request.acquireType);
|
||||
return true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user