feat: 국가 성향 모듈 추가 및 관련 타입 수정
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import type { General, GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
|
import type { General, GeneralTriggerState, Nation } from '@sammo-ts/logic/domain/entities.js';
|
||||||
import type { RandomGenerator } from '@sammo-ts/common';
|
import type { RandomGenerator } from '@sammo-ts/common';
|
||||||
import type { WorldStateRepository } from '@sammo-ts/logic/ports/world.js';
|
import type { WorldStateRepository } from '@sammo-ts/logic/ports/world.js';
|
||||||
import { TriggerCaller, type Trigger } from './core.js';
|
import { TriggerCaller, type Trigger } from './core.js';
|
||||||
@@ -30,6 +30,7 @@ export const createGeneralSkillActivation = <TriggerState extends GeneralTrigger
|
|||||||
|
|
||||||
export interface GeneralActionContext<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
export interface GeneralActionContext<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
|
||||||
general: General<TriggerState>;
|
general: General<TriggerState>;
|
||||||
|
nation?: Nation | null;
|
||||||
world?: WorldStateRepository;
|
world?: WorldStateRepository;
|
||||||
worldView?: GeneralWorldView<TriggerState>;
|
worldView?: GeneralWorldView<TriggerState>;
|
||||||
log?: GeneralActionLogSink;
|
log?: GeneralActionLogSink;
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ export * from './registry.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';
|
||||||
|
export * from './nation/index.js';
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 덕가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_덕가',
|
||||||
|
name: '덕가',
|
||||||
|
info: '장점: 치안↑ 인구↑ 민심↑ / 단점: 쌀수입↓ 수성↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '덕가',
|
||||||
|
getInfo: () => '장점: 치안↑ 인구↑ 민심↑ / 단점: 쌀수입↓ 수성↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '치안' || turnType === '민심' || turnType === '인구') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '수비' || turnType === '성벽') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'rice') return amount * 0.9;
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 1.2;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 도가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_도가',
|
||||||
|
name: '도가',
|
||||||
|
info: '장점: 인구↑ / 단점: 기술↓ 치안↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '도가',
|
||||||
|
getInfo: () => '장점: 인구↑ / 단점: 기술↓ 치안↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '기술' || turnType === '치안') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 1.2;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 도적
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_도적',
|
||||||
|
name: '도적',
|
||||||
|
info: '장점: 계략↑ / 단점: 금수입↓ 치안↓ 민심↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '도적',
|
||||||
|
getInfo: () => '장점: 계략↑ / 단점: 금수입↓ 치안↓ 민심↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '치안' || turnType === '민심' || turnType === '인구') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
} else if (turnType === '계략') {
|
||||||
|
if (varType === 'success') return value + 0.1;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'gold') return amount * 0.9;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 명가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_명가',
|
||||||
|
name: '명가',
|
||||||
|
info: '장점: 기술↑ 인구↑ / 단점: 쌀수입↓ 수성↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '명가',
|
||||||
|
getInfo: () => '장점: 기술↑ 인구↑ / 단점: 쌀수입↓ 수성↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '기술') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '수비' || turnType === '성벽') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'rice') return amount * 0.9;
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 1.2;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 묵가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_묵가',
|
||||||
|
name: '묵가',
|
||||||
|
info: '장점: 수성↑ / 단점: 기술↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '묵가',
|
||||||
|
getInfo: () => '장점: 수성↑ / 단점: 기술↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '수비' || turnType === '성벽') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '기술') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 법가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_법가',
|
||||||
|
name: '법가',
|
||||||
|
info: '장점: 금수입↑ 치안↑ / 단점: 인구↓ 민심↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '법가',
|
||||||
|
getInfo: () => '장점: 금수입↑ 치안↑ / 단점: 인구↓ 민심↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '치안') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '민심' || turnType === '인구') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'gold') return amount * 1.1;
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 0.8;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 병가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_병가',
|
||||||
|
name: '병가',
|
||||||
|
info: '장점: 기술↑ 수성↑ / 단점: 인구↓ 민심↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '병가',
|
||||||
|
getInfo: () => '장점: 기술↑ 수성↑ / 단점: 인구↓ 민심↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '기술' || turnType === '수비' || turnType === '성벽') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '민심' || turnType === '인구') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 0.8;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 불가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_불가',
|
||||||
|
name: '불가',
|
||||||
|
info: '장점: 민심↑ 수성↑ / 단점: 금수입↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '불가',
|
||||||
|
getInfo: () => '장점: 민심↑ 수성↑ / 단점: 금수입↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '민심' || turnType === '인구' || turnType === '수비' || turnType === '성벽') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'gold') return amount * 0.9;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 오두미도
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_오두미도',
|
||||||
|
name: '오두미도',
|
||||||
|
info: '장점: 쌀수입↑ 인구↑ / 단점: 기술↓ 수성↓ 농상↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '오두미도',
|
||||||
|
getInfo: () => '장점: 쌀수입↑ 인구↑ / 단점: 기술↓ 수성↓ 농상↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (
|
||||||
|
turnType === '기술' ||
|
||||||
|
turnType === '수비' ||
|
||||||
|
turnType === '성벽' ||
|
||||||
|
turnType === '농업' ||
|
||||||
|
turnType === '상업'
|
||||||
|
) {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'rice') return amount * 1.1;
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 1.2;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 유가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_유가',
|
||||||
|
name: '유가',
|
||||||
|
info: '장점: 농상↑ 민심↑ / 단점: 쌀수입↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '유가',
|
||||||
|
getInfo: () => '장점: 농상↑ 민심↑ / 단점: 쌀수입↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '농업' || turnType === '상업' || turnType === '민심' || turnType === '인구') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'rice') return amount * 0.9;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 음양가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_음양가',
|
||||||
|
name: '음양가',
|
||||||
|
info: '장점: 농상↑ 인구↑ / 단점: 기술↓ 전략↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '음양가',
|
||||||
|
getInfo: () => '장점: 농상↑ 인구↑ / 단점: 기술↓ 전략↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '농업' || turnType === '상업') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '기술') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 1.2;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
onCalcStrategic: (_context, _turnType, varType, value) => {
|
||||||
|
if (varType === 'delay') {
|
||||||
|
return Math.round((value * 4) / 3);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 종횡가
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_종횡가',
|
||||||
|
name: '종횡가',
|
||||||
|
info: '장점: 전략↑ 수성↑ / 단점: 금수입↓ 농상↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '종횡가',
|
||||||
|
getInfo: () => '장점: 전략↑ 수성↑ / 단점: 금수입↓ 농상↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '수비' || turnType === '성벽') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '농업' || turnType === '상업') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'gold') return amount * 0.9;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
onCalcStrategic: (_context, _turnType, varType, value) => {
|
||||||
|
if (varType === 'delay') {
|
||||||
|
return Math.round((value * 3) / 4);
|
||||||
|
}
|
||||||
|
if (varType === 'globalDelay') {
|
||||||
|
return Math.round(value / 2);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 중립
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_중립',
|
||||||
|
name: '중립',
|
||||||
|
info: '장점: 없음 / 단점: 없음',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '중립',
|
||||||
|
getInfo: () => '장점: 없음 / 단점: 없음',
|
||||||
|
};
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import type { TraitModule } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
// 국가 성향: 태평도
|
||||||
|
export const traitModule: TraitModule = {
|
||||||
|
key: 'che_태평도',
|
||||||
|
name: '태평도',
|
||||||
|
info: '장점: 인구↑ 민심↑ / 단점: 기술↓ 수성↓',
|
||||||
|
kind: 'nation',
|
||||||
|
getName: () => '태평도',
|
||||||
|
getInfo: () => '장점: 인구↑ 민심↑ / 단점: 기술↓ 수성↓',
|
||||||
|
onCalcDomestic: (_context, turnType, varType, value) => {
|
||||||
|
if (turnType === '민심' || turnType === '인구') {
|
||||||
|
if (varType === 'score') return value * 1.1;
|
||||||
|
if (varType === 'cost') return value * 0.8;
|
||||||
|
} else if (turnType === '기술' || turnType === '수비' || turnType === '성벽') {
|
||||||
|
if (varType === 'score') return value * 0.9;
|
||||||
|
if (varType === 'cost') return value * 1.2;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
onCalcNationalIncome: (_context, type, amount) => {
|
||||||
|
if (type === 'pop' && amount > 0) return amount * 1.2;
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import type { TraitModule, TraitModuleExport } from '@sammo-ts/logic/triggers/special/types.js';
|
||||||
|
|
||||||
|
export const NATION_TRAIT_KEYS = [
|
||||||
|
'che_중립',
|
||||||
|
'che_도적',
|
||||||
|
'che_명가',
|
||||||
|
'che_음양가',
|
||||||
|
'che_종횡가',
|
||||||
|
'che_불가',
|
||||||
|
'che_오두미도',
|
||||||
|
'che_태평도',
|
||||||
|
'che_도가',
|
||||||
|
'che_묵가',
|
||||||
|
'che_덕가',
|
||||||
|
'che_병가',
|
||||||
|
'che_유가',
|
||||||
|
'che_법가',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type NationTraitKey = (typeof NATION_TRAIT_KEYS)[number];
|
||||||
|
|
||||||
|
export type NationTraitModule = TraitModule;
|
||||||
|
|
||||||
|
export type NationTraitImporter = () => Promise<TraitModuleExport>;
|
||||||
|
|
||||||
|
const defaultImporters: Record<NationTraitKey, NationTraitImporter> = {
|
||||||
|
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 isNationTraitKey = (value: string): value is NationTraitKey =>
|
||||||
|
NATION_TRAIT_KEYS.includes(value as NationTraitKey);
|
||||||
|
|
||||||
|
export class NationTraitLoader {
|
||||||
|
private readonly cache = new Map<NationTraitKey, Promise<NationTraitModule>>();
|
||||||
|
|
||||||
|
constructor(private readonly importers: Record<NationTraitKey, NationTraitImporter> = defaultImporters) {}
|
||||||
|
|
||||||
|
async load(key: NationTraitKey): Promise<NationTraitModule> {
|
||||||
|
const cached = this.cache.get(key);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
const importer = this.importers[key];
|
||||||
|
if (!importer) {
|
||||||
|
throw new Error(`Unknown nation trait key: ${key}`);
|
||||||
|
}
|
||||||
|
const loading = importer().then((module) => {
|
||||||
|
if (!('traitModule' in module)) {
|
||||||
|
throw new Error(`Missing traitModule for nation trait: ${key}`);
|
||||||
|
}
|
||||||
|
const resolved = module.traitModule;
|
||||||
|
if (resolved.key !== key) {
|
||||||
|
throw new Error(`Nation trait key mismatch: expected ${key}, got ${resolved.key}`);
|
||||||
|
}
|
||||||
|
if (resolved.kind !== 'nation') {
|
||||||
|
throw new Error(`Nation trait kind mismatch: ${resolved.key}`);
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
});
|
||||||
|
this.cache.set(key, loading);
|
||||||
|
return loading;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadNationTraitModules = async (
|
||||||
|
keys: NationTraitKey[],
|
||||||
|
loader: NationTraitLoader = new NationTraitLoader()
|
||||||
|
): Promise<NationTraitModule[]> => {
|
||||||
|
const modules: NationTraitModule[] = [];
|
||||||
|
const seen = new Set<string>();
|
||||||
|
for (const key of keys) {
|
||||||
|
if (seen.has(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen.add(key);
|
||||||
|
modules.push(await loader.load(key));
|
||||||
|
}
|
||||||
|
return modules;
|
||||||
|
};
|
||||||
@@ -26,6 +26,7 @@ const resolveTraitKey = (
|
|||||||
specialWar: string | null;
|
specialWar: string | null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
nation?: { typeCode: string } | null;
|
||||||
},
|
},
|
||||||
kind: TraitKind
|
kind: TraitKind
|
||||||
): string | null => {
|
): string | null => {
|
||||||
@@ -35,6 +36,9 @@ const resolveTraitKey = (
|
|||||||
if (kind === 'war') {
|
if (kind === 'war') {
|
||||||
return context.general.role.specialWar;
|
return context.general.role.specialWar;
|
||||||
}
|
}
|
||||||
|
if (kind === 'nation') {
|
||||||
|
return context.nation?.typeCode ?? null;
|
||||||
|
}
|
||||||
return context.general.role.personality;
|
return context.general.role.personality;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -51,6 +55,8 @@ const resolveModule = <TriggerState extends GeneralTriggerState>(
|
|||||||
bucket = registry.domestic;
|
bucket = registry.domestic;
|
||||||
} else if (kind === 'war') {
|
} else if (kind === 'war') {
|
||||||
bucket = registry.war;
|
bucket = registry.war;
|
||||||
|
} else if (kind === 'nation') {
|
||||||
|
bucket = registry.nation;
|
||||||
} else {
|
} else {
|
||||||
bucket = registry.personality;
|
bucket = registry.personality;
|
||||||
}
|
}
|
||||||
@@ -201,10 +207,12 @@ export const createTraitModuleRegistry = <TriggerState extends GeneralTriggerSta
|
|||||||
domestic?: TraitModule<TriggerState>[];
|
domestic?: TraitModule<TriggerState>[];
|
||||||
war?: TraitModule<TriggerState>[];
|
war?: TraitModule<TriggerState>[];
|
||||||
personality?: TraitModule<TriggerState>[];
|
personality?: TraitModule<TriggerState>[];
|
||||||
|
nation?: TraitModule<TriggerState>[];
|
||||||
}): TraitModuleRegistry<TriggerState> => {
|
}): TraitModuleRegistry<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>>();
|
||||||
|
|
||||||
for (const module of options.domestic ?? []) {
|
for (const module of options.domestic ?? []) {
|
||||||
domestic.set(module.key, module);
|
domestic.set(module.key, module);
|
||||||
@@ -215,8 +223,11 @@ export const createTraitModuleRegistry = <TriggerState extends GeneralTriggerSta
|
|||||||
for (const module of options.personality ?? []) {
|
for (const module of options.personality ?? []) {
|
||||||
personality.set(module.key, module);
|
personality.set(module.key, module);
|
||||||
}
|
}
|
||||||
|
for (const module of options.nation ?? []) {
|
||||||
|
nation.set(module.key, module);
|
||||||
|
}
|
||||||
|
|
||||||
return { domestic, war, personality };
|
return { domestic, war, personality, nation };
|
||||||
};
|
};
|
||||||
|
|
||||||
// 특성 레지스트리를 General/전투 파이프라인용 모듈 목록으로 변환한다.
|
// 특성 레지스트리를 General/전투 파이프라인용 모듈 목록으로 변환한다.
|
||||||
@@ -227,10 +238,12 @@ export const createTraitModules = <TriggerState extends GeneralTriggerState = Ge
|
|||||||
new TraitGeneralActionRouter<TriggerState>('domestic', registry),
|
new TraitGeneralActionRouter<TriggerState>('domestic', registry),
|
||||||
new TraitGeneralActionRouter<TriggerState>('war', registry),
|
new TraitGeneralActionRouter<TriggerState>('war', registry),
|
||||||
new TraitGeneralActionRouter<TriggerState>('personality', registry),
|
new TraitGeneralActionRouter<TriggerState>('personality', registry),
|
||||||
|
new TraitGeneralActionRouter<TriggerState>('nation', registry),
|
||||||
],
|
],
|
||||||
war: [
|
war: [
|
||||||
new TraitWarActionRouter<TriggerState>('domestic', registry),
|
new TraitWarActionRouter<TriggerState>('domestic', registry),
|
||||||
new TraitWarActionRouter<TriggerState>('war', registry),
|
new TraitWarActionRouter<TriggerState>('war', registry),
|
||||||
new TraitWarActionRouter<TriggerState>('personality', registry),
|
new TraitWarActionRouter<TriggerState>('personality', registry),
|
||||||
|
new TraitWarActionRouter<TriggerState>('nation', registry),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ 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/triggers/general-action.js';
|
||||||
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
import type { WarActionModule } from '@sammo-ts/logic/war/actions.js';
|
||||||
|
|
||||||
export type TraitKind = 'domestic' | 'war' | 'personality';
|
export type TraitKind = 'domestic' | 'war' | 'personality' | 'nation';
|
||||||
|
|
||||||
export interface TraitSpec {
|
export interface TraitSpec {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -23,4 +23,5 @@ export interface TraitModuleRegistry<TriggerState extends 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>>;
|
||||||
|
nation: Map<string, TraitModule<TriggerState>>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export type TriggerStrategicActionType = '의병모집' | '허보' | '필사즉
|
|||||||
|
|
||||||
export type TriggerStrategicVarType = 'delay' | 'globalDelay';
|
export type TriggerStrategicVarType = 'delay' | 'globalDelay';
|
||||||
|
|
||||||
export type TriggerNationalIncomeType = 'gold' | 'rice';
|
export type TriggerNationalIncomeType = 'gold' | 'rice' | 'pop';
|
||||||
|
|
||||||
export type GeneralStatName = 'leadership' | 'strength' | 'intelligence' | 'experience' | 'dedication';
|
export type GeneralStatName = 'leadership' | 'strength' | 'intelligence' | 'experience' | 'dedication';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user