refactor(logic): replace arbitrary action hooks with typed events
This commit is contained in:
@@ -60,7 +60,7 @@ commit 또는 삭제를 하지 말아 주세요.
|
|||||||
- `app/game-api`: tRPC/SSE, 조회·입력 API와 battle/auction/tournament worker
|
- `app/game-api`: tRPC/SSE, 조회·입력 API와 battle/auction/tournament worker
|
||||||
- `app/game-engine`: turn daemon, scheduler, 월간 lifecycle와 DB flush
|
- `app/game-engine`: turn daemon, scheduler, 월간 lifecycle와 DB flush
|
||||||
- `packages/common`: 타입, 직렬화, RNG와 공통 유틸리티
|
- `packages/common`: 타입, 직렬화, RNG와 공통 유틸리티
|
||||||
- `packages/logic`: 전투·명령·월간 action 등 도메인 로직
|
- `packages/logic`: 전투·명령·월간 action과 typed action module 도메인 로직
|
||||||
- `packages/infra`: gateway/game Prisma schema, migration과 client
|
- `packages/infra`: gateway/game Prisma schema, migration과 client
|
||||||
- `tools/integration-tests`: PostgreSQL/Redis 및 ref↔core 차등
|
- `tools/integration-tests`: PostgreSQL/Redis 및 ref↔core 차등
|
||||||
- `tools/frontend-legacy-parity`: 실제 Chromium 비교
|
- `tools/frontend-legacy-parity`: 실제 Chromium 비교
|
||||||
@@ -71,6 +71,14 @@ placeholder입니다. 이를 완성된 배포 bundle이나 검증된 profile bui
|
|||||||
않습니다. 운영 build/reset/open은 gateway operation, commit별 worktree와
|
않습니다. 운영 build/reset/open은 gateway operation, commit별 worktree와
|
||||||
orchestrator 실행 경로를 조사해 주세요.
|
orchestrator 실행 경로를 조사해 주세요.
|
||||||
|
|
||||||
|
장수 action은 `packages/logic/src/actionModules/`에 둡니다. 계산 fold,
|
||||||
|
priority/unique-ID trigger와 닫힌 의미 이벤트를 한 범용 hook으로 합치지
|
||||||
|
말아 주세요. 제품용 module 순서는 `loadActionModuleBundle()`의
|
||||||
|
`RefOrderedActionStack`에서만 조립하며, 새 의미 이벤트는
|
||||||
|
`GeneralActionEventPayloadMap`에 payload와 필수 context를 먼저 선언해
|
||||||
|
주세요. 자세한 계약은 `docs/architecture/action-module-protocol.md`에
|
||||||
|
있습니다.
|
||||||
|
|
||||||
## 레거시 매핑과 비교
|
## 레거시 매핑과 비교
|
||||||
|
|
||||||
기능을 변경하기 전에 다음을 end-to-end로 연결해 주세요.
|
기능을 변경하기 전에 다음을 end-to-end로 연결해 주세요.
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ TypeScript로 호환 이관하는 pnpm 모노레포입니다. 기준 구현은
|
|||||||
| `app/game-api` | profile별 tRPC/SSE, 조회·입력 API와 비동기 worker |
|
| `app/game-api` | profile별 tRPC/SSE, 조회·입력 API와 비동기 worker |
|
||||||
| `app/game-engine` | 턴 scheduler/daemon, 월간 처리와 DB flush |
|
| `app/game-engine` | 턴 scheduler/daemon, 월간 처리와 DB flush |
|
||||||
| `packages/common` | 공통 타입, 직렬화, 결정적 RNG와 유틸리티 |
|
| `packages/common` | 공통 타입, 직렬화, 결정적 RNG와 유틸리티 |
|
||||||
| `packages/logic` | 전투·명령·월간 action 등 게임 도메인 로직 |
|
| `packages/logic` | 전투·명령·월간 action과 typed action module 로직 |
|
||||||
| `packages/infra` | game/gateway Prisma schema, migration과 client |
|
| `packages/infra` | game/gateway Prisma schema, migration과 client |
|
||||||
| `packages/tools-scripts` | resource schema 생성·검증 도구 |
|
| `packages/tools-scripts` | resource schema 생성·검증 도구 |
|
||||||
| `tools/integration-tests` | PostgreSQL/Redis 및 ref↔core 통합·차등 테스트 |
|
| `tools/integration-tests` | PostgreSQL/Redis 및 ref↔core 통합·차등 테스트 |
|
||||||
@@ -53,6 +53,12 @@ battle simulation 등 해당 기능의 계약에만 사용하며 게임 mutation
|
|||||||
[`docs/architecture/turn-daemon-lifecycle.md`](docs/architecture/turn-daemon-lifecycle.md)에
|
[`docs/architecture/turn-daemon-lifecycle.md`](docs/architecture/turn-daemon-lifecycle.md)에
|
||||||
있습니다.
|
있습니다.
|
||||||
|
|
||||||
|
장수 특기·관직·병종·계승·아이템 효과는
|
||||||
|
[`docs/architecture/action-module-protocol.md`](docs/architecture/action-module-protocol.md)의
|
||||||
|
계산 hook, 우선순위 trigger, 닫힌 의미 이벤트 경계를 따릅니다. 제품용
|
||||||
|
action stack은 ref의 소유권 순서를 brand한 `loadActionModuleBundle()`에서만
|
||||||
|
조립합니다.
|
||||||
|
|
||||||
## 도구 체인
|
## 도구 체인
|
||||||
|
|
||||||
- pnpm workspace와 Turbo
|
- pnpm workspace와 Turbo
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ import {
|
|||||||
resolveWarBattle,
|
resolveWarBattle,
|
||||||
createItemActionModules,
|
createItemActionModules,
|
||||||
createItemModuleRegistry,
|
createItemModuleRegistry,
|
||||||
|
createRefOrderedActionStack,
|
||||||
ITEM_KEYS,
|
ITEM_KEYS,
|
||||||
loadItemModules,
|
loadItemModules,
|
||||||
createInheritBuffModules,
|
createInheritBuffModules,
|
||||||
createTraitModuleRegistry,
|
createTraitCatalog,
|
||||||
createOfficerLevelActionModules,
|
createOfficerLevelActionModules,
|
||||||
DOMESTIC_TRAIT_KEYS,
|
DOMESTIC_TRAIT_KEYS,
|
||||||
loadDomesticTraitModules,
|
loadDomesticTraitModules,
|
||||||
@@ -30,6 +31,7 @@ import {
|
|||||||
type City,
|
type City,
|
||||||
type General,
|
type General,
|
||||||
type Nation,
|
type Nation,
|
||||||
|
type RefOrderedActionStack,
|
||||||
type UnitSetDefinition,
|
type UnitSetDefinition,
|
||||||
type WarBattleOutcome,
|
type WarBattleOutcome,
|
||||||
type WarActionModule,
|
type WarActionModule,
|
||||||
@@ -48,23 +50,31 @@ const itemWarModules: WarActionModule[] = createItemActionModules(
|
|||||||
createItemModuleRegistry(await loadItemModules([...ITEM_KEYS]))
|
createItemModuleRegistry(await loadItemModules([...ITEM_KEYS]))
|
||||||
).war;
|
).war;
|
||||||
const crewTypeWarTriggerRegistry = createCrewTypeWarTriggerRegistry();
|
const crewTypeWarTriggerRegistry = createCrewTypeWarTriggerRegistry();
|
||||||
const traitRegistry = createTraitModuleRegistry({
|
const traitCatalog = createTraitCatalog({
|
||||||
domestic: await loadDomesticTraitModules([...DOMESTIC_TRAIT_KEYS]),
|
domestic: await loadDomesticTraitModules([...DOMESTIC_TRAIT_KEYS]),
|
||||||
war: await loadWarTraitModules([...WAR_TRAIT_KEYS]),
|
war: await loadWarTraitModules([...WAR_TRAIT_KEYS]),
|
||||||
personality: await loadPersonalityTraitModules([...PERSONALITY_TRAIT_KEYS]),
|
personality: await loadPersonalityTraitModules([...PERSONALITY_TRAIT_KEYS]),
|
||||||
nation: await loadNationTraitModules([...NATION_TRAIT_KEYS]),
|
nation: await loadNationTraitModules([...NATION_TRAIT_KEYS]),
|
||||||
});
|
});
|
||||||
const traitWarModules: WarActionModule[] = [
|
const nationWarModule = new TraitWarActionRouter('nation', traitCatalog);
|
||||||
new TraitWarActionRouter('nation', traitRegistry),
|
const officerWarModule = createOfficerLevelActionModules().war;
|
||||||
createOfficerLevelActionModules().war,
|
const domesticWarModule = new TraitWarActionRouter('domestic', traitCatalog);
|
||||||
new TraitWarActionRouter('domestic', traitRegistry),
|
const warTraitModule = new TraitWarActionRouter('war', traitCatalog);
|
||||||
new TraitWarActionRouter('war', traitRegistry),
|
const personalityWarModule = new TraitWarActionRouter('personality', traitCatalog);
|
||||||
new TraitWarActionRouter('personality', traitRegistry),
|
|
||||||
];
|
|
||||||
|
|
||||||
const buildWarActionModules = (unitSet: UnitSetDefinition): WarActionModule[] => {
|
const buildWarActionModules = (unitSet: UnitSetDefinition): RefOrderedActionStack<WarActionModule> => {
|
||||||
const crewTypeCatalog = compileCrewTypeCatalog(unitSet, crewTypeWarTriggerRegistry);
|
const crewTypeCatalog = compileCrewTypeCatalog(unitSet, crewTypeWarTriggerRegistry);
|
||||||
return [...traitWarModules, crewTypeCatalog.warActionModule, inheritBuffModules.war, ...itemWarModules];
|
return createRefOrderedActionStack<WarActionModule>({
|
||||||
|
nation: nationWarModule,
|
||||||
|
officer: officerWarModule,
|
||||||
|
domestic: domesticWarModule,
|
||||||
|
war: warTraitModule,
|
||||||
|
personality: personalityWarModule,
|
||||||
|
crewType: crewTypeCatalog.warActionModule,
|
||||||
|
inheritance: inheritBuffModules.war,
|
||||||
|
scenario: null,
|
||||||
|
items: itemWarModules,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizeItemCode = (value: string | null): string | null => (value === 'None' ? null : value);
|
const normalizeItemCode = (value: string | null): string | null => (value === 'None' ? null : value);
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ const DISASTER_TEXT_BY_MONTH: Readonly<Record<number, DisasterText[]>> = {
|
|||||||
1: [
|
1: [
|
||||||
{ title: '<M><b>【재난】</b></>', stateCode: 4, body: '역병이 발생하여 도시가 황폐해지고 있습니다.' },
|
{ title: '<M><b>【재난】</b></>', stateCode: 4, body: '역병이 발생하여 도시가 황폐해지고 있습니다.' },
|
||||||
{ title: '<M><b>【재난】</b></>', stateCode: 5, body: '지진으로 피해가 속출하고 있습니다.' },
|
{ title: '<M><b>【재난】</b></>', stateCode: 5, body: '지진으로 피해가 속출하고 있습니다.' },
|
||||||
{ title: '<M><b>【재난】</b></>', stateCode: 3, body: '추위가 풀리지 않아 얼어죽는 백성들이 늘어나고 있습니다.' },
|
{
|
||||||
|
title: '<M><b>【재난】</b></>',
|
||||||
|
stateCode: 3,
|
||||||
|
body: '추위가 풀리지 않아 얼어죽는 백성들이 늘어나고 있습니다.',
|
||||||
|
},
|
||||||
{ title: '<M><b>【재난】</b></>', stateCode: 9, body: '황건적이 출현해 도시를 습격하고 있습니다.' },
|
{ title: '<M><b>【재난】</b></>', stateCode: 9, body: '황건적이 출현해 도시를 습격하고 있습니다.' },
|
||||||
],
|
],
|
||||||
4: [
|
4: [
|
||||||
@@ -67,7 +71,7 @@ const roundLegacyIntegerColumn = (value: number): number => Math.round(value);
|
|||||||
|
|
||||||
export const createRaiseDisasterHandler = (options: {
|
export const createRaiseDisasterHandler = (options: {
|
||||||
getWorld: () => InMemoryTurnWorld | null;
|
getWorld: () => InMemoryTurnWorld | null;
|
||||||
generalActionModules?: GeneralActionModule[];
|
generalActionModules?: ReadonlyArray<GeneralActionModule>;
|
||||||
}): MonthlyEventActionHandler => {
|
}): MonthlyEventActionHandler => {
|
||||||
const generalPipeline = new GeneralActionPipeline(options.generalActionModules ?? []);
|
const generalPipeline = new GeneralActionPipeline(options.generalActionModules ?? []);
|
||||||
|
|
||||||
@@ -95,9 +99,7 @@ export const createRaiseDisasterHandler = (options: {
|
|||||||
throw new Error(`Unsupported month for RaiseDisaster: ${environment.month}`);
|
throw new Error(`Unsupported month for RaiseDisaster: ${environment.month}`);
|
||||||
}
|
}
|
||||||
const rng = new RandUtil(
|
const rng = new RandUtil(
|
||||||
new LiteHashDRBG(
|
new LiteHashDRBG(simpleSerialize(resolveHiddenSeed(world), 'disater', environment.year, environment.month))
|
||||||
simpleSerialize(resolveHiddenSeed(world), 'disater', environment.year, environment.month)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
const isGood = rng.nextBool(boomingRate);
|
const isGood = rng.nextBool(boomingRate);
|
||||||
const targetCities = cities.filter((city) => {
|
const targetCities = cities.filter((city) => {
|
||||||
@@ -135,9 +137,7 @@ export const createRaiseDisasterHandler = (options: {
|
|||||||
world.updateCity(city.id, {
|
world.updateCity(city.id, {
|
||||||
state: picked.stateCode,
|
state: picked.stateCode,
|
||||||
population: roundLegacyIntegerColumn(
|
population: roundLegacyIntegerColumn(
|
||||||
isGood
|
isGood ? Math.min(city.population * affectRatio, city.populationMax) : city.population * affectRatio
|
||||||
? Math.min(city.population * affectRatio, city.populationMax)
|
|
||||||
: city.population * affectRatio
|
|
||||||
),
|
),
|
||||||
agriculture: roundLegacyIntegerColumn(
|
agriculture: roundLegacyIntegerColumn(
|
||||||
isGood
|
isGood
|
||||||
@@ -171,8 +171,7 @@ export const createRaiseDisasterHandler = (options: {
|
|||||||
nation: world.getNationById(general.nationId),
|
nation: world.getNationById(general.nationId),
|
||||||
worldView: {
|
worldView: {
|
||||||
listGenerals: () => allGenerals,
|
listGenerals: () => allGenerals,
|
||||||
listGeneralsByCity: (cityId) =>
|
listGeneralsByCity: (cityId) => allGenerals.filter((candidate) => candidate.cityId === cityId),
|
||||||
allGenerals.filter((candidate) => candidate.cityId === cityId),
|
|
||||||
},
|
},
|
||||||
rng,
|
rng,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -186,8 +186,8 @@ export const buildReservedTurnDefinitions = async (options: {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
options.env.generalActionModules = [...(options.env.generalActionModules ?? []), ...moduleBundle.general];
|
options.env.generalActionModules ??= moduleBundle.general;
|
||||||
options.env.warActionModules = [...(options.env.warActionModules ?? []), ...moduleBundle.war];
|
options.env.warActionModules ??= moduleBundle.war;
|
||||||
options.env.nationTraitModules = moduleBundle.nationTraitModules;
|
options.env.nationTraitModules = moduleBundle.nationTraitModules;
|
||||||
|
|
||||||
const generalSpecs = await loadGeneralTurnCommandSpecs(options.commandProfile.general);
|
const generalSpecs = await loadGeneralTurnCommandSpecs(options.commandProfile.general);
|
||||||
|
|||||||
@@ -976,6 +976,11 @@ export const createReservedTurnHandler = async (options: {
|
|||||||
getAdditionalOccupiedUniqueItemKeys: options.getAdditionalOccupiedUniqueItemKeys,
|
getAdditionalOccupiedUniqueItemKeys: options.getAdditionalOccupiedUniqueItemKeys,
|
||||||
});
|
});
|
||||||
let actionRng = sharedActionRng ?? buildRng(actionKey);
|
let actionRng = sharedActionRng ?? buildRng(actionKey);
|
||||||
|
const actionTime = {
|
||||||
|
year: context.world.currentYear,
|
||||||
|
month: context.world.currentMonth,
|
||||||
|
startYear: resolveStartYear(context.world, options.scenarioMeta),
|
||||||
|
};
|
||||||
let baseContext: ActionContextBase = {
|
let baseContext: ActionContextBase = {
|
||||||
general: currentGeneral,
|
general: currentGeneral,
|
||||||
city: currentCity,
|
city: currentCity,
|
||||||
@@ -991,6 +996,7 @@ export const createReservedTurnHandler = async (options: {
|
|||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
rng: actionRng,
|
rng: actionRng,
|
||||||
|
time: actionTime,
|
||||||
uniqueLottery,
|
uniqueLottery,
|
||||||
};
|
};
|
||||||
let specificContext = buildActionContext(
|
let specificContext = buildActionContext(
|
||||||
@@ -1023,6 +1029,7 @@ export const createReservedTurnHandler = async (options: {
|
|||||||
city: currentCity,
|
city: currentCity,
|
||||||
nation: currentNation,
|
nation: currentNation,
|
||||||
rng: actionRng,
|
rng: actionRng,
|
||||||
|
time: actionTime,
|
||||||
};
|
};
|
||||||
specificContext = baseContext;
|
specificContext = baseContext;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# 장수 행동 모듈 프로토콜
|
||||||
|
|
||||||
|
`packages/logic/src/actionModules/`는 ref의 `iAction`을 그대로 복사한 범용
|
||||||
|
interface가 아니라, 실제 core2026 실행 경계만 타입으로 표현합니다. 계산
|
||||||
|
hook, 우선순위 trigger, 의미 이벤트는 서로 다른 실행 계약입니다.
|
||||||
|
|
||||||
|
## 세 가지 실행 계약
|
||||||
|
|
||||||
|
| 계약 | core2026 경계 | 실행 의미 |
|
||||||
|
| ---------------- | ------------------------------------------------------- | ----------------------------------------------------------------- |
|
||||||
|
| 순차 계산 hook | `GeneralActionPipeline` | ref의 `General::getActionList()` 순서대로 값을 fold합니다. |
|
||||||
|
| 우선순위 trigger | `triggers/core.ts`, `triggers/general.ts`, 전투 trigger | priority, 삽입 순서와 unique ID 중복 제거를 보존한 뒤 fire합니다. |
|
||||||
|
| 의미 이벤트 | `actionModules/events.ts` | 닫힌 이벤트별 payload와 context를 동기적으로 순회합니다. |
|
||||||
|
|
||||||
|
priority trigger를 의미 이벤트로 바꾸거나, 의미 이벤트를 `TriggerCaller`로
|
||||||
|
감싸지 않습니다. 두 경로는 정렬과 중복 제거 의미가 다릅니다.
|
||||||
|
|
||||||
|
## ref 순서와 소유권
|
||||||
|
|
||||||
|
정기턴은 `loadActionModuleBundle()`에서, 전투 시뮬레이터는 같은
|
||||||
|
`createRefOrderedActionStack()` factory에서 제품용 action stack을
|
||||||
|
조립합니다. 순서는 다음과 같습니다.
|
||||||
|
|
||||||
|
1. 국가 타입
|
||||||
|
2. 관직
|
||||||
|
3. 내정 특기
|
||||||
|
4. 전투 특기
|
||||||
|
5. 성격
|
||||||
|
6. 병종
|
||||||
|
7. 계승 버프
|
||||||
|
8. 시나리오 효과
|
||||||
|
9. 아이템
|
||||||
|
|
||||||
|
`RefOrderedActionStack`의 readonly unique-symbol brand는 임의 배열을 제품용
|
||||||
|
표준 stack으로 오인하지 않게 하는 shadow type입니다. 모든 slot을 명시하는
|
||||||
|
factory에서만 이 brand를 만들 수 있으며, 예약턴 runtime env에도 spread하지
|
||||||
|
않고 그대로 전달합니다. 현재 시나리오 효과 runtime module은 이식되지 않아
|
||||||
|
해당 slot은 명시적으로 `null`입니다. 따라서 이 brand는 순서와 slot 소유권을
|
||||||
|
증명하며, 시나리오 효과 구현 완료를 뜻하지 않습니다.
|
||||||
|
|
||||||
|
## 닫힌 의미 이벤트
|
||||||
|
|
||||||
|
`GeneralActionEventPayloadMap`이 허용하는 이벤트와 payload의 단일
|
||||||
|
source입니다. 현재 이벤트는 장비 구매·판매, 계략 성공, 도시 점령입니다.
|
||||||
|
|
||||||
|
- 이벤트는 `createGeneralActionEvent()`만 생성합니다. private
|
||||||
|
unique-symbol brand 때문에 객체 literal로 위조할 수 없습니다.
|
||||||
|
- `GeneralActionEventContext<K>`가 이벤트별 필수 능력을 정합니다. 예를 들어
|
||||||
|
판매는 RNG와 연월, 도시 점령은 RNG가 없으면 compile되지 않습니다.
|
||||||
|
- leaf module은 `eventHandlers`에 처리하는 이벤트 key만 선언합니다.
|
||||||
|
- trait, 병종과 item catalog 같은 합성 router만 내부 `handleEvent`를
|
||||||
|
구현합니다. 두 capability는 `never`를 사용한 상호 배타적 union이라 한
|
||||||
|
module에서 동시에 선언할 수 없습니다.
|
||||||
|
- 새 문자열 action name, `phase`, `aux: Record<string, unknown>`를 범용
|
||||||
|
우회로로 추가하지 않습니다.
|
||||||
|
|
||||||
|
새 이벤트를 추가할 때는 payload map과 context 조건을 먼저 추가한 뒤,
|
||||||
|
실제 producer와 필요한 handler만 연결합니다. 존재하지 않는 handler
|
||||||
|
종류를 interface에 선행 추가하지 않습니다.
|
||||||
|
|
||||||
|
## 저장과 RNG 경계
|
||||||
|
|
||||||
|
의미 이벤트는 producer가 가진 객체를 동기적으로 수정합니다. producer는
|
||||||
|
이벤트 전후의 ref mutation 순서를 그대로 유지한 뒤 기존 effect/flush
|
||||||
|
경계에 결과를 전달합니다.
|
||||||
|
|
||||||
|
- 장비 판매는 판매 대금 반영 → 판매 이벤트 → 슬롯 제거 순서입니다.
|
||||||
|
- 도기 판매의 2분기는 ref `choice([gold, rice])`와 같이 index 0이 금,
|
||||||
|
index 1이 쌀입니다.
|
||||||
|
- 도시 점령은 점령 도시의 수비국 장수 전원을 입력 순서로 호출한 뒤 국가
|
||||||
|
멸망 손실을 계산합니다. 이벤트 handler와 멸망 손실은 같은
|
||||||
|
`ConquerCity` RNG 객체를 이어 씁니다.
|
||||||
|
- 계략 성공 아이템 소비는 `consumeOnStrategySuccess`라는 명시 capability로
|
||||||
|
선언하며 다른 임의 action 이름과 공유하지 않습니다.
|
||||||
|
|
||||||
|
## 검증 경계
|
||||||
|
|
||||||
|
`actionModuleEvents.test.ts`는 표준 순서, 이벤트 brand와 잘못된 context의
|
||||||
|
compile 실패를 검증합니다. `itemActionEvents.test.ts`는 도기 분기와
|
||||||
|
연차 경계, 충차·환약 초기 충전, 계략 성공 소비를 검증합니다.
|
||||||
|
`warAftermath.test.ts`는 도시 점령 대상과 공유 RNG 소비 순서를 검증합니다.
|
||||||
|
ref↔core 실제 명령 차등은
|
||||||
|
`turnCommandGeneralMatrix.integration.test.ts`의 도기 판매 fixture가
|
||||||
|
담당합니다.
|
||||||
@@ -200,6 +200,22 @@ non-item versions (see `ActionItem/che_저격_매화수전.php`).
|
|||||||
per-phase activation.
|
per-phase activation.
|
||||||
- Ensure RNG usage stays deterministic (`RandUtil` everywhere in triggers).
|
- Ensure RNG usage stays deterministic (`RandUtil` everywhere in triggers).
|
||||||
|
|
||||||
|
## Current core2026 boundary
|
||||||
|
|
||||||
|
core2026 does not expose the whole legacy `iAction` surface as one interface.
|
||||||
|
Modifier folds and semantic side effects live under `src/actionModules/`;
|
||||||
|
priority callers remain under `src/triggers/` and the war trigger modules.
|
||||||
|
This separation is required because `TriggerCaller` sorts by priority and
|
||||||
|
deduplicates unique IDs, while semantic events synchronously preserve module
|
||||||
|
order and producer-owned mutation/RNG boundaries.
|
||||||
|
|
||||||
|
The former copied `onArbitraryAction(actionName, phase, aux)` surface was
|
||||||
|
removed. Equipment purchase/sale, strategy success and city conquest now use
|
||||||
|
the closed, nominally branded protocol documented in
|
||||||
|
[장수 행동 모듈 프로토콜](./action-module-protocol.md). This is a core2026
|
||||||
|
typing boundary only; the ref call order and persisted effects remain the
|
||||||
|
compatibility contract.
|
||||||
|
|
||||||
## Related Files
|
## Related Files
|
||||||
|
|
||||||
- `legacy/hwe/sammo/iAction.php`
|
- `legacy/hwe/sammo/iAction.php`
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
이 핸드북은 새 기능을 어디에 넣을지뿐 아니라 요청이 어떤 경계를 지나 상태로 남는지 설명합니다. 먼저
|
이 핸드북은 새 기능을 어디에 넣을지뿐 아니라 요청이 어떤 경계를 지나 상태로 남는지 설명합니다. 먼저
|
||||||
[문서 기준선](../reference-baseline.md)을 확인하고, 변경 성격에 따라 다음 순서로 읽어 주세요.
|
[문서 기준선](../reference-baseline.md)을 확인하고, 변경 성격에 따라 다음 순서로 읽어 주세요.
|
||||||
|
|
||||||
| 변경하려는 것 | 먼저 읽을 문서 | 주로 확인할 코드 |
|
| 변경하려는 것 | 먼저 읽을 문서 | 주로 확인할 코드 |
|
||||||
| -------------------------- | ---------------------------------------------------- | -------------------------------------------- |
|
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
||||||
| 화면·라우팅·조회 API | [시스템 아키텍처](./system-architecture.md) | `app/*-frontend`, `app/*-api` |
|
| 화면·라우팅·조회 API | [시스템 아키텍처](./system-architecture.md) | `app/*-frontend`, `app/*-api` |
|
||||||
| 턴 입력·게임 상태 mutation | [요청·턴·저장 흐름](./request-turn-persistence.md) | `app/game-api`, `app/game-engine` |
|
| 턴 입력·게임 상태 mutation | [요청·턴·저장 흐름](./request-turn-persistence.md) | `app/game-api`, `app/game-engine` |
|
||||||
| 명령·전투·월간 로직 | [도메인 로직과 핵심 클래스](./domain-and-classes.md) | `packages/logic`, `app/game-engine/src/turn` |
|
| 명령·전투·월간 로직 | [도메인 로직과 핵심 클래스](./domain-and-classes.md), [장수 행동 모듈 프로토콜](../architecture/action-module-protocol.md) | `packages/logic`, `app/game-engine/src/turn` |
|
||||||
| 새 파일 위치·검증 범위 | [파일 지도와 변경 절차](./code-map.md) | package manifest, test, docs |
|
| 새 파일 위치·검증 범위 | [파일 지도와 변경 절차](./code-map.md) | package manifest, test, docs |
|
||||||
|
|
||||||
## 읽을 때 지켜야 할 경계
|
## 읽을 때 지켜야 할 경계
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
|
import { compileCrewTypeCatalog } from '@sammo-ts/logic/crewType/catalog.js';
|
||||||
|
import { createCrewTypeWarTriggerRegistry } from '@sammo-ts/logic/war/crewTypeTriggers.js';
|
||||||
|
import { createInheritBuffModules } from '@sammo-ts/logic/inheritance/inheritBuff.js';
|
||||||
|
import {
|
||||||
|
createItemActionModules,
|
||||||
|
createItemModuleRegistry,
|
||||||
|
ITEM_KEYS,
|
||||||
|
loadItemModules,
|
||||||
|
type ItemModule,
|
||||||
|
} from '@sammo-ts/logic/items/index.js';
|
||||||
|
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
|
import type { GeneralActionModule } from './general.js';
|
||||||
|
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||||
|
import { createOfficerLevelActionModules } from './officerLevel.js';
|
||||||
|
import {
|
||||||
|
createTraitCatalog,
|
||||||
|
DOMESTIC_TRAIT_KEYS,
|
||||||
|
loadDomesticTraitModules,
|
||||||
|
loadNationTraitModules,
|
||||||
|
loadPersonalityTraitModules,
|
||||||
|
loadWarTraitModules,
|
||||||
|
NATION_TRAIT_KEYS,
|
||||||
|
PERSONALITY_TRAIT_KEYS,
|
||||||
|
TraitGeneralActionRouter,
|
||||||
|
TraitWarActionRouter,
|
||||||
|
WAR_TRAIT_KEYS,
|
||||||
|
} from './traits/index.js';
|
||||||
|
import type { NationTraitModule } from './traits/nation/index.js';
|
||||||
|
|
||||||
|
export interface ActionModuleBundle<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||||
|
general: RefOrderedActionStack<GeneralActionModule<TriggerState>>;
|
||||||
|
war: RefOrderedActionStack<WarActionModule<TriggerState>>;
|
||||||
|
itemModules: ItemModule<TriggerState>[];
|
||||||
|
nationTraitModules: NationTraitModule[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const refActionOrderBrand: unique symbol = Symbol('RefOrderedActionStack');
|
||||||
|
|
||||||
|
export type RefOrderedActionStack<Module> = ReadonlyArray<Module> & {
|
||||||
|
readonly [refActionOrderBrand]: true;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface RefActionSlots<Module> {
|
||||||
|
nation: Module;
|
||||||
|
officer: Module;
|
||||||
|
domestic: Module;
|
||||||
|
war: Module;
|
||||||
|
personality: Module;
|
||||||
|
crewType: Module | null;
|
||||||
|
inheritance: Module;
|
||||||
|
scenario: Module | null;
|
||||||
|
items: readonly Module[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const markRefOrderedActionStack: <Module>(
|
||||||
|
stack: Module[]
|
||||||
|
) => asserts stack is Module[] & { readonly [refActionOrderBrand]: true } = (stack) => {
|
||||||
|
Object.defineProperty(stack, refActionOrderBrand, {
|
||||||
|
value: true,
|
||||||
|
enumerable: false,
|
||||||
|
writable: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref General::getActionList()의 소유권 순서를 한 곳에서만 조립합니다.
|
||||||
|
export const createRefOrderedActionStack = <Module>(slots: RefActionSlots<Module>): RefOrderedActionStack<Module> => {
|
||||||
|
const stack = [
|
||||||
|
slots.nation,
|
||||||
|
slots.officer,
|
||||||
|
slots.domestic,
|
||||||
|
slots.war,
|
||||||
|
slots.personality,
|
||||||
|
...(slots.crewType ? [slots.crewType] : []),
|
||||||
|
slots.inheritance,
|
||||||
|
...(slots.scenario ? [slots.scenario] : []),
|
||||||
|
...slots.items,
|
||||||
|
];
|
||||||
|
markRefOrderedActionStack(stack);
|
||||||
|
return stack;
|
||||||
|
};
|
||||||
|
|
||||||
|
// General::getActionList와 같은 소유권 순서로 실제 턴과 시뮬레이터의 모듈을 조립한다.
|
||||||
|
export const loadActionModuleBundle = async <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
|
||||||
|
unitSet?: UnitSetDefinition
|
||||||
|
): Promise<ActionModuleBundle<TriggerState>> => {
|
||||||
|
const [domestic, war, personality, nation, itemModules] = await Promise.all([
|
||||||
|
loadDomesticTraitModules([...DOMESTIC_TRAIT_KEYS]),
|
||||||
|
loadWarTraitModules([...WAR_TRAIT_KEYS]),
|
||||||
|
loadPersonalityTraitModules([...PERSONALITY_TRAIT_KEYS]),
|
||||||
|
loadNationTraitModules([...NATION_TRAIT_KEYS]),
|
||||||
|
loadItemModules([...ITEM_KEYS]) as Promise<ItemModule<TriggerState>[]>,
|
||||||
|
]);
|
||||||
|
const traitCatalog = createTraitCatalog<TriggerState>({ domestic, war, personality, nation });
|
||||||
|
const officer = createOfficerLevelActionModules<TriggerState>();
|
||||||
|
const items = createItemActionModules(createItemModuleRegistry(itemModules));
|
||||||
|
const inherit = createInheritBuffModules();
|
||||||
|
const crewTypeCatalog = unitSet?.crewTypes?.length
|
||||||
|
? compileCrewTypeCatalog(unitSet, createCrewTypeWarTriggerRegistry())
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
general: createRefOrderedActionStack<GeneralActionModule<TriggerState>>({
|
||||||
|
nation: new TraitGeneralActionRouter('nation', traitCatalog),
|
||||||
|
officer: officer.general,
|
||||||
|
domestic: new TraitGeneralActionRouter('domestic', traitCatalog),
|
||||||
|
war: new TraitGeneralActionRouter('war', traitCatalog),
|
||||||
|
personality: new TraitGeneralActionRouter('personality', traitCatalog),
|
||||||
|
crewType: crewTypeCatalog
|
||||||
|
? (crewTypeCatalog.generalActionModule as GeneralActionModule<TriggerState>)
|
||||||
|
: null,
|
||||||
|
inheritance: inherit.general as GeneralActionModule<TriggerState>,
|
||||||
|
// scenarioEffect는 현재 core runtime module이 없어 명시적으로 빈 slot입니다.
|
||||||
|
scenario: null,
|
||||||
|
items: items.general,
|
||||||
|
}),
|
||||||
|
war: createRefOrderedActionStack<WarActionModule<TriggerState>>({
|
||||||
|
nation: new TraitWarActionRouter('nation', traitCatalog),
|
||||||
|
officer: officer.war,
|
||||||
|
domestic: new TraitWarActionRouter('domestic', traitCatalog),
|
||||||
|
war: new TraitWarActionRouter('war', traitCatalog),
|
||||||
|
personality: new TraitWarActionRouter('personality', traitCatalog),
|
||||||
|
crewType: crewTypeCatalog ? (crewTypeCatalog.warActionModule as WarActionModule<TriggerState>) : null,
|
||||||
|
inheritance: inherit.war as WarActionModule<TriggerState>,
|
||||||
|
// ref의 scenarioEffect 위치를 보존하되 미이식 module은 별도 gap으로 남깁니다.
|
||||||
|
scenario: null,
|
||||||
|
items: items.war,
|
||||||
|
}),
|
||||||
|
itemModules,
|
||||||
|
nationTraitModules: nation,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import type { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
|
import type { RandomGenerator } from '@sammo-ts/common';
|
||||||
|
|
||||||
|
const generalActionEventBrand: unique symbol = Symbol('GeneralActionEvent');
|
||||||
|
|
||||||
|
export interface GeneralActionEventPayloadMap {
|
||||||
|
'item.purchased': {
|
||||||
|
itemKey: string;
|
||||||
|
slot: 'horse' | 'weapon' | 'book' | 'item';
|
||||||
|
};
|
||||||
|
'item.sold': {
|
||||||
|
itemKey: string;
|
||||||
|
slot: 'horse' | 'weapon' | 'book' | 'item';
|
||||||
|
};
|
||||||
|
'strategy.succeeded': {
|
||||||
|
consumedItems: readonly string[];
|
||||||
|
};
|
||||||
|
'city.conquered': {
|
||||||
|
attacker: General;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GeneralActionEventType = keyof GeneralActionEventPayloadMap;
|
||||||
|
|
||||||
|
export type GeneralActionEventContext<
|
||||||
|
K extends GeneralActionEventType,
|
||||||
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
|
> = K extends 'item.sold' | 'city.conquered'
|
||||||
|
? GeneralActionContext<TriggerState> & { rng: RandomGenerator } & (K extends 'item.sold'
|
||||||
|
? { time: NonNullable<GeneralActionContext<TriggerState>['time']> }
|
||||||
|
: object)
|
||||||
|
: GeneralActionContext<TriggerState>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 레거시 문자열/phase/aux 삼중항을 닫힌 이벤트 계약으로 투영합니다.
|
||||||
|
*
|
||||||
|
* unique-symbol 필드는 런타임 분기용이 아니라 서로 다른 이벤트 payload가
|
||||||
|
* 구조적으로 우연히 호환되는 것을 막는 nominal shadow type입니다. 이벤트는
|
||||||
|
* 반드시 createGeneralActionEvent()로 만들며, handler는 같은 K만 반환합니다.
|
||||||
|
*/
|
||||||
|
export type GeneralActionEvent<
|
||||||
|
K extends GeneralActionEventType,
|
||||||
|
_TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
|
> = Readonly<{
|
||||||
|
type: K;
|
||||||
|
payload: Readonly<GeneralActionEventPayloadMap[K]>;
|
||||||
|
[generalActionEventBrand]: K;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type GeneralActionEventHandler<TriggerState extends GeneralTriggerState, K extends GeneralActionEventType> = {
|
||||||
|
bivarianceHack(
|
||||||
|
context: GeneralActionEventContext<K, TriggerState>,
|
||||||
|
event: GeneralActionEvent<K, TriggerState>
|
||||||
|
): GeneralActionEvent<K, TriggerState> | void;
|
||||||
|
}['bivarianceHack'];
|
||||||
|
|
||||||
|
export type GeneralActionEventHandlers<TriggerState extends GeneralTriggerState = GeneralTriggerState> = Partial<{
|
||||||
|
[K in GeneralActionEventType]: GeneralActionEventHandler<TriggerState, K>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export const createGeneralActionEvent = <
|
||||||
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
|
K extends GeneralActionEventType = GeneralActionEventType,
|
||||||
|
>(
|
||||||
|
type: K,
|
||||||
|
payload: GeneralActionEventPayloadMap[K]
|
||||||
|
): GeneralActionEvent<K, TriggerState> => ({
|
||||||
|
type,
|
||||||
|
payload,
|
||||||
|
[generalActionEventBrand]: type,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const dispatchGeneralActionEventHandlers = <
|
||||||
|
TriggerState extends GeneralTriggerState,
|
||||||
|
K extends GeneralActionEventType,
|
||||||
|
>(
|
||||||
|
handlers: GeneralActionEventHandlers<TriggerState> | null | undefined,
|
||||||
|
context: GeneralActionEventContext<K, TriggerState>,
|
||||||
|
event: GeneralActionEvent<K, TriggerState>
|
||||||
|
): GeneralActionEvent<K, TriggerState> => {
|
||||||
|
// Mapped-type lookup preserves K, but TypeScript cannot currently retain
|
||||||
|
// that correlation through a generic indexed access. This single local
|
||||||
|
// assertion is the proof boundary; module authors and call sites remain
|
||||||
|
// fully checked without unknown/any casts.
|
||||||
|
const handler = handlers?.[event.type] as GeneralActionEventHandler<TriggerState, K> | undefined;
|
||||||
|
return handler?.(context, event) ?? event;
|
||||||
|
};
|
||||||
+53
-33
@@ -1,23 +1,27 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import { type GeneralActionContext, GeneralTriggerCaller } from './general.js';
|
import { type GeneralActionContext, GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralStatName,
|
GeneralStatName,
|
||||||
TriggerActionPhase,
|
|
||||||
TriggerActionType,
|
|
||||||
TriggerDomesticActionType,
|
TriggerDomesticActionType,
|
||||||
TriggerDomesticVarType,
|
TriggerDomesticVarType,
|
||||||
TriggerNationalIncomeType,
|
TriggerNationalIncomeType,
|
||||||
TriggerStrategicActionType,
|
TriggerStrategicActionType,
|
||||||
TriggerStrategicVarType,
|
TriggerStrategicVarType,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
|
import {
|
||||||
|
dispatchGeneralActionEventHandlers,
|
||||||
|
type GeneralActionEvent,
|
||||||
|
type GeneralActionEventContext,
|
||||||
|
type GeneralActionEventHandlers,
|
||||||
|
type GeneralActionEventType,
|
||||||
|
} from './events.js';
|
||||||
|
|
||||||
export interface GeneralActionModule<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
interface GeneralActionModuleBase<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||||
getName?: (() => string) | undefined;
|
getName?: (() => string) | undefined;
|
||||||
getInfo?: (() => string) | undefined;
|
getInfo?: (() => string) | undefined;
|
||||||
|
|
||||||
getPreTurnExecuteTriggerList?:
|
getPreTurnExecuteTriggerList?:
|
||||||
| ((context: GeneralActionContext<TriggerState>) => GeneralTriggerCaller<TriggerState> | null)
|
((context: GeneralActionContext<TriggerState>) => GeneralTriggerCaller<TriggerState> | null) | undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
onCalcDomestic?:
|
onCalcDomestic?:
|
||||||
| ((
|
| ((
|
||||||
@@ -59,22 +63,46 @@ export interface GeneralActionModule<TriggerState extends GeneralTriggerState =
|
|||||||
onCalcNationalIncome?:
|
onCalcNationalIncome?:
|
||||||
| ((context: GeneralActionContext<TriggerState>, type: TriggerNationalIncomeType, amount: number) => number)
|
| ((context: GeneralActionContext<TriggerState>, type: TriggerNationalIncomeType, amount: number) => number)
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
onArbitraryAction?:
|
|
||||||
| ((
|
|
||||||
context: GeneralActionContext<TriggerState>,
|
|
||||||
actionType: TriggerActionType,
|
|
||||||
phase?: TriggerActionPhase | null,
|
|
||||||
aux?: Record<string, unknown> | null
|
|
||||||
) => Record<string, unknown> | null)
|
|
||||||
| undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
interface GeneralActionLeafModule<TriggerState extends GeneralTriggerState> {
|
||||||
private readonly modules: GeneralActionModule<TriggerState>[];
|
eventHandlers?: GeneralActionEventHandlers<TriggerState> | undefined;
|
||||||
|
handleEvent?: never;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
interface GeneralActionCompositeModule<TriggerState extends GeneralTriggerState> {
|
||||||
this.modules = modules.filter(Boolean) as GeneralActionModule<TriggerState>[];
|
eventHandlers?: never;
|
||||||
|
handleEvent<K extends GeneralActionEventType>(
|
||||||
|
context: GeneralActionEventContext<K, TriggerState>,
|
||||||
|
event: GeneralActionEvent<K, TriggerState>
|
||||||
|
): GeneralActionEvent<K, TriggerState>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* leaf handler와 합성 router는 상호 배타적입니다. 한 module이 같은 이벤트를
|
||||||
|
* 두 경로로 중복 처리할 수 없습니다.
|
||||||
|
*/
|
||||||
|
export type GeneralActionModule<TriggerState extends GeneralTriggerState = GeneralTriggerState> =
|
||||||
|
GeneralActionModuleBase<TriggerState> &
|
||||||
|
(GeneralActionLeafModule<TriggerState> | GeneralActionCompositeModule<TriggerState>);
|
||||||
|
|
||||||
|
export const dispatchGeneralActionModuleEvent = <
|
||||||
|
TriggerState extends GeneralTriggerState,
|
||||||
|
K extends GeneralActionEventType,
|
||||||
|
>(
|
||||||
|
module: GeneralActionModule<TriggerState>,
|
||||||
|
context: GeneralActionEventContext<K, TriggerState>,
|
||||||
|
event: GeneralActionEvent<K, TriggerState>
|
||||||
|
): GeneralActionEvent<K, TriggerState> =>
|
||||||
|
module.handleEvent
|
||||||
|
? module.handleEvent(context, event)
|
||||||
|
: dispatchGeneralActionEventHandlers(module.eventHandlers, context, event);
|
||||||
|
|
||||||
|
export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||||
|
private readonly modules: ReadonlyArray<GeneralActionModule<TriggerState>>;
|
||||||
|
|
||||||
|
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||||
|
this.modules = modules.filter(Boolean) as ReadonlyArray<GeneralActionModule<TriggerState>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>): GeneralTriggerCaller<TriggerState> {
|
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>): GeneralTriggerCaller<TriggerState> {
|
||||||
@@ -170,21 +198,13 @@ export class GeneralActionPipeline<TriggerState extends GeneralTriggerState = Ge
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
onArbitraryAction(
|
dispatch<K extends GeneralActionEventType>(
|
||||||
context: GeneralActionContext<TriggerState>,
|
context: GeneralActionEventContext<K, TriggerState>,
|
||||||
actionType: TriggerActionType,
|
event: GeneralActionEvent<K, TriggerState>
|
||||||
phase?: TriggerActionPhase | null,
|
): GeneralActionEvent<K, TriggerState> {
|
||||||
aux?: Record<string, unknown> | null
|
let current = event;
|
||||||
): Record<string, unknown> | null {
|
|
||||||
let current = aux ?? null;
|
|
||||||
for (const module of this.modules) {
|
for (const module of this.modules) {
|
||||||
if (!module.onArbitraryAction) {
|
current = dispatchGeneralActionModuleEvent(module, context, current);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const result = module.onArbitraryAction(context, actionType, phase, current);
|
|
||||||
if (result !== undefined) {
|
|
||||||
current = result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export * from './events.js';
|
||||||
|
export * from './general.js';
|
||||||
|
export * from './types.js';
|
||||||
|
export * from './officerLevel.js';
|
||||||
|
export * from './bundle.js';
|
||||||
|
export * from './traits/index.js';
|
||||||
+2
-4
@@ -1,6 +1,6 @@
|
|||||||
import { asRecord } from '@sammo-ts/common';
|
import { asRecord } from '@sammo-ts/common';
|
||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { GeneralActionModule } from './general-action.js';
|
import type { GeneralActionModule } from './general.js';
|
||||||
import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||||
|
|
||||||
const resolveOfficerLevel = (context: {
|
const resolveOfficerLevel = (context: {
|
||||||
@@ -65,9 +65,7 @@ const officerWarModule: WarActionModule = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createOfficerLevelActionModules = <
|
export const createOfficerLevelActionModules = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(): {
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
|
||||||
>(): {
|
|
||||||
general: GeneralActionModule<TriggerState>;
|
general: GeneralActionModule<TriggerState>;
|
||||||
war: WarActionModule<TriggerState>;
|
war: WarActionModule<TriggerState>;
|
||||||
} => ({
|
} => ({
|
||||||
+56
-41
@@ -1,21 +1,24 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { dispatchGeneralActionModuleEvent, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
|
import {
|
||||||
|
type GeneralActionEvent,
|
||||||
|
type GeneralActionEventContext,
|
||||||
|
type GeneralActionEventType,
|
||||||
|
} from '@sammo-ts/logic/actionModules/events.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralStatName,
|
GeneralStatName,
|
||||||
TriggerActionPhase,
|
|
||||||
TriggerActionType,
|
|
||||||
TriggerDomesticActionType,
|
TriggerDomesticActionType,
|
||||||
TriggerDomesticVarType,
|
TriggerDomesticVarType,
|
||||||
TriggerNationalIncomeType,
|
TriggerNationalIncomeType,
|
||||||
TriggerStrategicActionType,
|
TriggerStrategicActionType,
|
||||||
TriggerStrategicVarType,
|
TriggerStrategicVarType,
|
||||||
WarStatName,
|
WarStatName,
|
||||||
} from '@sammo-ts/logic/triggers/types.js';
|
} from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext, WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { WarUnit } from '@sammo-ts/logic/war/units.js';
|
import type { WarUnit } from '@sammo-ts/logic/war/units.js';
|
||||||
import type { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import type { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import type { TraitKind, TraitModule, TraitModuleRegistry } from './types.js';
|
import type { TraitCatalog, TraitKind, TraitModule } from './types.js';
|
||||||
|
|
||||||
const resolveTraitKey = (
|
const resolveTraitKey = (
|
||||||
context: {
|
context: {
|
||||||
@@ -43,7 +46,7 @@ const resolveTraitKey = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resolveModule = <TriggerState extends GeneralTriggerState>(
|
const resolveModule = <TriggerState extends GeneralTriggerState>(
|
||||||
registry: TraitModuleRegistry<TriggerState>,
|
catalog: TraitCatalog<TriggerState>,
|
||||||
kind: TraitKind,
|
kind: TraitKind,
|
||||||
key: string | null
|
key: string | null
|
||||||
): TraitModule<TriggerState> | null => {
|
): TraitModule<TriggerState> | null => {
|
||||||
@@ -52,29 +55,27 @@ const resolveModule = <TriggerState extends GeneralTriggerState>(
|
|||||||
}
|
}
|
||||||
let bucket: Map<string, TraitModule<TriggerState>>;
|
let bucket: Map<string, TraitModule<TriggerState>>;
|
||||||
if (kind === 'domestic') {
|
if (kind === 'domestic') {
|
||||||
bucket = registry.domestic;
|
bucket = catalog.domestic;
|
||||||
} else if (kind === 'war') {
|
} else if (kind === 'war') {
|
||||||
bucket = registry.war;
|
bucket = catalog.war;
|
||||||
} else if (kind === 'nation') {
|
} else if (kind === 'nation') {
|
||||||
bucket = registry.nation;
|
bucket = catalog.nation;
|
||||||
} else {
|
} else {
|
||||||
bucket = registry.personality;
|
bucket = catalog.personality;
|
||||||
}
|
}
|
||||||
return bucket.get(key) ?? null;
|
return bucket.get(key) ?? null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// General 파이프라인에서 특성(특기/성격) 모듈을 선택해 위임하는 라우터.
|
// General 파이프라인에서 특성(특기/성격) 모듈을 선택해 위임하는 라우터.
|
||||||
export class TraitGeneralActionRouter<
|
export class TraitGeneralActionRouter<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
|
||||||
> implements GeneralActionModule<TriggerState> {
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly kind: TraitKind,
|
private readonly kind: TraitKind,
|
||||||
private readonly registry: TraitModuleRegistry<TriggerState>
|
private readonly catalog: TraitCatalog<TriggerState>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private getModule(context: GeneralActionContext<TriggerState>): TraitModule<TriggerState> | null {
|
private getModule(context: GeneralActionContext<TriggerState>): TraitModule<TriggerState> | null {
|
||||||
const key = resolveTraitKey(context, this.kind);
|
const key = resolveTraitKey(context, this.kind);
|
||||||
return resolveModule(this.registry, this.kind, key);
|
return resolveModule(this.catalog, this.kind, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>) {
|
getPreTurnExecuteTriggerList(context: GeneralActionContext<TriggerState>) {
|
||||||
@@ -132,15 +133,15 @@ export class TraitGeneralActionRouter<
|
|||||||
return module?.onCalcNationalIncome?.(context, type, amount) ?? amount;
|
return module?.onCalcNationalIncome?.(context, type, amount) ?? amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
onArbitraryAction(
|
handleEvent<K extends GeneralActionEventType>(
|
||||||
context: GeneralActionContext<TriggerState>,
|
context: GeneralActionEventContext<K, TriggerState>,
|
||||||
actionType: TriggerActionType,
|
event: GeneralActionEvent<K, TriggerState>
|
||||||
phase?: TriggerActionPhase | null,
|
): GeneralActionEvent<K, TriggerState> {
|
||||||
aux?: Record<string, unknown> | null
|
|
||||||
): Record<string, unknown> | null {
|
|
||||||
const module = this.getModule(context);
|
const module = this.getModule(context);
|
||||||
const result = module?.onArbitraryAction?.(context, actionType, phase, aux);
|
if (!module) {
|
||||||
return result === undefined ? (aux ?? null) : result;
|
return event;
|
||||||
|
}
|
||||||
|
return dispatchGeneralActionModuleEvent(module, context, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,12 +151,12 @@ export class TraitWarActionRouter<
|
|||||||
> implements WarActionModule<TriggerState> {
|
> implements WarActionModule<TriggerState> {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly kind: TraitKind,
|
private readonly kind: TraitKind,
|
||||||
private readonly registry: TraitModuleRegistry<TriggerState>
|
private readonly catalog: TraitCatalog<TriggerState>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private getModule(context: WarActionContext<TriggerState>): TraitModule<TriggerState> | null {
|
private getModule(context: WarActionContext<TriggerState>): TraitModule<TriggerState> | null {
|
||||||
const key = resolveTraitKey(context, this.kind);
|
const key = resolveTraitKey(context, this.kind);
|
||||||
return resolveModule(this.registry, this.kind, key);
|
return resolveModule(this.catalog, this.kind, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBattleInitTriggerList(context: WarActionContext<TriggerState>): WarTriggerCaller | null {
|
getBattleInitTriggerList(context: WarActionContext<TriggerState>): WarTriggerCaller | null {
|
||||||
@@ -199,32 +200,46 @@ export class TraitWarActionRouter<
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TraitModuleSet<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
export interface TraitModuleSet<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||||
general: GeneralActionModule<TriggerState>[];
|
general: ReadonlyArray<GeneralActionModule<TriggerState>>;
|
||||||
war: WarActionModule<TriggerState>[];
|
war: WarActionModule<TriggerState>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createTraitModuleRegistry = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(options: {
|
export const createTraitCatalog = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(options: {
|
||||||
domestic?: TraitModule<TriggerState>[];
|
domestic?: TraitModule<TriggerState>[];
|
||||||
war?: TraitModule<TriggerState>[];
|
war?: TraitModule<TriggerState>[];
|
||||||
personality?: TraitModule<TriggerState>[];
|
personality?: TraitModule<TriggerState>[];
|
||||||
nation?: TraitModule<TriggerState>[];
|
nation?: TraitModule<TriggerState>[];
|
||||||
}): TraitModuleRegistry<TriggerState> => {
|
}): TraitCatalog<TriggerState> => {
|
||||||
const domestic = new Map<string, TraitModule<TriggerState>>();
|
const domestic = new Map<string, TraitModule<TriggerState>>();
|
||||||
const war = new Map<string, TraitModule<TriggerState>>();
|
const war = new Map<string, TraitModule<TriggerState>>();
|
||||||
const personality = new Map<string, TraitModule<TriggerState>>();
|
const personality = new Map<string, TraitModule<TriggerState>>();
|
||||||
const nation = new Map<string, TraitModule<TriggerState>>();
|
const nation = new Map<string, TraitModule<TriggerState>>();
|
||||||
|
|
||||||
|
const insert = (
|
||||||
|
bucket: Map<string, TraitModule<TriggerState>>,
|
||||||
|
kind: TraitKind,
|
||||||
|
module: TraitModule<TriggerState>
|
||||||
|
): void => {
|
||||||
|
if (module.kind !== kind) {
|
||||||
|
throw new Error(`Trait ${module.key} declared kind ${module.kind}, expected ${kind}`);
|
||||||
|
}
|
||||||
|
if (bucket.has(module.key)) {
|
||||||
|
throw new Error(`Duplicate ${kind} trait key: ${module.key}`);
|
||||||
|
}
|
||||||
|
bucket.set(module.key, module);
|
||||||
|
};
|
||||||
|
|
||||||
for (const module of options.domestic ?? []) {
|
for (const module of options.domestic ?? []) {
|
||||||
domestic.set(module.key, module);
|
insert(domestic, 'domestic', module);
|
||||||
}
|
}
|
||||||
for (const module of options.war ?? []) {
|
for (const module of options.war ?? []) {
|
||||||
war.set(module.key, module);
|
insert(war, 'war', module);
|
||||||
}
|
}
|
||||||
for (const module of options.personality ?? []) {
|
for (const module of options.personality ?? []) {
|
||||||
personality.set(module.key, module);
|
insert(personality, 'personality', module);
|
||||||
}
|
}
|
||||||
for (const module of options.nation ?? []) {
|
for (const module of options.nation ?? []) {
|
||||||
nation.set(module.key, module);
|
insert(nation, 'nation', module);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { domestic, war, personality, nation };
|
return { domestic, war, personality, nation };
|
||||||
@@ -232,18 +247,18 @@ export const createTraitModuleRegistry = <TriggerState extends GeneralTriggerSta
|
|||||||
|
|
||||||
// 특성 레지스트리를 General/전투 파이프라인용 모듈 목록으로 변환한다.
|
// 특성 레지스트리를 General/전투 파이프라인용 모듈 목록으로 변환한다.
|
||||||
export const createTraitModules = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
|
export const createTraitModules = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
|
||||||
registry: TraitModuleRegistry<TriggerState>
|
catalog: TraitCatalog<TriggerState>
|
||||||
): TraitModuleSet<TriggerState> => ({
|
): TraitModuleSet<TriggerState> => ({
|
||||||
general: [
|
general: [
|
||||||
new TraitGeneralActionRouter<TriggerState>('domestic', registry),
|
new TraitGeneralActionRouter<TriggerState>('domestic', catalog),
|
||||||
new TraitGeneralActionRouter<TriggerState>('war', registry),
|
new TraitGeneralActionRouter<TriggerState>('war', catalog),
|
||||||
new TraitGeneralActionRouter<TriggerState>('personality', registry),
|
new TraitGeneralActionRouter<TriggerState>('personality', catalog),
|
||||||
new TraitGeneralActionRouter<TriggerState>('nation', registry),
|
new TraitGeneralActionRouter<TriggerState>('nation', catalog),
|
||||||
],
|
],
|
||||||
war: [
|
war: [
|
||||||
new TraitWarActionRouter<TriggerState>('domestic', registry),
|
new TraitWarActionRouter<TriggerState>('domestic', catalog),
|
||||||
new TraitWarActionRouter<TriggerState>('war', registry),
|
new TraitWarActionRouter<TriggerState>('war', catalog),
|
||||||
new TraitWarActionRouter<TriggerState>('personality', registry),
|
new TraitWarActionRouter<TriggerState>('personality', catalog),
|
||||||
new TraitWarActionRouter<TriggerState>('nation', registry),
|
new TraitWarActionRouter<TriggerState>('nation', catalog),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 경작
|
// 내정 특기: 경작
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 귀모
|
// 내정 특기: 귀모
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 발명
|
// 내정 특기: 발명
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 상재
|
// 내정 특기: 상재
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 수비
|
// 내정 특기: 수비
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 인덕
|
// 내정 특기: 인덕
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 축성
|
// 내정 특기: 축성
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js';
|
import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/actionModules/traits/requirements.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 내정 특기: 통찰
|
// 내정 특기: 통찰
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
export const DOMESTIC_TRAIT_KEYS = [
|
export const DOMESTIC_TRAIT_KEYS = [
|
||||||
'che_인덕',
|
'che_인덕',
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
export * from './types.js';
|
export * from './types.js';
|
||||||
export * from './requirements.js';
|
export * from './requirements.js';
|
||||||
export * from './selector.js';
|
export * from './selector.js';
|
||||||
export * from './registry.js';
|
export * from './catalog.js';
|
||||||
export * from './domestic/index.js';
|
export * from './domestic/index.js';
|
||||||
export * from './war/index.js';
|
export * from './war/index.js';
|
||||||
export * from './personality/index.js';
|
export * from './personality/index.js';
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 덕가
|
// 국가 성향: 덕가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 도가
|
// 국가 성향: 도가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 도적
|
// 국가 성향: 도적
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 명가
|
// 국가 성향: 명가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 묵가
|
// 국가 성향: 묵가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 법가
|
// 국가 성향: 법가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 병가
|
// 국가 성향: 병가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 불가
|
// 국가 성향: 불가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 오두미도
|
// 국가 성향: 오두미도
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 유가
|
// 국가 성향: 유가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 음양가
|
// 국가 성향: 음양가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 종횡가
|
// 국가 성향: 종횡가
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 중립
|
// 국가 성향: 중립
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
// 국가 성향: 태평도
|
// 국가 성향: 태평도
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
export const NATION_TRAIT_KEYS = [
|
export const NATION_TRAIT_KEYS = [
|
||||||
'che_중립',
|
'che_중립',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_대의',
|
key: 'che_대의',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_안전',
|
key: 'che_안전',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_왕좌',
|
key: 'che_왕좌',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_유지',
|
key: 'che_유지',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_은둔',
|
key: 'che_은둔',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_의협',
|
key: 'che_의협',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_재간',
|
key: 'che_재간',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_정복',
|
key: 'che_정복',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_출세',
|
key: 'che_출세',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_패권',
|
key: 'che_패권',
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
|
|
||||||
export const traitModule: TraitModule = {
|
export const traitModule: TraitModule = {
|
||||||
key: 'che_할거',
|
key: 'che_할거',
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
export const PERSONALITY_TRAIT_KEYS = [
|
export const PERSONALITY_TRAIT_KEYS = [
|
||||||
'che_안전',
|
'che_안전',
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitSelection } from './requirements.js';
|
import type { TraitSelection } from './requirements.js';
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ export interface TraitModuleExport<TriggerState extends GeneralTriggerState = Ge
|
|||||||
traitModule: TraitModule<TriggerState>;
|
traitModule: TraitModule<TriggerState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TraitModuleRegistry<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
export interface TraitCatalog<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||||
domestic: Map<string, TraitModule<TriggerState>>;
|
domestic: Map<string, TraitModule<TriggerState>>;
|
||||||
war: Map<string, TraitModule<TriggerState>>;
|
war: Map<string, TraitModule<TriggerState>>;
|
||||||
personality: Map<string, TraitModule<TriggerState>>;
|
personality: Map<string, TraitModule<TriggerState>>;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import { che_격노발동, che_격노시도 } from '@sammo-ts/logic/war/triggers/che_격노.js';
|
import { che_격노발동, che_격노시도 } from '@sammo-ts/logic/war/triggers/che_격노.js';
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import { che_부상무효 } from '@sammo-ts/logic/war/triggers/che_견고.js';
|
import { che_부상무효 } from '@sammo-ts/logic/war/triggers/che_견고.js';
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
import { WarUnitCity } from '@sammo-ts/logic/war/units.js';
|
import { WarUnitCity } from '@sammo-ts/logic/war/units.js';
|
||||||
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
||||||
|
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
||||||
|
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
||||||
|
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import { che_돌격지속 } from '@sammo-ts/logic/war/triggers/che_돌격.js';
|
import { che_돌격지속 } from '@sammo-ts/logic/war/triggers/che_돌격.js';
|
||||||
|
|
||||||
+3
-7
@@ -1,8 +1,8 @@
|
|||||||
import type { TriggerValue } from '@sammo-ts/logic/domain/entities.js';
|
import type { TriggerValue } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
|
|
||||||
@@ -53,11 +53,7 @@ export const traitModule: TraitModule = {
|
|||||||
// Note: unit.getGeneral() is only available for WarUnitGeneral.
|
// Note: unit.getGeneral() is only available for WarUnitGeneral.
|
||||||
// In a real scenario, we should check if unit is WarUnitGeneral.
|
// In a real scenario, we should check if unit is WarUnitGeneral.
|
||||||
if (hasGeneral(unit)) {
|
if (hasGeneral(unit)) {
|
||||||
const killnum = getMetaNumber(
|
const killnum = getMetaNumber(unit.getGeneral().meta as Record<string, TriggerValue>, 'rank_killnum', 0);
|
||||||
unit.getGeneral().meta as Record<string, TriggerValue>,
|
|
||||||
'rank_killnum',
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const logVal = Math.log2(Math.max(1, killnum / 5));
|
const logVal = Math.log2(Math.max(1, killnum / 5));
|
||||||
attackMultiplier += logVal / 20;
|
attackMultiplier += logVal / 20;
|
||||||
defenceMultiplier -= logVal / 50;
|
defenceMultiplier -= logVal / 50;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import { che_반계발동, che_반계시도 } from '@sammo-ts/logic/war/triggers/che_반계.js';
|
import { che_반계발동, che_반계시도 } from '@sammo-ts/logic/war/triggers/che_반계.js';
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { getMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
import { getAuxArmType, parseWarDexAux } from './aux.js';
|
||||||
|
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
|
|
||||||
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
|
|
||||||
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import { che_위압발동, che_위압시도 } from '@sammo-ts/logic/war/triggers/che_위압.js';
|
import { che_위압발동, che_위압시도 } from '@sammo-ts/logic/war/triggers/che_위압.js';
|
||||||
+1
-1
@@ -2,7 +2,7 @@ import { GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js';
|
|||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/che_도시치료.js';
|
import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/che_도시치료.js';
|
||||||
import { triggerModule as cheUisulTriggerModule } from '@sammo-ts/logic/war/triggers/che_의술.js';
|
import { triggerModule as cheUisulTriggerModule } from '@sammo-ts/logic/war/triggers/che_의술.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
|
|
||||||
// 전투 특기: 의술
|
// 전투 특기: 의술
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import { che_저격발동, che_저격시도 } from '@sammo-ts/logic/war/triggers/che_저격.js';
|
import { che_저격발동, che_저격시도 } from '@sammo-ts/logic/war/triggers/che_저격.js';
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
|
|
||||||
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
|
|
||||||
const RECRUIT_TRAIN = 70;
|
const RECRUIT_TRAIN = 70;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
|
|
||||||
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js';
|
||||||
import { che_필살강화_회피불가 } from '@sammo-ts/logic/war/triggers/che_필살.js';
|
import { che_필살강화_회피불가 } from '@sammo-ts/logic/war/triggers/che_필살.js';
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js';
|
import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionContext } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
import { TraitRequirement, TraitWeightType } from '../requirements.js';
|
||||||
|
|
||||||
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/actionModules/traits/types.js';
|
||||||
|
|
||||||
export const WAR_TRAIT_KEYS = [
|
export const WAR_TRAIT_KEYS = [
|
||||||
'che_귀병',
|
'che_귀병',
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
export type TriggerActionType = '장비매매' | 'GeneralCommand';
|
|
||||||
|
|
||||||
export type TriggerActionPhase = '판매' | '구매';
|
|
||||||
|
|
||||||
export type TriggerDomesticActionType =
|
export type TriggerDomesticActionType =
|
||||||
| '상업'
|
| '상업'
|
||||||
| '농업'
|
| '농업'
|
||||||
@@ -22,6 +22,11 @@ export type ActionContextBase = {
|
|||||||
worldView?: GeneralWorldView;
|
worldView?: GeneralWorldView;
|
||||||
rng: ActionRandomSource;
|
rng: ActionRandomSource;
|
||||||
uniqueLottery?: UniqueLotteryRunner;
|
uniqueLottery?: UniqueLotteryRunner;
|
||||||
|
time?: {
|
||||||
|
year: number;
|
||||||
|
month: number;
|
||||||
|
startYear: number;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ActionResolveContext = ActionContextBase & Record<string, unknown>;
|
export type ActionResolveContext = ActionContextBase & Record<string, unknown>;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
import type { UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
import type { NationTraitModule } from '@sammo-ts/logic/triggers/special/nation/index.js';
|
import type { NationTraitModule } from '@sammo-ts/logic/actionModules/traits/nation/index.js';
|
||||||
|
import type { RefOrderedActionStack } from '@sammo-ts/logic/actionModules/bundle.js';
|
||||||
|
|
||||||
export interface TurnCommandItemCatalogEntry {
|
export interface TurnCommandItemCatalogEntry {
|
||||||
slot: 'horse' | 'weapon' | 'book' | 'item';
|
slot: 'horse' | 'weapon' | 'book' | 'item';
|
||||||
@@ -56,7 +57,7 @@ export interface TurnCommandEnv {
|
|||||||
npcSeizureMessageProb?: number;
|
npcSeizureMessageProb?: number;
|
||||||
maxResourceActionAmount: number;
|
maxResourceActionAmount: number;
|
||||||
itemCatalog?: Record<string, TurnCommandItemCatalogEntry>;
|
itemCatalog?: Record<string, TurnCommandItemCatalogEntry>;
|
||||||
generalActionModules?: Array<GeneralActionModule>;
|
generalActionModules?: RefOrderedActionStack<GeneralActionModule>;
|
||||||
warActionModules?: Array<WarActionModule>;
|
warActionModules?: RefOrderedActionStack<WarActionModule>;
|
||||||
nationTraitModules?: Array<NationTraitModule>;
|
nationTraitModules?: Array<NationTraitModule>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
|
|||||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { setMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { setMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
import { DOMESTIC_TRAIT_KEYS } from '@sammo-ts/logic/triggers/special/domestic/index.js';
|
import { DOMESTIC_TRAIT_KEYS } from '@sammo-ts/logic/actionModules/traits/domestic/index.js';
|
||||||
|
|
||||||
export interface ResetSpecialDomesticArgs {}
|
export interface ResetSpecialDomesticArgs {}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from './che_징병.js';
|
} from './che_징병.js';
|
||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
|
|
||||||
export class ActionDefinition<
|
export class ActionDefinition<
|
||||||
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
TriggerState extends GeneralTriggerState = GeneralTriggerState,
|
||||||
@@ -14,7 +14,7 @@ export class ActionDefinition<
|
|||||||
public override readonly key = 'che_모병';
|
public override readonly key = 'che_모병';
|
||||||
public override readonly name = '모병';
|
public override readonly name = '모병';
|
||||||
|
|
||||||
constructor(modules: GeneralActionModule<TriggerState>[]) {
|
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState>>) {
|
||||||
super(modules, {
|
super(modules, {
|
||||||
actionName: '모병',
|
actionName: '모병',
|
||||||
costOffset: 2,
|
costOffset: 2,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import { notBeNeutral, notWanderingNation, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
import { notBeNeutral, notWanderingNation, occupiedCity, suppliedCity } from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionOutcome,
|
GeneralActionOutcome,
|
||||||
@@ -31,7 +31,7 @@ export class ActionResolver<
|
|||||||
readonly key = ACTION_KEY;
|
readonly key = ACTION_KEY;
|
||||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||||
this.pipeline = new GeneralActionPipeline(modules);
|
this.pipeline = new GeneralActionPipeline(modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ export class ActionDefinition<
|
|||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
private readonly resolver: ActionResolver<TriggerState>;
|
private readonly resolver: ActionResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>) {
|
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>) {
|
||||||
this.resolver = new ActionResolver(modules);
|
this.resolver = new ActionResolver(modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
|
|||||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { clamp } from 'es-toolkit';
|
import { clamp } from 'es-toolkit';
|
||||||
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
|
|
||||||
export interface BoostMoraleArgs {}
|
export interface BoostMoraleArgs {}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import {
|
|||||||
reqGeneralRice,
|
reqGeneralRice,
|
||||||
suppliedCity,
|
suppliedCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { TriggerDomesticActionType } from '@sammo-ts/logic/triggers/types.js';
|
import type { TriggerDomesticActionType } from '@sammo-ts/logic/actionModules/types.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionOutcome,
|
GeneralActionOutcome,
|
||||||
@@ -168,7 +168,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
|
|||||||
private readonly config: InvestmentConfig;
|
private readonly config: InvestmentConfig;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
env: InvestmentEnvironment,
|
env: InvestmentEnvironment,
|
||||||
config: InvestmentConfig = DEFAULT_CONFIG
|
config: InvestmentConfig = DEFAULT_CONFIG
|
||||||
) {
|
) {
|
||||||
@@ -324,7 +324,7 @@ export class ActionResolver<
|
|||||||
private readonly config: InvestmentConfig;
|
private readonly config: InvestmentConfig;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
env: InvestmentEnvironment,
|
env: InvestmentEnvironment,
|
||||||
config: InvestmentConfig = DEFAULT_CONFIG
|
config: InvestmentConfig = DEFAULT_CONFIG
|
||||||
) {
|
) {
|
||||||
@@ -398,7 +398,7 @@ export class ActionDefinition<
|
|||||||
private readonly config: InvestmentConfig;
|
private readonly config: InvestmentConfig;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
env: InvestmentEnvironment,
|
env: InvestmentEnvironment,
|
||||||
config: InvestmentConfig = DEFAULT_CONFIG
|
config: InvestmentConfig = DEFAULT_CONFIG
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/ac
|
|||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
|
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
|
||||||
import {
|
import {
|
||||||
buildStrategyActionContext,
|
buildStrategyActionContext,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-t
|
|||||||
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js';
|
||||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
|
|
||||||
export interface DisbandArgs {}
|
export interface DisbandArgs {}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import type {
|
|||||||
} from '@sammo-ts/logic/domain/entities.js';
|
} from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
import type { Constraint, ConstraintContext } from '@sammo-ts/logic/constraints/types.js';
|
||||||
import { reqGeneralGold, reqGeneralRice } from '@sammo-ts/logic/constraints/presets.js';
|
import { reqGeneralGold, reqGeneralRice } from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionOutcome,
|
GeneralActionOutcome,
|
||||||
@@ -175,12 +175,11 @@ const legacyChoiceIndex = (rng: RandomGenerator, length: number): number => {
|
|||||||
throw new Error('Empty items');
|
throw new Error('Empty items');
|
||||||
}
|
}
|
||||||
const inclusive = rng as InclusiveRandomGenerator;
|
const inclusive = rng as InclusiveRandomGenerator;
|
||||||
return inclusive.nextIntInclusive
|
return inclusive.nextIntInclusive ? inclusive.nextIntInclusive(length - 1) : rng.nextInt(0, length);
|
||||||
? inclusive.nextIntInclusive(length - 1)
|
|
||||||
: rng.nextInt(0, length);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const legacyChoice = <T>(rng: RandomGenerator, values: readonly T[]): T => values[legacyChoiceIndex(rng, values.length)]!;
|
const legacyChoice = <T>(rng: RandomGenerator, values: readonly T[]): T =>
|
||||||
|
values[legacyChoiceIndex(rng, values.length)]!;
|
||||||
|
|
||||||
const resolveCandidate = (
|
const resolveCandidate = (
|
||||||
context: TalentScoutResolveContext,
|
context: TalentScoutResolveContext,
|
||||||
@@ -239,7 +238,10 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
|
|||||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||||
private readonly env: TalentScoutEnvironment;
|
private readonly env: TalentScoutEnvironment;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: TalentScoutEnvironment) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
env: TalentScoutEnvironment
|
||||||
|
) {
|
||||||
this.pipeline = new GeneralActionPipeline(modules);
|
this.pipeline = new GeneralActionPipeline(modules);
|
||||||
this.env = env;
|
this.env = env;
|
||||||
}
|
}
|
||||||
@@ -269,7 +271,10 @@ export class ActionResolver<
|
|||||||
private readonly env: TalentScoutEnvironment;
|
private readonly env: TalentScoutEnvironment;
|
||||||
private readonly command: CommandResolver<TriggerState>;
|
private readonly command: CommandResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: TalentScoutEnvironment) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
env: TalentScoutEnvironment
|
||||||
|
) {
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.command = new CommandResolver(modules, env);
|
this.command = new CommandResolver(modules, env);
|
||||||
}
|
}
|
||||||
@@ -353,20 +358,19 @@ export class ActionResolver<
|
|||||||
let dex: [number, number, number, number, number];
|
let dex: [number, number, number, number, number];
|
||||||
if (pickType === '무') {
|
if (pickType === '무') {
|
||||||
const distributions = [
|
const distributions = [
|
||||||
[dexTotal * 5 / 8, dexTotal / 8, dexTotal / 8, dexTotal / 8],
|
[(dexTotal * 5) / 8, dexTotal / 8, dexTotal / 8, dexTotal / 8],
|
||||||
[dexTotal / 8, dexTotal * 5 / 8, dexTotal / 8, dexTotal / 8],
|
[dexTotal / 8, (dexTotal * 5) / 8, dexTotal / 8, dexTotal / 8],
|
||||||
[dexTotal / 8, dexTotal / 8, dexTotal * 5 / 8, dexTotal / 8],
|
[dexTotal / 8, dexTotal / 8, (dexTotal * 5) / 8, dexTotal / 8],
|
||||||
] as const;
|
] as const;
|
||||||
const picked = legacyChoice(context.rng, distributions);
|
const picked = legacyChoice(context.rng, distributions);
|
||||||
dex = [picked[0], picked[1], picked[2], picked[3], averageDex[4]];
|
dex = [picked[0], picked[1], picked[2], picked[3], averageDex[4]];
|
||||||
} else if (pickType === '지') {
|
} else if (pickType === '지') {
|
||||||
dex = [dexTotal / 8, dexTotal / 8, dexTotal / 8, dexTotal * 5 / 8, averageDex[4]];
|
dex = [dexTotal / 8, dexTotal / 8, dexTotal / 8, (dexTotal * 5) / 8, averageDex[4]];
|
||||||
} else {
|
} else {
|
||||||
dex = [dexTotal / 4, dexTotal / 4, dexTotal / 4, dexTotal / 4, averageDex[4]];
|
dex = [dexTotal / 4, dexTotal / 4, dexTotal / 4, dexTotal / 4, averageDex[4]];
|
||||||
}
|
}
|
||||||
const personality =
|
const personality =
|
||||||
resolvedCandidate.personality ??
|
resolvedCandidate.personality ?? legacyChoice(context.rng, this.env.availablePersonalities ?? ['che_안전']);
|
||||||
legacyChoice(context.rng, this.env.availablePersonalities ?? ['che_안전']);
|
|
||||||
const name = this.env.decorateName
|
const name = this.env.decorateName
|
||||||
? this.env.decorateName(resolvedCandidate.name, NPC_TYPE)
|
? this.env.decorateName(resolvedCandidate.name, NPC_TYPE)
|
||||||
: `ⓜ${resolvedCandidate.name}`;
|
: `ⓜ${resolvedCandidate.name}`;
|
||||||
@@ -374,10 +378,7 @@ export class ActionResolver<
|
|||||||
const turnSecond = randomRangeInt(context.rng, 0, context.turnTermMinutes * 60 - 1);
|
const turnSecond = randomRangeInt(context.rng, 0, context.turnTermMinutes * 60 - 1);
|
||||||
const turnFraction = randomRangeInt(context.rng, 0, 999_999);
|
const turnFraction = randomRangeInt(context.rng, 0, 999_999);
|
||||||
const killturn =
|
const killturn =
|
||||||
(deathYear - context.currentYear) * 12 +
|
(deathYear - context.currentYear) * 12 + randomRangeInt(context.rng, 0, 11) + context.currentMonth - 1;
|
||||||
randomRangeInt(context.rng, 0, 11) +
|
|
||||||
context.currentMonth -
|
|
||||||
1;
|
|
||||||
const meta: GeneralMeta = {
|
const meta: GeneralMeta = {
|
||||||
killturn,
|
killturn,
|
||||||
npcType: NPC_TYPE,
|
npcType: NPC_TYPE,
|
||||||
@@ -461,7 +462,10 @@ export class ActionDefinition<
|
|||||||
private readonly command: CommandResolver<TriggerState>;
|
private readonly command: CommandResolver<TriggerState>;
|
||||||
private readonly resolver: ActionResolver<TriggerState>;
|
private readonly resolver: ActionResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: TalentScoutEnvironment) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
env: TalentScoutEnvironment
|
||||||
|
) {
|
||||||
this.command = new CommandResolver(modules, env);
|
this.command = new CommandResolver(modules, env);
|
||||||
this.resolver = new ActionResolver(modules, env);
|
this.resolver = new ActionResolver(modules, env);
|
||||||
}
|
}
|
||||||
@@ -517,6 +521,5 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
category: '인사',
|
category: '인사',
|
||||||
reqArg: false,
|
reqArg: false,
|
||||||
|
|
||||||
createDefinition: (env: TurnCommandEnv) =>
|
createDefinition: (env: TurnCommandEnv) => new ActionDefinition(env.generalActionModules ?? [], env),
|
||||||
new ActionDefinition(env.generalActionModules ?? [], env),
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,8 +8,12 @@ import {
|
|||||||
reqGeneralRice,
|
reqGeneralRice,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type { GeneralActionOutcome, GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type {
|
||||||
import { createGeneralPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
GeneralActionEffect,
|
||||||
|
GeneralActionOutcome,
|
||||||
|
GeneralActionResolveContext,
|
||||||
|
} from '@sammo-ts/logic/actions/engine.js';
|
||||||
|
import { createGeneralPatchEffect, createNationPatchEffect } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
import { LogCategory, LogFormat, LogScope } from '@sammo-ts/logic/logging/types.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@@ -19,6 +23,8 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
|
|||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
import { equipNewItem, removeEquippedItem } from '@sammo-ts/logic/items/inventory.js';
|
import { equipNewItem, removeEquippedItem } from '@sammo-ts/logic/items/inventory.js';
|
||||||
|
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
|
import { createGeneralActionEvent } from '@sammo-ts/logic/actionModules/events.js';
|
||||||
|
|
||||||
const ACTION_NAME = '장비매매';
|
const ACTION_NAME = '장비매매';
|
||||||
const ACTION_KEY = 'che_장비매매';
|
const ACTION_KEY = 'che_장비매매';
|
||||||
@@ -54,8 +60,11 @@ export class ActionDefinition<
|
|||||||
> implements GeneralActionDefinition<TriggerState, TradeItemArgs> {
|
> implements GeneralActionDefinition<TriggerState, TradeItemArgs> {
|
||||||
public readonly key = ACTION_KEY;
|
public readonly key = ACTION_KEY;
|
||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
|
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||||
|
|
||||||
constructor(private readonly env: TurnCommandEnv) {}
|
constructor(private readonly env: TurnCommandEnv) {
|
||||||
|
this.pipeline = new GeneralActionPipeline(env.generalActionModules ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): TradeItemArgs | null {
|
parseArgs(raw: unknown): TradeItemArgs | null {
|
||||||
const args = parseArgsWithSchema(ARGS_SCHEMA, raw);
|
const args = parseArgsWithSchema(ARGS_SCHEMA, raw);
|
||||||
@@ -144,6 +153,7 @@ export class ActionDefinition<
|
|||||||
): GeneralActionOutcome<TriggerState> {
|
): GeneralActionOutcome<TriggerState> {
|
||||||
const general = context.general;
|
const general = context.general;
|
||||||
const nation = context.nation;
|
const nation = context.nation;
|
||||||
|
const nationResourcesBeforeEvent = nation ? { gold: nation.gold, rice: nation.rice } : null;
|
||||||
|
|
||||||
const itemType = args.itemType;
|
const itemType = args.itemType;
|
||||||
const requestedItemCode = args.itemCode;
|
const requestedItemCode = args.itemCode;
|
||||||
@@ -162,14 +172,6 @@ export class ActionDefinition<
|
|||||||
const josaUl = JosaUtil.pick(itemRawName, '을');
|
const josaUl = JosaUtil.pick(itemRawName, '을');
|
||||||
|
|
||||||
const nextGold = buying ? Math.max(0, general.gold - itemCost) : general.gold + Math.floor(itemCost / 2);
|
const nextGold = buying ? Math.max(0, general.gold - itemCost) : general.gold + Math.floor(itemCost / 2);
|
||||||
if (buying) {
|
|
||||||
equipNewItem(general, itemType, finalItemCode, {
|
|
||||||
...(item?.initialCharges === undefined ? {} : { charges: item.initialCharges }),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
removeEquippedItem(general, itemType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buying) {
|
if (buying) {
|
||||||
context.addLog(`<C>${itemName}</>${josaUl} 구입했습니다.`, {
|
context.addLog(`<C>${itemName}</>${josaUl} 구입했습니다.`, {
|
||||||
scope: LogScope.GENERAL,
|
scope: LogScope.GENERAL,
|
||||||
@@ -184,6 +186,43 @@ export class ActionDefinition<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
general.gold = nextGold;
|
||||||
|
if (buying) {
|
||||||
|
equipNewItem(general, itemType, finalItemCode, {
|
||||||
|
...(item?.initialCharges === undefined ? {} : { charges: item.initialCharges }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventLog = {
|
||||||
|
push: (message: string) =>
|
||||||
|
context.addLog(message, {
|
||||||
|
scope: LogScope.GENERAL,
|
||||||
|
category: LogCategory.ACTION,
|
||||||
|
format: LogFormat.MONTH,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
if (buying) {
|
||||||
|
this.pipeline.dispatch(
|
||||||
|
{ ...context, log: eventLog },
|
||||||
|
createGeneralActionEvent<TriggerState, 'item.purchased'>('item.purchased', {
|
||||||
|
itemKey: finalItemCode,
|
||||||
|
slot: itemType,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (!context.time) {
|
||||||
|
throw new Error('장비 판매 이벤트에는 현재 연도와 시나리오 시작 연도가 필요합니다.');
|
||||||
|
}
|
||||||
|
this.pipeline.dispatch(
|
||||||
|
{ ...context, time: context.time, log: eventLog },
|
||||||
|
createGeneralActionEvent<TriggerState, 'item.sold'>('item.sold', {
|
||||||
|
itemKey: finalItemCode,
|
||||||
|
slot: itemType,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
removeEquippedItem(general, itemType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!buying && item && !item.buyable && nation) {
|
if (!buying && item && !item.buyable && nation) {
|
||||||
const josaYi = JosaUtil.pick(general.name, '이');
|
const josaYi = JosaUtil.pick(general.name, '이');
|
||||||
context.addLog(`<Y>${general.name}</>${josaYi} <C>${itemName}</>${josaUl} 판매했습니다!`, {
|
context.addLog(`<Y>${general.name}</>${josaYi} <C>${itemName}</>${josaUl} 판매했습니다!`, {
|
||||||
@@ -201,13 +240,31 @@ export class ActionDefinition<
|
|||||||
|
|
||||||
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
tryApplyUniqueLottery(context, { acquireType: '아이템', reason: ACTION_NAME });
|
||||||
|
|
||||||
|
const effects: Array<GeneralActionEffect<TriggerState>> = [
|
||||||
|
createGeneralPatchEffect<TriggerState>({
|
||||||
|
gold: general.gold,
|
||||||
|
rice: general.rice,
|
||||||
|
experience: general.experience + 10,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
if (
|
||||||
|
nation &&
|
||||||
|
nationResourcesBeforeEvent &&
|
||||||
|
(nation.gold !== nationResourcesBeforeEvent.gold || nation.rice !== nationResourcesBeforeEvent.rice)
|
||||||
|
) {
|
||||||
|
effects.push(
|
||||||
|
createNationPatchEffect(
|
||||||
|
{
|
||||||
|
gold: nation.gold,
|
||||||
|
rice: nation.rice,
|
||||||
|
},
|
||||||
|
nation.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
effects: [
|
effects,
|
||||||
createGeneralPatchEffect<TriggerState>({
|
|
||||||
gold: nextGold,
|
|
||||||
experience: general.experience + 10,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/action
|
|||||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { setMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
import { setMetaNumber } from '@sammo-ts/logic/war/utils.js';
|
||||||
import { WAR_TRAIT_KEYS } from '@sammo-ts/logic/triggers/special/war/index.js';
|
import { WAR_TRAIT_KEYS } from '@sammo-ts/logic/actionModules/traits/war/index.js';
|
||||||
|
|
||||||
export interface ResetSpecialWarArgs {}
|
export interface ResetSpecialWarArgs {}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
reqGeneralGold,
|
reqGeneralGold,
|
||||||
reqGeneralRice,
|
reqGeneralRice,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionOutcome,
|
GeneralActionOutcome,
|
||||||
@@ -217,7 +217,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
|
|||||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||||
private readonly env: RecruitEnvironment;
|
private readonly env: RecruitEnvironment;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
|
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
|
||||||
this.pipeline = new GeneralActionPipeline(modules);
|
this.pipeline = new GeneralActionPipeline(modules);
|
||||||
this.env = env;
|
this.env = env;
|
||||||
}
|
}
|
||||||
@@ -331,7 +331,7 @@ export class ActionResolver<
|
|||||||
private readonly env: RecruitEnvironment;
|
private readonly env: RecruitEnvironment;
|
||||||
private readonly command: CommandResolver<TriggerState>;
|
private readonly command: CommandResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
|
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.command = new CommandResolver(modules, env);
|
this.command = new CommandResolver(modules, env);
|
||||||
}
|
}
|
||||||
@@ -444,7 +444,7 @@ export class ActionDefinition<
|
|||||||
private readonly resolver: ActionResolver<TriggerState>;
|
private readonly resolver: ActionResolver<TriggerState>;
|
||||||
private readonly env: RecruitEnvironment;
|
private readonly env: RecruitEnvironment;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
|
constructor(modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>, env: RecruitEnvironment) {
|
||||||
this.command = new CommandResolver(modules, env);
|
this.command = new CommandResolver(modules, env);
|
||||||
this.resolver = new ActionResolver(modules, env);
|
this.resolver = new ActionResolver(modules, env);
|
||||||
this.env = env;
|
this.env = env;
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ import type { WarAftermathConfig, WarEngineConfig, WarTimeContext } from '@sammo
|
|||||||
import { resolveWarAftermath } from '@sammo-ts/logic/war/aftermath.js';
|
import { resolveWarAftermath } from '@sammo-ts/logic/war/aftermath.js';
|
||||||
import { resolveWarBattle } from '@sammo-ts/logic/war/engine.js';
|
import { resolveWarBattle } from '@sammo-ts/logic/war/engine.js';
|
||||||
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||||
import type { NationTraitModule } from '@sammo-ts/logic/triggers/special/nation/index.js';
|
import type { NationTraitModule } from '@sammo-ts/logic/actionModules/traits/nation/index.js';
|
||||||
|
import type { GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import { increaseMetaNumber, simpleSerialize } from '@sammo-ts/logic/war/utils.js';
|
import { increaseMetaNumber, simpleSerialize } from '@sammo-ts/logic/war/utils.js';
|
||||||
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
import type { MapDefinition, UnitSetDefinition } from '@sammo-ts/logic/world/types.js';
|
||||||
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import type { ActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
@@ -163,9 +164,7 @@ const pickCandidateCity = (
|
|||||||
const legacyCompatibleRng = rng as typeof rng & {
|
const legacyCompatibleRng = rng as typeof rng & {
|
||||||
nextIntInclusive?: (maxInclusive: number) => number;
|
nextIntInclusive?: (maxInclusive: number) => number;
|
||||||
};
|
};
|
||||||
const index =
|
const index = legacyCompatibleRng.nextIntInclusive?.(items.length - 1) ?? rng.nextInt(0, items.length);
|
||||||
legacyCompatibleRng.nextIntInclusive?.(items.length - 1) ??
|
|
||||||
rng.nextInt(0, items.length);
|
|
||||||
return items[index]!;
|
return items[index]!;
|
||||||
};
|
};
|
||||||
const distances = Array.from(distanceList.keys()).sort((a, b) => a - b);
|
const distances = Array.from(distanceList.keys()).sort((a, b) => a - b);
|
||||||
@@ -255,15 +254,18 @@ export class ActionDefinition<
|
|||||||
getInheritanceActiveActionAmount(): number {
|
getInheritanceActiveActionAmount(): number {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
private readonly warModules: Array<WarActionModule<TriggerState>>;
|
private readonly warModules: ReadonlyArray<WarActionModule<TriggerState>>;
|
||||||
private readonly nationTraitModules: Map<string, NationTraitModule>;
|
private readonly nationTraitModules: Map<string, NationTraitModule>;
|
||||||
|
private readonly generalModules: ReadonlyArray<GeneralActionModule<TriggerState>>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
modules: Array<WarActionModule<TriggerState> | null | undefined> = [],
|
modules: ReadonlyArray<WarActionModule<TriggerState> | null | undefined> = [],
|
||||||
nationTraitModules: NationTraitModule[] = []
|
nationTraitModules: NationTraitModule[] = [],
|
||||||
|
generalModules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined> = []
|
||||||
) {
|
) {
|
||||||
this.warModules = modules.filter(Boolean) as Array<WarActionModule<TriggerState>>;
|
this.warModules = modules.filter(Boolean) as ReadonlyArray<WarActionModule<TriggerState>>;
|
||||||
this.nationTraitModules = new Map(nationTraitModules.map((module) => [module.key, module]));
|
this.nationTraitModules = new Map(nationTraitModules.map((module) => [module.key, module]));
|
||||||
|
this.generalModules = generalModules.filter(Boolean) as ReadonlyArray<GeneralActionModule<TriggerState>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseArgs(raw: unknown): DispatchArgs | null {
|
parseArgs(raw: unknown): DispatchArgs | null {
|
||||||
@@ -474,15 +476,12 @@ export class ActionDefinition<
|
|||||||
config: context.aftermathConfig,
|
config: context.aftermathConfig,
|
||||||
time,
|
time,
|
||||||
hiddenSeed: context.seedBase,
|
hiddenSeed: context.seedBase,
|
||||||
|
generalActionModules: this.generalModules,
|
||||||
calcNationTechGain: ({ nation, baseGain }) => {
|
calcNationTechGain: ({ nation, baseGain }) => {
|
||||||
const module = this.nationTraitModules.get(nation.typeCode);
|
const module = this.nationTraitModules.get(nation.typeCode);
|
||||||
return (
|
return (
|
||||||
module?.onCalcDomestic?.(
|
module?.onCalcDomestic?.({ general: context.general, nation }, '기술', 'score', baseGain) ??
|
||||||
{ general: context.general, nation },
|
baseGain
|
||||||
'기술',
|
|
||||||
'score',
|
|
||||||
baseGain
|
|
||||||
) ?? baseGain
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -601,5 +600,5 @@ export const commandSpec: GeneralTurnCommandSpec = {
|
|||||||
availabilityArgs: { destCityId: 0 },
|
availabilityArgs: { destCityId: 0 },
|
||||||
argsSchema: ARGS_SCHEMA,
|
argsSchema: ARGS_SCHEMA,
|
||||||
createDefinition: (env: TurnCommandEnv) =>
|
createDefinition: (env: TurnCommandEnv) =>
|
||||||
new ActionDefinition(env.warActionModules ?? [], env.nationTraitModules ?? []),
|
new ActionDefinition(env.warActionModules ?? [], env.nationTraitModules ?? [], env.generalActionModules ?? []),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/ac
|
|||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
|
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
|
||||||
import {
|
import {
|
||||||
buildStrategyActionContext,
|
buildStrategyActionContext,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import type { ActionContextBase, ActionContextOptions } from '@sammo-ts/logic/ac
|
|||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { JosaUtil } from '@sammo-ts/common';
|
import { JosaUtil } from '@sammo-ts/common';
|
||||||
import { parseArgsWithSchema } from '../parseArgs.js';
|
import { parseArgsWithSchema } from '../parseArgs.js';
|
||||||
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
|
import { consumeSuccessfulStrategyItem } from './strategyItemConsumption.js';
|
||||||
import {
|
import {
|
||||||
buildStrategyActionContext,
|
buildStrategyActionContext,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
suppliedCity,
|
suppliedCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js';
|
||||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionEffect,
|
GeneralActionEffect,
|
||||||
@@ -125,7 +125,10 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
|
|||||||
private readonly env: FireAttackEnvironment;
|
private readonly env: FireAttackEnvironment;
|
||||||
private readonly statKey: 'leadership' | 'strength' | 'intelligence';
|
private readonly statKey: 'leadership' | 'strength' | 'intelligence';
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: FireAttackEnvironment) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
env: FireAttackEnvironment
|
||||||
|
) {
|
||||||
this.pipeline = new GeneralActionPipeline(modules);
|
this.pipeline = new GeneralActionPipeline(modules);
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.statKey = env.statKey ?? 'intelligence';
|
this.statKey = env.statKey ?? 'intelligence';
|
||||||
@@ -287,7 +290,10 @@ export class ActionResolver<
|
|||||||
private readonly command: CommandResolver<TriggerState>;
|
private readonly command: CommandResolver<TriggerState>;
|
||||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: FireAttackEnvironment) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
env: FireAttackEnvironment
|
||||||
|
) {
|
||||||
this.command = new CommandResolver(modules, env);
|
this.command = new CommandResolver(modules, env);
|
||||||
this.pipeline = new GeneralActionPipeline(modules);
|
this.pipeline = new GeneralActionPipeline(modules);
|
||||||
}
|
}
|
||||||
@@ -376,8 +382,7 @@ export class ActionResolver<
|
|||||||
);
|
);
|
||||||
|
|
||||||
const itemCode = general.role.items.item;
|
const itemCode = general.role.items.item;
|
||||||
const actionResult = consumeSuccessfulStrategyItem(this.pipeline, context);
|
const consumedItems = consumeSuccessfulStrategyItem(this.pipeline, context);
|
||||||
const consumedItems = Array.isArray(actionResult?.['consumedItems']) ? actionResult['consumedItems'] : [];
|
|
||||||
if (typeof itemCode === 'string' && consumedItems.includes(itemCode)) {
|
if (typeof itemCode === 'string' && consumedItems.includes(itemCode)) {
|
||||||
context.addLog(`<C>${itemCode}</>${JosaUtil.pick(itemCode, '을')} 사용!`, {
|
context.addLog(`<C>${itemCode}</>${JosaUtil.pick(itemCode, '을')} 사용!`, {
|
||||||
format: LogFormat.PLAIN,
|
format: LogFormat.PLAIN,
|
||||||
@@ -405,7 +410,10 @@ export class ActionDefinition<
|
|||||||
private readonly command: CommandResolver<TriggerState>;
|
private readonly command: CommandResolver<TriggerState>;
|
||||||
private readonly resolver: ActionResolver<TriggerState>;
|
private readonly resolver: ActionResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, env: FireAttackEnvironment) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
env: FireAttackEnvironment
|
||||||
|
) {
|
||||||
this.command = new CommandResolver(modules, env);
|
this.command = new CommandResolver(modules, env);
|
||||||
this.resolver = new ActionResolver(modules, env);
|
this.resolver = new ActionResolver(modules, env);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import type { TurnCommandEnv } from '@sammo-ts/logic/actions/turn/commandEnv.js'
|
|||||||
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
import { defaultActionContextBuilder } from '@sammo-ts/logic/actions/turn/actionContext.js';
|
||||||
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
import { tryApplyUniqueLottery } from '@sammo-ts/logic/rewards/uniqueLottery.js';
|
||||||
import type { GeneralTurnCommandSpec } from './index.js';
|
import type { GeneralTurnCommandSpec } from './index.js';
|
||||||
import { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
|
|
||||||
const ACTION_NAME = '맹훈련';
|
const ACTION_NAME = '맹훈련';
|
||||||
const ACTION_KEY = 'cr_맹훈련';
|
const ACTION_KEY = 'cr_맹훈련';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { NATION_TRAIT_KEYS } from '@sammo-ts/logic/triggers/special/nation/index.js';
|
import { NATION_TRAIT_KEYS } from '@sammo-ts/logic/actionModules/traits/nation/index.js';
|
||||||
import { getLegacyStringWidth } from '@sammo-ts/logic/troop/management.js';
|
import { getLegacyStringWidth } from '@sammo-ts/logic/troop/management.js';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
import type { GeneralActionResolveContext } from '@sammo-ts/logic/actions/engine.js';
|
||||||
import type { GeneralActionPipeline } from '@sammo-ts/logic/triggers/general-action.js';
|
import type { GeneralActionPipeline } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
|
import { createGeneralActionEvent } from '@sammo-ts/logic/actionModules/events.js';
|
||||||
|
|
||||||
export const consumeSuccessfulStrategyItem = <TriggerState extends GeneralTriggerState>(
|
export const consumeSuccessfulStrategyItem = <TriggerState extends GeneralTriggerState>(
|
||||||
pipeline: GeneralActionPipeline<TriggerState>,
|
pipeline: GeneralActionPipeline<TriggerState>,
|
||||||
context: GeneralActionResolveContext<TriggerState>
|
context: GeneralActionResolveContext<TriggerState>
|
||||||
): Record<string, unknown> | null =>
|
): readonly string[] =>
|
||||||
pipeline.onArbitraryAction(context, 'GeneralCommand', null, {
|
pipeline.dispatch(
|
||||||
command: '계략',
|
context,
|
||||||
success: true,
|
createGeneralActionEvent<TriggerState, 'strategy.succeeded'>('strategy.succeeded', {
|
||||||
});
|
consumedItems: [],
|
||||||
|
})
|
||||||
|
).payload.consumedItems;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
existsDestNation,
|
existsDestNation,
|
||||||
occupiedCity,
|
occupiedCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionEffect,
|
GeneralActionEffect,
|
||||||
@@ -51,7 +51,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
|
|||||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
private readonly initialNationGenLimit = 10
|
private readonly initialNationGenLimit = 10
|
||||||
) {
|
) {
|
||||||
this.pipeline = new GeneralActionPipeline(modules);
|
this.pipeline = new GeneralActionPipeline(modules);
|
||||||
@@ -75,7 +75,10 @@ export class ActionResolver<
|
|||||||
readonly key = 'che_급습';
|
readonly key = 'che_급습';
|
||||||
private readonly command: CommandResolver<TriggerState>;
|
private readonly command: CommandResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
initialNationGenLimit = 10
|
||||||
|
) {
|
||||||
this.command = new CommandResolver(modules, initialNationGenLimit);
|
this.command = new CommandResolver(modules, initialNationGenLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +180,10 @@ export class ActionDefinition<
|
|||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
private readonly resolver: ActionResolver<TriggerState>;
|
private readonly resolver: ActionResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
initialNationGenLimit = 10
|
||||||
|
) {
|
||||||
this.resolver = new ActionResolver(modules, initialNationGenLimit);
|
this.resolver = new ActionResolver(modules, initialNationGenLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
occupiedCity,
|
occupiedCity,
|
||||||
occupiedDestCity,
|
occupiedDestCity,
|
||||||
} from '@sammo-ts/logic/constraints/presets.js';
|
} from '@sammo-ts/logic/constraints/presets.js';
|
||||||
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js';
|
import { GeneralActionPipeline, type GeneralActionModule } from '@sammo-ts/logic/actionModules/general.js';
|
||||||
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
import type { GeneralActionDefinition } from '@sammo-ts/logic/actions/definition.js';
|
||||||
import type {
|
import type {
|
||||||
GeneralActionEffect,
|
GeneralActionEffect,
|
||||||
@@ -46,7 +46,7 @@ export class CommandResolver<TriggerState extends GeneralTriggerState = GeneralT
|
|||||||
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
private readonly pipeline: GeneralActionPipeline<TriggerState>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
modules: Array<GeneralActionModule<TriggerState> | null | undefined>,
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
private readonly initialNationGenLimit = 10
|
private readonly initialNationGenLimit = 10
|
||||||
) {
|
) {
|
||||||
this.pipeline = new GeneralActionPipeline(modules);
|
this.pipeline = new GeneralActionPipeline(modules);
|
||||||
@@ -70,7 +70,10 @@ export class ActionResolver<
|
|||||||
readonly key = 'che_백성동원';
|
readonly key = 'che_백성동원';
|
||||||
private readonly command: CommandResolver<TriggerState>;
|
private readonly command: CommandResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
initialNationGenLimit = 10
|
||||||
|
) {
|
||||||
this.command = new CommandResolver(modules, initialNationGenLimit);
|
this.command = new CommandResolver(modules, initialNationGenLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +157,10 @@ export class ActionDefinition<
|
|||||||
public readonly name = ACTION_NAME;
|
public readonly name = ACTION_NAME;
|
||||||
private readonly resolver: ActionResolver<TriggerState>;
|
private readonly resolver: ActionResolver<TriggerState>;
|
||||||
|
|
||||||
constructor(modules: Array<GeneralActionModule<TriggerState> | null | undefined>, initialNationGenLimit = 10) {
|
constructor(
|
||||||
|
modules: ReadonlyArray<GeneralActionModule<TriggerState> | null | undefined>,
|
||||||
|
initialNationGenLimit = 10
|
||||||
|
) {
|
||||||
this.resolver = new ActionResolver(modules, initialNationGenLimit);
|
this.resolver = new ActionResolver(modules, initialNationGenLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user