feat: Add new traits and requirements for war mechanics
- Introduced new traits including '귀병', '신산', '환술', '집중', '신중', '반계', '돌격', '무쌍', '견고', '위압', '저격', '필살', '격노', and '척사'. - Implemented selection criteria for each trait, specifying weight, weight type, and requirements based on leadership, strength, intelligence, and army types. - Updated existing traits to include selection properties for better trait management. - Added a new requirements module to define trait requirements and weight types. - Enhanced the trait selection logic to accommodate new traits and their specific conditions.
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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[];
|
||||
}
|
||||
@@ -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<number, number> = {
|
||||
[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<string, number> = {};
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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<TriggerState extends GeneralTriggerState = GeneralTriggerState> = TraitSpec &
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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%<br>[전투] 성벽 공격 시 대미지 +100%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 차병 숙련을 가산',
|
||||
kind: 'war',
|
||||
selection: {
|
||||
weight: 1,
|
||||
weightType: TraitWeightType.NORM,
|
||||
requirements: [TraitRequirement.STAT_LEADERSHIP | TraitRequirement.REQ_DEXTERITY | TraitRequirement.ARMY_SIEGE],
|
||||
},
|
||||
getName: () => '공성',
|
||||
getInfo: () =>
|
||||
'[군사] 차병 계통 징·모병비 -10%<br>[전투] 성벽 공격 시 대미지 +100%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 차병 숙련을 가산',
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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%<br>[전투] 회피 확률 +20%p,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 궁병 숙련을 가산',
|
||||
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%<br>[전투] 회피 확률 +20%p,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 궁병 숙련을 가산',
|
||||
|
||||
@@ -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%<br>[전투] 계략 성공 확률 +20%p,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 귀병 숙련을 가산',
|
||||
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%<br>[전투] 계략 성공 확률 +20%p,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 귀병 숙련을 가산',
|
||||
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,
|
||||
};
|
||||
@@ -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%<br>[전투] 수비 시 대미지 +10%, 공격 시 대미지 +20%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 기병 숙련을 가산',
|
||||
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%<br>[전투] 수비 시 대미지 +10%, 공격 시 대미지 +20%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 기병 숙련을 가산',
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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, <br>승리 수의 로그 비례로 대미지 상승(10회 ⇒ +5%, 40회 ⇒ +15%)<br>승리 수의 로그 비례로 피해 감소(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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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%<br>[전투] 공격 시 아군 피해 -10%, 수비 시 아군 피해 -20%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 보병 숙련을 가산',
|
||||
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%<br>[전투] 공격 시 아군 피해 -10%, 수비 시 아군 피해 -20%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 보병 숙련을 가산',
|
||||
|
||||
@@ -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<br>[전투] 계략 시도 확률 +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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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%) 부상 회복<br>[전투] 페이즈마다 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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 제공<br>[기타] 통솔 순수 능력치 보정 +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') {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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<TraitModuleExport>;
|
||||
|
||||
const defaultImporters: Record<WarTraitKey, WarTraitImporter> = {
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user