diff --git a/packages/logic/src/triggers/special/domestic/che_경작.ts b/packages/logic/src/triggers/special/domestic/che_경작.ts index 5cc2179..870d231 100644 --- a/packages/logic/src/triggers/special/domestic/che_경작.ts +++ b/packages/logic/src/triggers/special/domestic/che_경작.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 경작 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '경작', info: '[내정] 농지 개간 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, getName: () => '경작', getInfo: () => '[내정] 농지 개간 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/domestic/che_귀모.ts b/packages/logic/src/triggers/special/domestic/che_귀모.ts index 63ae228..74544b7 100644 --- a/packages/logic/src/triggers/special/domestic/che_귀모.ts +++ b/packages/logic/src/triggers/special/domestic/che_귀모.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 귀모 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '귀모', info: '[계략] 화계·탈취·파괴·선동 : 성공률 +20%p', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_LEADERSHIP, TraitRequirement.STAT_STRENGTH, TraitRequirement.STAT_INTEL], + weight: 2.5, + weightType: TraitWeightType.PERCENT, + }, getName: () => '귀모', getInfo: () => '[계략] 화계·탈취·파괴·선동 : 성공률 +20%p', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/domestic/che_발명.ts b/packages/logic/src/triggers/special/domestic/che_발명.ts index 83621c6..dea3eac 100644 --- a/packages/logic/src/triggers/special/domestic/che_발명.ts +++ b/packages/logic/src/triggers/special/domestic/che_발명.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 발명 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '발명', info: '[내정] 기술 연구 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, getName: () => '발명', getInfo: () => '[내정] 기술 연구 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/domestic/che_상재.ts b/packages/logic/src/triggers/special/domestic/che_상재.ts index 1ee3235..d32c852 100644 --- a/packages/logic/src/triggers/special/domestic/che_상재.ts +++ b/packages/logic/src/triggers/special/domestic/che_상재.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 상재 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '상재', info: '[내정] 상업 투자 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, getName: () => '상재', getInfo: () => '[내정] 상업 투자 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/domestic/che_수비.ts b/packages/logic/src/triggers/special/domestic/che_수비.ts index 4525478..7ae77b1 100644 --- a/packages/logic/src/triggers/special/domestic/che_수비.ts +++ b/packages/logic/src/triggers/special/domestic/che_수비.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 수비 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '수비', info: '[내정] 수비 강화 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_STRENGTH], + weight: 1, + weightType: TraitWeightType.NORM, + }, getName: () => '수비', getInfo: () => '[내정] 수비 강화 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/domestic/che_인덕.ts b/packages/logic/src/triggers/special/domestic/che_인덕.ts index 403ba22..1148be5 100644 --- a/packages/logic/src/triggers/special/domestic/che_인덕.ts +++ b/packages/logic/src/triggers/special/domestic/che_인덕.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 인덕 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '인덕', info: '[내정] 주민 선정·정착 장려 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_LEADERSHIP], + weight: 1, + weightType: TraitWeightType.NORM, + }, getName: () => '인덕', getInfo: () => '[내정] 주민 선정·정착 장려 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/domestic/che_축성.ts b/packages/logic/src/triggers/special/domestic/che_축성.ts index 9d0a158..7d2ff70 100644 --- a/packages/logic/src/triggers/special/domestic/che_축성.ts +++ b/packages/logic/src/triggers/special/domestic/che_축성.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 축성 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '축성', info: '[내정] 성벽 보수 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_STRENGTH], + weight: 1, + weightType: TraitWeightType.NORM, + }, getName: () => '축성', getInfo: () => '[내정] 성벽 보수 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/domestic/che_통찰.ts b/packages/logic/src/triggers/special/domestic/che_통찰.ts index e8b66ad..c89eae4 100644 --- a/packages/logic/src/triggers/special/domestic/che_통찰.ts +++ b/packages/logic/src/triggers/special/domestic/che_통찰.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '@sammo-ts/logic/triggers/special/requirements.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; // 내정 특기: 통찰 @@ -6,6 +7,11 @@ export const traitModule: TraitModule = { name: '통찰', info: '[내정] 치안 강화 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', kind: 'domestic', + selection: { + requirements: [TraitRequirement.STAT_STRENGTH], + weight: 1, + weightType: TraitWeightType.NORM, + }, getName: () => '통찰', getInfo: () => '[내정] 치안 강화 : 기본 보정 +10%, 성공률 +10%p, 비용 -20%', onCalcDomestic: (_context, turnType, varType, value) => { diff --git a/packages/logic/src/triggers/special/index.ts b/packages/logic/src/triggers/special/index.ts index 0afdd10..1f3f54f 100644 --- a/packages/logic/src/triggers/special/index.ts +++ b/packages/logic/src/triggers/special/index.ts @@ -1,4 +1,6 @@ export * from './types.js'; +export * from './requirements.js'; +export * from './selector.js'; export * from './registry.js'; export * from './domestic/index.js'; export * from './war/index.js'; diff --git a/packages/logic/src/triggers/special/requirements.ts b/packages/logic/src/triggers/special/requirements.ts new file mode 100644 index 0000000..3542f92 --- /dev/null +++ b/packages/logic/src/triggers/special/requirements.ts @@ -0,0 +1,30 @@ +export enum TraitRequirement { + DISABLED = 0x1, + + STAT_LEADERSHIP = 0x2, + STAT_STRENGTH = 0x4, + STAT_INTEL = 0x8, + + ARMY_FOOTMAN = 0x100, + ARMY_ARCHER = 0x200, + ARMY_CAVALRY = 0x400, + ARMY_WIZARD = 0x800, + ARMY_SIEGE = 0x1000, + + REQ_DEXTERITY = 0x4000, + + STAT_NOT_LEADERSHIP = 0x20000, + STAT_NOT_STRENGTH = 0x40000, + STAT_NOT_INTEL = 0x80000, +} + +export enum TraitWeightType { + NORM = 1, + PERCENT = 2, +} + +export interface TraitSelection { + weightType: TraitWeightType; + weight: number; + requirements: TraitRequirement[]; +} diff --git a/packages/logic/src/triggers/special/selector.ts b/packages/logic/src/triggers/special/selector.ts new file mode 100644 index 0000000..debc593 --- /dev/null +++ b/packages/logic/src/triggers/special/selector.ts @@ -0,0 +1,150 @@ +import { RandUtil } from '@sammo-ts/common'; +import { TraitRequirement, TraitWeightType } from './requirements.js'; +import type { TraitModule } from './types.js'; +import type { ScenarioStatBlock } from '../../scenario/types.js'; + +export class TraitSelector { + /** + * 기초 스탯 기반 선택 조건 계산 (calcCondGeneric) + */ + static calcCondGeneric( + stats: { leadership: number; strength: number; intelligence: number }, + scenarioStat: ScenarioStatBlock + ): number { + const { leadership, strength, intelligence } = stats; + const chiefMin = scenarioStat.chiefMin; + + let myCond = 0; + if (leadership < chiefMin || strength < chiefMin || intelligence < chiefMin) { + if (leadership < chiefMin) myCond |= TraitRequirement.STAT_NOT_LEADERSHIP; + if (strength < chiefMin) myCond |= TraitRequirement.STAT_NOT_STRENGTH; + if (intelligence < chiefMin) myCond |= TraitRequirement.STAT_NOT_INTEL; + } + + if (myCond === 0) { + if (leadership * 0.9 > strength && leadership * 0.9 > intelligence) { + myCond |= TraitRequirement.STAT_LEADERSHIP; + } else if (strength >= intelligence) { + myCond |= TraitRequirement.STAT_STRENGTH; + } else { + myCond |= TraitRequirement.STAT_INTEL; + } + } + + return myCond; + } + + /** + * 숙련도 기반 선택 조건 계산 (calcCondDexterity) + */ + static calcCondDexterity(rng: RandUtil, dex: number[]): number { + const dexMap: Record = { + [TraitRequirement.ARMY_FOOTMAN]: dex[0] || 0, + [TraitRequirement.ARMY_ARCHER]: dex[1] || 0, + [TraitRequirement.ARMY_CAVALRY]: dex[2] || 0, + [TraitRequirement.ARMY_WIZARD]: dex[3] || 0, + [TraitRequirement.ARMY_SIEGE]: dex[4] || 0, + }; + + const dexSum = Object.values(dexMap).reduce((a, b) => a + b, 0); + // 루트(합)/4 확률 기반 로직 (Legacy: sqrt(dexSum)/4) + const dexProb = Math.sqrt(dexSum) / 4; + + // Legacy: 80% 확률로 0 반환 (이전 연도에 이미 얻었거나 기타 이유로 제한하는 인지) + // 실제로는 pickSpecialWar에서 이 메서드 호출 전후에 별도 확률을 둘 수도 있으나, + // Legacy SpecialityHelper.php의 로직을 그대로 따름. + if (rng.nextBool(0.8)) { + return 0; + } + + if (rng.nextRangeInt(0, 99) < dexProb) { + return 0; + } + + if (dexSum === 0) { + return Number(rng.choice(Object.keys(dexMap))); + } + + const maxDex = Math.max(...Object.values(dexMap)); + const candidates = Object.keys(dexMap) + .map(Number) + .filter((k) => dexMap[k] === maxDex); + + return Number(rng.choice(candidates)); + } + + /** + * 사용 가능한 특기 목록에서 하나를 무작위로 선택 (pickTrait) + */ + static pickTrait(rng: RandUtil, myCond: number, traits: TraitModule[], prevTraitKeys: string[]): string | null { + const normPool: Record = {}; + const percentPool: { key: string; weight: number }[] = []; + + for (const trait of traits) { + if (!trait.selection) continue; + if (prevTraitKeys.includes(trait.key)) continue; + + let valid = false; + for (const req of trait.selection.requirements) { + if (req === (req & myCond)) { + valid = true; + break; + } + } + + if (!valid) continue; + + if (trait.selection.weightType === TraitWeightType.PERCENT) { + percentPool.push({ key: trait.key, weight: trait.selection.weight }); + } else { + normPool[trait.key] = trait.selection.weight; + } + } + + // PERCENT 타입 특기 먼저 우선권 확인 + for (const item of percentPool) { + if (rng.nextBool(item.weight / 100)) { + return item.key; + } + } + + // NORM 타입 특기들 중 가중치 기반 선택 + if (Object.keys(normPool).length === 0) return null; + + return String(rng.choiceUsingWeight(normPool)); + } + + /** + * 전투 특기 선택 통합 로직 + */ + static pickWarTrait( + rng: RandUtil, + stats: { leadership: number; strength: number; intelligence: number }, + dex: number[], + traits: TraitModule[], + prevTraitKeys: string[], + scenarioStat: ScenarioStatBlock + ): string | null { + let myCond = this.calcCondGeneric(stats, scenarioStat); + const dexCond = this.calcCondDexterity(rng, dex); + if (dexCond) { + myCond |= dexCond | TraitRequirement.REQ_DEXTERITY; + } + + return this.pickTrait(rng, myCond, traits, prevTraitKeys); + } + + /** + * 내정 특기 선택 통합 로직 + */ + static pickDomesticTrait( + rng: RandUtil, + stats: { leadership: number; strength: number; intelligence: number }, + traits: TraitModule[], + prevTraitKeys: string[], + scenarioStat: ScenarioStatBlock + ): string | null { + const myCond = this.calcCondGeneric(stats, scenarioStat); + return this.pickTrait(rng, myCond, traits, prevTraitKeys); + } +} diff --git a/packages/logic/src/triggers/special/types.ts b/packages/logic/src/triggers/special/types.ts index 1774c52..db7ce3e 100644 --- a/packages/logic/src/triggers/special/types.ts +++ b/packages/logic/src/triggers/special/types.ts @@ -1,6 +1,7 @@ import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js'; import type { GeneralActionModule } from '@sammo-ts/logic/triggers/general-action.js'; import type { WarActionModule } from '@sammo-ts/logic/war/actions.js'; +import type { TraitSelection } from './requirements.js'; export type TraitKind = 'domestic' | 'war' | 'personality' | 'nation'; @@ -9,6 +10,7 @@ export interface TraitSpec { name: string; info: string; kind: TraitKind; + selection?: TraitSelection; } export type TraitModule = TraitSpec & diff --git a/packages/logic/src/triggers/special/war/che_격노.ts b/packages/logic/src/triggers/special/war/che_격노.ts index e5cccf8..7401959 100644 --- a/packages/logic/src/triggers/special/war/che_격노.ts +++ b/packages/logic/src/triggers/special/war/che_격노.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; import type { WarUnit } from '@sammo-ts/logic/war/units.js'; import { LogFormat } from '@sammo-ts/logic/logging/types.js'; @@ -98,6 +99,11 @@ export const traitModule: TraitModule = { getName: () => '격노', getInfo: () => '[전투] 상대방 필살 시 격노(필살) 발동, 회피 시도시 25% 확률로 격노 발동, 공격 시 일정 확률로 진노(1페이즈 추가), 격노마다 대미지 20% 추가 중첩', + selection: { + requirements: [TraitRequirement.STAT_STRENGTH], + weight: 1, + weightType: TraitWeightType.NORM, + }, getWarPowerMultiplier: (_context, unit, _oppose) => { const activatedCnt = unit.hasActivatedSkillOnLog('격노'); return [1 + 0.2 * activatedCnt, 1]; diff --git a/packages/logic/src/triggers/special/war/che_견고.ts b/packages/logic/src/triggers/special/war/che_견고.ts index 84565fa..042df7d 100644 --- a/packages/logic/src/triggers/special/war/che_견고.ts +++ b/packages/logic/src/triggers/special/war/che_견고.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; import type { WarUnit } from '@sammo-ts/logic/war/units.js'; @@ -44,6 +45,11 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '견고', getInfo: () => '[전투] 상대 필살 확률 -20%p, 상대 계략 시도시 성공 확률 -10%p, 부상 없음, 아군 피해 -10%', + selection: { + requirements: [TraitRequirement.STAT_STRENGTH], + weight: 1, + weightType: TraitWeightType.NORM, + }, onCalcOpposeStat: ((_context, statName, value, _aux) => { if (statName === 'warMagicSuccessProb' && typeof value === 'number') { return value - 0.1; diff --git a/packages/logic/src/triggers/special/war/che_공성.ts b/packages/logic/src/triggers/special/war/che_공성.ts index 80190ad..d2ce15e 100644 --- a/packages/logic/src/triggers/special/war/che_공성.ts +++ b/packages/logic/src/triggers/special/war/che_공성.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; @@ -49,13 +50,18 @@ export const traitModule: TraitModule = { name: '공성', info: '[군사] 차병 계통 징·모병비 -10%
[전투] 성벽 공격 시 대미지 +100%,
공격시 상대 병종에/수비시 자신 병종 숙련에 차병 숙련을 가산', kind: 'war', + selection: { + weight: 1, + weightType: TraitWeightType.NORM, + requirements: [TraitRequirement.STAT_LEADERSHIP | TraitRequirement.REQ_DEXTERITY | TraitRequirement.ARMY_SIEGE], + }, getName: () => '공성', getInfo: () => '[군사] 차병 계통 징·모병비 -10%
[전투] 성벽 공격 시 대미지 +100%,
공격시 상대 병종에/수비시 자신 병종 숙련에 차병 숙련을 가산', onCalcDomestic: (_context, turnType, varType, value, aux) => { if (turnType === '징병' || turnType === '모병') { const armType = getAuxArmType(aux); - if (varType === 'cost' && armType === 4) { + if (varType === 'cost' && armType === 5) { return value * 0.9; } } diff --git a/packages/logic/src/triggers/special/war/che_궁병.ts b/packages/logic/src/triggers/special/war/che_궁병.ts index 4767080..b3574d1 100644 --- a/packages/logic/src/triggers/special/war/che_궁병.ts +++ b/packages/logic/src/triggers/special/war/che_궁병.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; @@ -52,6 +53,17 @@ export const traitModule: TraitModule = { name: '궁병', info: '[군사] 궁병 계통 징·모병비 -10%
[전투] 회피 확률 +20%p,
공격시 상대 병종에/수비시 자신 병종 숙련에 궁병 숙련을 가산', kind: 'war', + selection: { + weight: 1, + weightType: TraitWeightType.NORM, + requirements: [ + TraitRequirement.STAT_LEADERSHIP | + TraitRequirement.REQ_DEXTERITY | + TraitRequirement.ARMY_ARCHER | + TraitRequirement.STAT_NOT_INTEL, + TraitRequirement.STAT_STRENGTH | TraitRequirement.REQ_DEXTERITY | TraitRequirement.ARMY_ARCHER, + ], + }, getName: () => '궁병', getInfo: () => '[군사] 궁병 계통 징·모병비 -10%
[전투] 회피 확률 +20%p,
공격시 상대 병종에/수비시 자신 병종 숙련에 궁병 숙련을 가산', diff --git a/packages/logic/src/triggers/special/war/che_귀병.ts b/packages/logic/src/triggers/special/war/che_귀병.ts new file mode 100644 index 0000000..682a8de --- /dev/null +++ b/packages/logic/src/triggers/special/war/che_귀병.ts @@ -0,0 +1,79 @@ +import { TraitRequirement, TraitWeightType } from '../requirements.js'; +import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; +import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; +import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; +import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { getMetaNumber } from '@sammo-ts/logic/war/utils.js'; +import { getAuxArmType, parseWarDexAux } from './aux.js'; + +function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number; +function onCalcStat( + context: WarActionContext, + statName: WarStatName, + value: number | [number, number], + aux?: unknown +): number | [number, number]; +function onCalcStat( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: number | [number, number], + aux?: unknown +): number | [number, number] { + if (statName === 'warMagicSuccessProb') { + return (value as number) + 0.2; + } + + if (!('unit' in context) || !context.unit) { + return value; + } + const unit = context.unit; + + const wizardType = unit.getGameConfig().armTypes.wizard; + if (wizardType === undefined) { + return value; + } + + if (statName.startsWith('dex')) { + const myDex = getMetaNumber(context.general.meta, `dex${wizardType}`); + const { isAttacker, opposeType } = parseWarDexAux(aux); + + if (isAttacker && opposeType && statName === `dex${opposeType.armType}`) { + return (value as number) + myDex; + } + if (!isAttacker && statName === `dex${wizardType}`) { + return (value as number) + myDex; + } + } + return value; +} + +// 전투 특기: 귀병 +export const traitModule: TraitModule = { + key: 'che_귀병', + name: '귀병', + info: '[군사] 귀병 계통 징·모병비 -10%
[전투] 계략 성공 확률 +20%p,
공격시 상대 병종에/수비시 자신 병종 숙련에 귀병 숙련을 가산', + kind: 'war', + selection: { + weight: 1, + weightType: TraitWeightType.NORM, + requirements: [ + TraitRequirement.STAT_INTEL | + TraitRequirement.ARMY_WIZARD | + TraitRequirement.REQ_DEXTERITY | + TraitRequirement.STAT_NOT_STRENGTH, + ], + }, + getName: () => '귀병', + getInfo: () => + '[군사] 귀병 계통 징·모병비 -10%
[전투] 계략 성공 확률 +20%p,
공격시 상대 병종에/수비시 자신 병종 숙련에 귀병 숙련을 가산', + onCalcDomestic: (_context, turnType, varType, value, aux) => { + if (turnType === '징병' || turnType === '모병') { + const armType = getAuxArmType(aux); + if (varType === 'cost' && armType === 4) { + return value * 0.9; + } + } + return value; + }, + onCalcStat, +}; diff --git a/packages/logic/src/triggers/special/war/che_기병.ts b/packages/logic/src/triggers/special/war/che_기병.ts index d28a979..fcf751f 100644 --- a/packages/logic/src/triggers/special/war/che_기병.ts +++ b/packages/logic/src/triggers/special/war/che_기병.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; @@ -48,6 +49,17 @@ export const traitModule: TraitModule = { name: '기병', info: '[군사] 기병 계통 징·모병비 -10%
[전투] 수비 시 대미지 +10%, 공격 시 대미지 +20%,
공격시 상대 병종에/수비시 자신 병종 숙련에 기병 숙련을 가산', kind: 'war', + selection: { + weight: 1, + weightType: TraitWeightType.NORM, + requirements: [ + TraitRequirement.STAT_LEADERSHIP | + TraitRequirement.REQ_DEXTERITY | + TraitRequirement.ARMY_CAVALRY | + TraitRequirement.STAT_NOT_INTEL, + TraitRequirement.STAT_STRENGTH | TraitRequirement.REQ_DEXTERITY | TraitRequirement.ARMY_CAVALRY, + ], + }, getName: () => '기병', getInfo: () => '[군사] 기병 계통 징·모병비 -10%
[전투] 수비 시 대미지 +10%, 공격 시 대미지 +20%,
공격시 상대 병종에/수비시 자신 병종 숙련에 기병 숙련을 가산', diff --git a/packages/logic/src/triggers/special/war/che_돌격.ts b/packages/logic/src/triggers/special/war/che_돌격.ts index dc660b2..d5b59b2 100644 --- a/packages/logic/src/triggers/special/war/che_돌격.ts +++ b/packages/logic/src/triggers/special/war/che_돌격.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; @@ -61,6 +62,11 @@ export const traitModule: TraitModule = { name: '돌격', info: '[전투] 공격 시 대등/유리한 병종에게는 퇴각 전까지 전투, 공격 시 페이즈 + 2, 공격 시 대미지 +5%', kind: 'war', + selection: { + weight: 1, + weightType: TraitWeightType.NORM, + requirements: [TraitRequirement.STAT_STRENGTH], + }, getName: () => '돌격', getInfo: () => '[전투] 공격 시 대등/유리한 병종에게는 퇴각 전까지 전투, 공격 시 페이즈 + 2, 공격 시 대미지 +5%', getWarPowerMultiplier: (_context, unit, _oppose) => { diff --git a/packages/logic/src/triggers/special/war/che_무쌍.ts b/packages/logic/src/triggers/special/war/che_무쌍.ts index ea7a07f..e8f449f 100644 --- a/packages/logic/src/triggers/special/war/che_무쌍.ts +++ b/packages/logic/src/triggers/special/war/che_무쌍.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import { getMetaNumber } from '@sammo-ts/logic/war/utils.js'; import { WarUnit } from '@sammo-ts/logic/war/units.js'; @@ -40,6 +41,11 @@ export const traitModule: TraitModule = { getName: () => '무쌍', getInfo: () => '[전투] 대미지 +5%, 피해 -2%, 공격 시 필살 확률 +10%p,
승리 수의 로그 비례로 대미지 상승(10회 ⇒ +5%, 40회 ⇒ +15%)
승리 수의 로그 비례로 피해 감소(10회 ⇒ -2%, 40회 ⇒ -6%)', + selection: { + requirements: [TraitRequirement.STAT_STRENGTH], + weight: 1, + weightType: TraitWeightType.NORM, + }, getWarPowerMultiplier: (_context, unit, _oppose) => { let attackMultiplier = 1.05; let defenceMultiplier = 0.98; diff --git a/packages/logic/src/triggers/special/war/che_반계.ts b/packages/logic/src/triggers/special/war/che_반계.ts index ea1d526..c384b9c 100644 --- a/packages/logic/src/triggers/special/war/che_반계.ts +++ b/packages/logic/src/triggers/special/war/che_반계.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; import type { WarUnit } from '@sammo-ts/logic/war/units.js'; import { LogFormat } from '@sammo-ts/logic/logging/types.js'; @@ -99,6 +100,11 @@ export const traitModule: TraitModule = { getName: () => '반계', getInfo: () => '[전투] 상대의 계략 성공 확률 -10%p, 상대의 계략을 40% 확률로 되돌림, 반목 성공시 대미지 추가(+60% → +150%)', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, onCalcOpposeStat: ((_context, statName, value, _aux) => { if (statName === 'warMagicSuccessProb' && typeof value === 'number') { return value - 0.1; diff --git a/packages/logic/src/triggers/special/war/che_보병.ts b/packages/logic/src/triggers/special/war/che_보병.ts index 7a6834f..0bdbb00 100644 --- a/packages/logic/src/triggers/special/war/che_보병.ts +++ b/packages/logic/src/triggers/special/war/che_보병.ts @@ -1,3 +1,4 @@ +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; @@ -48,6 +49,17 @@ export const traitModule: TraitModule = { name: '보병', info: '[군사] 보병 계통 징·모병비 -10%
[전투] 공격 시 아군 피해 -10%, 수비 시 아군 피해 -20%,
공격시 상대 병종에/수비시 자신 병종 숙련에 보병 숙련을 가산', kind: 'war', + selection: { + weight: 1, + weightType: TraitWeightType.NORM, + requirements: [ + TraitRequirement.STAT_LEADERSHIP | + TraitRequirement.REQ_DEXTERITY | + TraitRequirement.ARMY_FOOTMAN | + TraitRequirement.STAT_NOT_INTEL, + TraitRequirement.STAT_STRENGTH | TraitRequirement.REQ_DEXTERITY | TraitRequirement.ARMY_FOOTMAN, + ], + }, getName: () => '보병', getInfo: () => '[군사] 보병 계통 징·모병비 -10%
[전투] 공격 시 아군 피해 -10%, 수비 시 아군 피해 -20%,
공격시 상대 병종에/수비시 자신 병종 숙련에 보병 숙련을 가산', diff --git a/packages/logic/src/triggers/special/war/che_신산.ts b/packages/logic/src/triggers/special/war/che_신산.ts index d056130..7251498 100644 --- a/packages/logic/src/triggers/special/war/che_신산.ts +++ b/packages/logic/src/triggers/special/war/che_신산.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number; function onCalcStat( @@ -32,6 +33,11 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '신산', getInfo: () => '[계략] 화계·탈취·파괴·선동 : 성공률 +10%p
[전투] 계략 시도 확률 +20%p, 계략 성공 확률 +20%p', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, onCalcDomestic: (_context, turnType, varType, value, _aux) => { if (turnType === '계략') { if (varType === 'success') return value + 0.1; diff --git a/packages/logic/src/triggers/special/war/che_신중.ts b/packages/logic/src/triggers/special/war/che_신중.ts index afa0a63..ee5ae4b 100644 --- a/packages/logic/src/triggers/special/war/che_신중.ts +++ b/packages/logic/src/triggers/special/war/che_신중.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number; function onCalcStat( @@ -29,5 +30,10 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '신중', getInfo: () => '[전투] 계략 성공 확률 100%', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, onCalcStat, }; diff --git a/packages/logic/src/triggers/special/war/che_위압.ts b/packages/logic/src/triggers/special/war/che_위압.ts index ee68581..1d7e1e4 100644 --- a/packages/logic/src/triggers/special/war/che_위압.ts +++ b/packages/logic/src/triggers/special/war/che_위압.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; import type { WarUnit } from '@sammo-ts/logic/war/units.js'; import { LogFormat } from '@sammo-ts/logic/logging/types.js'; @@ -84,6 +85,11 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '위압', getInfo: () => '[전투] 첫 페이즈 위압 발동(적 공격, 회피 불가, 사기 5 감소)', + selection: { + requirements: [TraitRequirement.STAT_STRENGTH], + weight: 1, + weightType: TraitWeightType.NORM, + }, getBattlePhaseTriggerList: (_context) => { if (!_context.unit) return null; return new WarTriggerCaller(new che_위압시도(_context.unit), new che_위압발동(_context.unit)); diff --git a/packages/logic/src/triggers/special/war/che_의술.ts b/packages/logic/src/triggers/special/war/che_의술.ts index 276a1b6..eb0fc45 100644 --- a/packages/logic/src/triggers/special/war/che_의술.ts +++ b/packages/logic/src/triggers/special/war/che_의술.ts @@ -3,6 +3,7 @@ import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/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 { TraitRequirement, TraitWeightType } from '../requirements.js'; // 전투 특기: 의술 export const traitModule: TraitModule = { @@ -13,6 +14,11 @@ export const traitModule: TraitModule = { getName: () => '의술', getInfo: () => '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복
[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 30% 감소, 부상 회복)', + selection: { + requirements: [TraitRequirement.STAT_LEADERSHIP, TraitRequirement.STAT_STRENGTH, TraitRequirement.STAT_INTEL], + weight: 2, + weightType: TraitWeightType.PERCENT, + }, getPreTurnExecuteTriggerList: (context) => new GeneralTriggerCaller(new CheUisulCityHealTrigger(context.general)), getBattlePhaseTriggerList: (context: WarActionContext) => { const unit = context.unit; diff --git a/packages/logic/src/triggers/special/war/che_저격.ts b/packages/logic/src/triggers/special/war/che_저격.ts index 9de1a6d..eeb240b 100644 --- a/packages/logic/src/triggers/special/war/che_저격.ts +++ b/packages/logic/src/triggers/special/war/che_저격.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; import type { WarUnit } from '@sammo-ts/logic/war/units.js'; import { LogFormat } from '@sammo-ts/logic/logging/types.js'; @@ -122,6 +123,11 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '저격', getInfo: () => '[전투] 새로운 상대와 전투 시 50% 확률로 저격 발동, 성공 시 사기+20', + selection: { + requirements: [TraitRequirement.STAT_LEADERSHIP, TraitRequirement.STAT_STRENGTH, TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, getBattlePhaseTriggerList: (_context) => { if (!_context.unit) return null; return new WarTriggerCaller(new che_저격시도(_context.unit, 0.5, 20, 40, 20), new che_저격발동(_context.unit)); diff --git a/packages/logic/src/triggers/special/war/che_집중.ts b/packages/logic/src/triggers/special/war/che_집중.ts index a630876..2f539de 100644 --- a/packages/logic/src/triggers/special/war/che_집중.ts +++ b/packages/logic/src/triggers/special/war/che_집중.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number; function onCalcStat( @@ -29,5 +30,10 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '집중', getInfo: () => '[전투] 계략 성공 시 대미지 +50%', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, onCalcStat, }; diff --git a/packages/logic/src/triggers/special/war/che_징병.ts b/packages/logic/src/triggers/special/war/che_징병.ts index 9845b51..ef97864 100644 --- a/packages/logic/src/triggers/special/war/che_징병.ts +++ b/packages/logic/src/triggers/special/war/che_징병.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; const RECRUIT_TRAIN = 70; const CONSCRIPT_TRAIN = 84; @@ -44,6 +45,11 @@ export const traitModule: TraitModule = { getName: () => '징병', getInfo: () => '[군사] 징병/모병 시 훈사 70/84 제공
[기타] 통솔 순수 능력치 보정 +25%, 징병/모병/소집해제 시 인구 변동 없음', + selection: { + requirements: [TraitRequirement.STAT_LEADERSHIP, TraitRequirement.STAT_STRENGTH, TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, onCalcDomestic: (_context, turnType, varType, value) => { if (turnType === '징병' || turnType === '모병') { if (varType === 'train' || varType === 'atmos') { diff --git a/packages/logic/src/triggers/special/war/che_척사.ts b/packages/logic/src/triggers/special/war/che_척사.ts index 5dc0e55..46093df 100644 --- a/packages/logic/src/triggers/special/war/che_척사.ts +++ b/packages/logic/src/triggers/special/war/che_척사.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number; function onCalcStat( @@ -26,6 +27,11 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '척사', getInfo: () => '[전투] 지역·도시 병종 상대로 대미지 +20%, 아군 피해 -20%', + selection: { + requirements: [TraitRequirement.STAT_LEADERSHIP, TraitRequirement.STAT_STRENGTH, TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, getWarPowerMultiplier: (_context, _unit, oppose) => { const opposeCrewType = oppose.getCrewType(); if (opposeCrewType.reqCities() || opposeCrewType.reqRegions()) { diff --git a/packages/logic/src/triggers/special/war/che_필살.ts b/packages/logic/src/triggers/special/war/che_필살.ts index f3f11fa..b93571b 100644 --- a/packages/logic/src/triggers/special/war/che_필살.ts +++ b/packages/logic/src/triggers/special/war/che_필살.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; import type { WarUnit } from '@sammo-ts/logic/war/units.js'; @@ -55,6 +56,11 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '필살', getInfo: () => '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 향상', + selection: { + requirements: [TraitRequirement.STAT_LEADERSHIP, TraitRequirement.STAT_STRENGTH, TraitRequirement.STAT_INTEL], + weight: 1, + weightType: TraitWeightType.NORM, + }, getBattlePhaseTriggerList: (_context) => { if (!_context.unit) return null; return new WarTriggerCaller(new che_필살강화_회피불가(_context.unit)); diff --git a/packages/logic/src/triggers/special/war/che_환술.ts b/packages/logic/src/triggers/special/war/che_환술.ts index 6c841cc..1f73dc5 100644 --- a/packages/logic/src/triggers/special/war/che_환술.ts +++ b/packages/logic/src/triggers/special/war/che_환술.ts @@ -2,6 +2,7 @@ import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js'; +import { TraitRequirement, TraitWeightType } from '../requirements.js'; function onCalcStat(context: GeneralActionContext, statName: GeneralStatName, value: number, aux?: unknown): number; function onCalcStat( @@ -32,5 +33,10 @@ export const traitModule: TraitModule = { kind: 'war', getName: () => '환술', getInfo: () => '[전투] 계략 성공 확률 +10%p, 계략 성공 시 대미지 +30%', + selection: { + requirements: [TraitRequirement.STAT_INTEL], + weight: 5, + weightType: TraitWeightType.PERCENT, + }, onCalcStat, }; diff --git a/packages/logic/src/triggers/special/war/index.ts b/packages/logic/src/triggers/special/war/index.ts index a8d2243..00e18bc 100644 --- a/packages/logic/src/triggers/special/war/index.ts +++ b/packages/logic/src/triggers/special/war/index.ts @@ -1,6 +1,27 @@ import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js'; -export const WAR_TRAIT_KEYS = ['che_의술', 'che_징병', 'che_보병', 'che_궁병', 'che_기병', 'che_공성'] as const; +export const WAR_TRAIT_KEYS = [ + 'che_귀병', + 'che_신산', + 'che_환술', + 'che_집중', + 'che_신중', + 'che_반계', + 'che_보병', + 'che_궁병', + 'che_기병', + 'che_공성', + 'che_돌격', + 'che_무쌍', + 'che_견고', + 'che_위압', + 'che_저격', + 'che_필살', + 'che_징병', + 'che_의술', + 'che_격노', + 'che_척사', +] as const; export type WarTraitKey = (typeof WAR_TRAIT_KEYS)[number]; @@ -9,12 +30,26 @@ export type WarTraitModule = TraitModule; export type WarTraitImporter = () => Promise; const defaultImporters: Record = { - che_의술: async () => import('./che_의술.js'), - che_징병: async () => import('./che_징병.js'), + che_귀병: async () => import('./che_귀병.js'), + che_신산: async () => import('./che_신산.js'), + che_환술: async () => import('./che_환술.js'), + che_집중: async () => import('./che_집중.js'), + che_신중: async () => import('./che_신중.js'), + che_반계: async () => import('./che_반계.js'), che_보병: async () => import('./che_보병.js'), che_궁병: async () => import('./che_궁병.js'), che_기병: async () => import('./che_기병.js'), che_공성: async () => import('./che_공성.js'), + che_돌격: async () => import('./che_돌격.js'), + che_무쌍: async () => import('./che_무쌍.js'), + che_견고: async () => import('./che_견고.js'), + che_위압: async () => import('./che_위압.js'), + che_저격: async () => import('./che_저격.js'), + che_필살: async () => import('./che_필살.js'), + che_징병: async () => import('./che_징병.js'), + che_의술: async () => import('./che_의술.js'), + che_격노: async () => import('./che_격노.js'), + che_척사: async () => import('./che_척사.js'), }; export const isWarTraitKey = (value: string): value is WarTraitKey => WAR_TRAIT_KEYS.includes(value as WarTraitKey);