diff --git a/packages/logic/src/items/che_간파_노군입산부.ts b/packages/logic/src/items/che_간파_노군입산부.ts new file mode 100644 index 0000000..2008d5d --- /dev/null +++ b/packages/logic/src/items/che_간파_노군입산부.ts @@ -0,0 +1,32 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_간파_노군입산부'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '노군입산부', + name: '노군입산부(간파)', + info: '[전투] 상대 회피 확률 -25%p, 상대 필살 확률 -10%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcOpposeStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warAvoidRatio') { + return (value as number) - 0.25; + } + if (statName === 'warCriticalRatio') { + return (value as number) - 0.1; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_격노_구정신단경.ts b/packages/logic/src/items/che_격노_구정신단경.ts new file mode 100644 index 0000000..a746a74 --- /dev/null +++ b/packages/logic/src/items/che_격노_구정신단경.ts @@ -0,0 +1,98 @@ +import { LogFormat } from '@sammo-ts/logic/logging/types.js'; +import { TriggerPriority } from '@sammo-ts/logic/triggers/core.js'; +import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import type { WarUnit } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_격노_구정신단경'; + +class CheRageAttemptTrigger extends BaseWarUnitTrigger { + constructor(unit: WarUnit, raiseType: number) { + super(unit, TriggerPriority.Body + 400, raiseType); + } + + protected actionWar( + self: WarUnit, + oppose: WarUnit, + _selfEnv: Record, + _opposeEnv: Record + ): boolean { + if (!oppose.hasActivatedSkill('필살') && !oppose.hasActivatedSkill('회피')) { + return true; + } + if (self.hasActivatedSkill('격노불가')) { + return true; + } + + if (oppose.hasActivatedSkill('필살')) { + self.activateSkill('격노'); + oppose.deactivateSkill('회피'); + if (self.isAttacker() && self.rng.nextBool(0.5)) { + self.activateSkill('진노'); + } + } else if (self.rng.nextBool(0.25)) { + self.activateSkill('격노'); + oppose.deactivateSkill('회피'); + if (self.isAttacker() && self.rng.nextBool(0.5)) { + self.activateSkill('진노'); + } + } + return true; + } +} + +class CheRageActivateTrigger extends BaseWarUnitTrigger { + constructor(unit: WarUnit, raiseType: number) { + super(unit, TriggerPriority.Post + 600, raiseType); + } + + protected actionWar( + self: WarUnit, + oppose: WarUnit, + _selfEnv: Record, + _opposeEnv: Record + ): boolean { + if (!self.hasActivatedSkill('격노')) { + return true; + } + + const targetAct = oppose.hasActivatedSkill('필살') ? '필살 공격' : '회피 시도'; + const isJinno = self.hasActivatedSkill('진노'); + const reaction = isJinno ? '진노' : '격노'; + + self.getLogger().pushGeneralBattleDetailLog(`상대의 ${targetAct}에 ${reaction}했다!`, LogFormat.PLAIN); + oppose + .getLogger() + .pushGeneralBattleDetailLog(`${targetAct}에 상대가 ${reaction}했다!`, LogFormat.PLAIN); + + if (isJinno) { + self.addBonusPhase(1); + } + self.multiplyWarPowerMultiply(self.criticalDamage()); + return true; + } +} + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '구정신단경', + name: '구정신단경(격노)', + info: '[전투] 상대방 필살 시 격노(필살) 발동, 회피 시도시 25% 확률로 격노 발동, 공격 시 일정 확률로 진노(1페이즈 추가), 격노마다 대미지 5% 추가 중첩', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getWarPowerMultiplier: (_context, unit, _oppose) => { + const activatedCnt = unit.hasActivatedSkillOnLog('격노'); + return [1 + 0.05 * activatedCnt, 1]; + }, + getBattlePhaseTriggerList: (context) => { + if (!context.unit) return null; + return new WarTriggerCaller( + new CheRageAttemptTrigger(context.unit, BaseWarUnitTrigger.TYPE_ITEM), + new CheRageActivateTrigger(context.unit, BaseWarUnitTrigger.TYPE_ITEM) + ); + }, +}; diff --git a/packages/logic/src/items/che_계략_삼략.ts b/packages/logic/src/items/che_계략_삼략.ts new file mode 100644 index 0000000..4066963 --- /dev/null +++ b/packages/logic/src/items/che_계략_삼략.ts @@ -0,0 +1,35 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_계략_삼략'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '삼략', + name: '삼략(계략)', + info: '[계략] 화계·탈취·파괴·선동 : 성공률 +20%p
[전투] 계략 시도 확률 +10%p, 계략 성공 확률 +10%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcDomestic: (_context, turnType, varType, value) => { + if (turnType === '계략' && varType === 'success') { + return value + 0.2; + } + return value; + }, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warMagicTrialProb' || statName === 'warMagicSuccessProb') { + return (value as number) + 0.1; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_계략_육도.ts b/packages/logic/src/items/che_계략_육도.ts new file mode 100644 index 0000000..6f1e072 --- /dev/null +++ b/packages/logic/src/items/che_계략_육도.ts @@ -0,0 +1,35 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_계략_육도'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '육도', + name: '육도(계략)', + info: '[계략] 화계·탈취·파괴·선동 : 성공률 +20%p
[전투] 계략 시도 확률 +10%p, 계략 성공 확률 +10%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcDomestic: (_context, turnType, varType, value) => { + if (turnType === '계략' && varType === 'success') { + return value + 0.2; + } + return value; + }, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warMagicTrialProb' || statName === 'warMagicSuccessProb') { + return (value as number) + 0.1; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_계략_이추.ts b/packages/logic/src/items/che_계략_이추.ts new file mode 100644 index 0000000..39ce68b --- /dev/null +++ b/packages/logic/src/items/che_계략_이추.ts @@ -0,0 +1,22 @@ +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_계략_이추'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '이추', + name: '이추(계략)', + info: '[계략] 화계·탈취·파괴·선동 : 성공률 +20%p', + slot: 'item', + cost: 1000, + buyable: true, + consumable: true, + reqSecu: 1000, + unique: false, + onCalcDomestic: (_context, turnType, varType, value) => { + if (turnType === '계략' && varType === 'success') { + return value + 0.2; + } + return value; + }, +}; diff --git a/packages/logic/src/items/che_계략_향낭.ts b/packages/logic/src/items/che_계략_향낭.ts new file mode 100644 index 0000000..c60d5fb --- /dev/null +++ b/packages/logic/src/items/che_계략_향낭.ts @@ -0,0 +1,22 @@ +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_계략_향낭'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '향낭', + name: '향낭(계략)', + info: '[계략] 화계·탈취·파괴·선동 : 성공률 +50%p', + slot: 'item', + cost: 3000, + buyable: true, + consumable: true, + reqSecu: 2000, + unique: false, + onCalcDomestic: (_context, turnType, varType, value) => { + if (turnType === '계략' && varType === 'success') { + return value + 0.5; + } + return value; + }, +}; diff --git a/packages/logic/src/items/che_공성_묵자.ts b/packages/logic/src/items/che_공성_묵자.ts new file mode 100644 index 0000000..74a6146 --- /dev/null +++ b/packages/logic/src/items/che_공성_묵자.ts @@ -0,0 +1,22 @@ +import { WarUnitCity } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = { + key: 'che_공성_묵자', + rawName: '묵자', + name: '묵자(공성)', + info: '[전투] 성벽 공격 시 대미지 +50%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: true, + getWarPowerMultiplier: (_context, unit) => { + const oppose = unit.getOppose(); + if (oppose instanceof WarUnitCity) { + return [1.5, 1]; + } + return [1, 1]; + }, +}; diff --git a/packages/logic/src/items/che_내정_납금박산로.ts b/packages/logic/src/items/che_내정_납금박산로.ts new file mode 100644 index 0000000..ccaeed9 --- /dev/null +++ b/packages/logic/src/items/che_내정_납금박산로.ts @@ -0,0 +1,22 @@ +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_내정_납금박산로'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '납금박산로', + name: '납금박산로(내정)', + info: '[내정] 내정 성공률 +15%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcDomestic: (_context, turnType, varType, value) => { + if (['상업', '농업', '기술', '성벽', '수비', '치안', '민심', '인구'].includes(turnType)) { + if (varType === 'success') return value + 0.15; + } + return value; + }, +}; diff --git a/packages/logic/src/items/che_농성_위공자병법.ts b/packages/logic/src/items/che_농성_위공자병법.ts new file mode 100644 index 0000000..e3cd222 --- /dev/null +++ b/packages/logic/src/items/che_농성_위공자병법.ts @@ -0,0 +1,39 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_농성_위공자병법'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '위공자병법', + name: '위공자병법(농성)', + info: '[계략] 장수 주둔 도시 화계·탈취·파괴·선동 : 성공률 -30%p
[전투] 상대 계략 시도 확률 -10%p, 상대 계략 성공 확률 -10%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'sabotageDefence') { + return (value as number) + 0.3; + } + return value; + } as NonNullable, + onCalcOpposeStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warMagicTrialProb' || statName === 'warMagicSuccessProb') { + return (value as number) - 0.1; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_농성_주서음부.ts b/packages/logic/src/items/che_농성_주서음부.ts new file mode 100644 index 0000000..3388bff --- /dev/null +++ b/packages/logic/src/items/che_농성_주서음부.ts @@ -0,0 +1,39 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_농성_주서음부'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '주서음부', + name: '주서음부(농성)', + info: '[계략] 장수 주둔 도시 화계·탈취·파괴·선동 : 성공률 -30%p
[전투] 상대 계략 시도 확률 -10%p, 상대 계략 성공 확률 -10%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'sabotageDefence') { + return (value as number) + 0.3; + } + return value; + } as NonNullable, + onCalcOpposeStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warMagicTrialProb' || statName === 'warMagicSuccessProb') { + return (value as number) - 0.1; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_능력치_무력_두강주.ts b/packages/logic/src/items/che_능력치_무력_두강주.ts new file mode 100644 index 0000000..cb0eee1 --- /dev/null +++ b/packages/logic/src/items/che_능력치_무력_두강주.ts @@ -0,0 +1,44 @@ +import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; +import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; +import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; +import { clamp } from '@sammo-ts/logic/war/utils.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_능력치_무력_두강주'; + +const resolveNumber = (value: unknown, fallback = 0): number => + typeof value === 'number' && Number.isFinite(value) ? value : fallback; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '두강주', + name: '두강주(무력)', + info: '[능력치] 무력 +5 +(4년마다 +1)', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + if (statName === 'strength') { + const auxObj = aux as Record | undefined; + const year = resolveNumber(auxObj?.['year']); + const startYear = resolveNumber(auxObj?.['startYear']); + const maxTechLevel = resolveNumber(auxObj?.['maxTechLevel'], 12); + const relYear = Math.max(0, year - startYear); + const bonus = 5 + clamp(Math.floor(relYear / 4), 0, maxTechLevel); + + if (Array.isArray(value)) { + return [value[0] + bonus, value[1] + bonus]; + } + return (value as number) + bonus; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_능력치_지력_이강주.ts b/packages/logic/src/items/che_능력치_지력_이강주.ts new file mode 100644 index 0000000..5390a19 --- /dev/null +++ b/packages/logic/src/items/che_능력치_지력_이강주.ts @@ -0,0 +1,44 @@ +import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; +import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; +import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; +import { clamp } from '@sammo-ts/logic/war/utils.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_능력치_지력_이강주'; + +const resolveNumber = (value: unknown, fallback = 0): number => + typeof value === 'number' && Number.isFinite(value) ? value : fallback; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '이강주', + name: '이강주(지력)', + info: '[능력치] 지력 +5 +(4년마다 +1)', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + if (statName === 'intelligence') { + const auxObj = aux as Record | undefined; + const year = resolveNumber(auxObj?.['year']); + const startYear = resolveNumber(auxObj?.['startYear']); + const maxTechLevel = resolveNumber(auxObj?.['maxTechLevel'], 12); + const relYear = Math.max(0, year - startYear); + const bonus = 5 + clamp(Math.floor(relYear / 4), 0, maxTechLevel); + + if (Array.isArray(value)) { + return [value[0] + bonus, value[1] + bonus]; + } + return (value as number) + bonus; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_능력치_통솔_보령압주.ts b/packages/logic/src/items/che_능력치_통솔_보령압주.ts new file mode 100644 index 0000000..3c97074 --- /dev/null +++ b/packages/logic/src/items/che_능력치_통솔_보령압주.ts @@ -0,0 +1,44 @@ +import type { GeneralStatName, WarStatName } from '@sammo-ts/logic/triggers/types.js'; +import type { GeneralActionContext } from '@sammo-ts/logic/triggers/general.js'; +import type { WarActionContext } from '@sammo-ts/logic/war/actions.js'; +import { clamp } from '@sammo-ts/logic/war/utils.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_능력치_통솔_보령압주'; + +const resolveNumber = (value: unknown, fallback = 0): number => + typeof value === 'number' && Number.isFinite(value) ? value : fallback; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '보령압주', + name: '보령압주(통솔)', + info: '[능력치] 통솔 +5 +(4년마다 +1)', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + if (statName === 'leadership') { + const auxObj = aux as Record | undefined; + const year = resolveNumber(auxObj?.['year']); + const startYear = resolveNumber(auxObj?.['startYear']); + const maxTechLevel = resolveNumber(auxObj?.['maxTechLevel'], 12); + const relYear = Math.max(0, year - startYear); + const bonus = 5 + clamp(Math.floor(relYear / 4), 0, maxTechLevel); + + if (Array.isArray(value)) { + return [value[0] + bonus, value[1] + bonus]; + } + return (value as number) + bonus; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_명마_02_조랑.ts b/packages/logic/src/items/che_명마_02_조랑.ts new file mode 100644 index 0000000..358eb91 --- /dev/null +++ b/packages/logic/src/items/che_명마_02_조랑.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_02_조랑', + rawName: '조랑', + slot: 'horse', + statName: 'leadership', + statValue: 2, + cost: 3000, + buyable: true, + reqSecu: 2000, +}); diff --git a/packages/logic/src/items/che_명마_03_노새.ts b/packages/logic/src/items/che_명마_03_노새.ts new file mode 100644 index 0000000..39fa81e --- /dev/null +++ b/packages/logic/src/items/che_명마_03_노새.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_03_노새', + rawName: '노새', + slot: 'horse', + statName: 'leadership', + statValue: 3, + cost: 4500, + buyable: true, + reqSecu: 2500, +}); diff --git a/packages/logic/src/items/che_명마_04_나귀.ts b/packages/logic/src/items/che_명마_04_나귀.ts new file mode 100644 index 0000000..4f8dd0b --- /dev/null +++ b/packages/logic/src/items/che_명마_04_나귀.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_04_나귀', + rawName: '나귀', + slot: 'horse', + statName: 'leadership', + statValue: 4, + cost: 6000, + buyable: true, + reqSecu: 3000, +}); diff --git a/packages/logic/src/items/che_명마_05_갈색마.ts b/packages/logic/src/items/che_명마_05_갈색마.ts new file mode 100644 index 0000000..922d8bd --- /dev/null +++ b/packages/logic/src/items/che_명마_05_갈색마.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_05_갈색마', + rawName: '갈색마', + slot: 'horse', + statName: 'leadership', + statValue: 5, + cost: 7500, + buyable: true, + reqSecu: 3500, +}); diff --git a/packages/logic/src/items/che_명마_07_기주마.ts b/packages/logic/src/items/che_명마_07_기주마.ts new file mode 100644 index 0000000..7f6078a --- /dev/null +++ b/packages/logic/src/items/che_명마_07_기주마.ts @@ -0,0 +1,34 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const baseModule = createStatItemModule({ + key: 'che_명마_07_기주마', + rawName: '기주마', + slot: 'horse', + statName: 'leadership', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 공격 시 페이즈 +1', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!(context as never, statName as never, value as never, aux); + if (statName === 'initWarPhase') { + return (newValue as number) + 1; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_명마_07_백마.ts b/packages/logic/src/items/che_명마_07_백마.ts new file mode 100644 index 0000000..71bcb15 --- /dev/null +++ b/packages/logic/src/items/che_명마_07_백마.ts @@ -0,0 +1,27 @@ +import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import { CheRetreatNoWoundTrigger } from '@sammo-ts/logic/war/triggers/che_퇴각부상무효.js'; +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const baseModule = createStatItemModule({ + key: 'che_명마_07_백마', + rawName: '백마', + slot: 'horse', + statName: 'leadership', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 전투 종료로 인한 부상 없음', +}); + +export const itemModule: ItemModule = { + ...baseModule, + getBattleInitTriggerList: (context) => { + if (!context.unit) { + return null; + } + return new WarTriggerCaller(new CheRetreatNoWoundTrigger(context.unit)); + }, +}; diff --git a/packages/logic/src/items/che_명마_07_백상.ts b/packages/logic/src/items/che_명마_07_백상.ts new file mode 100644 index 0000000..6d81155 --- /dev/null +++ b/packages/logic/src/items/che_명마_07_백상.ts @@ -0,0 +1,45 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const baseModule = createStatItemModule({ + key: 'che_명마_07_백상', + rawName: '백상', + slot: 'horse', + statName: 'leadership', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 공격력 +20%, 소모 군량 +10%, 공격 시 페이즈 -1', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'killRice') { + return (newValue as number) * 1.1; + } + if (statName === 'initWarPhase') { + return (newValue as number) - 1; + } + return newValue; + } as NonNullable, + getWarPowerMultiplier() { + return [1.2, 1]; + }, +}; diff --git a/packages/logic/src/items/che_명마_07_오환마.ts b/packages/logic/src/items/che_명마_07_오환마.ts new file mode 100644 index 0000000..e6050a8 --- /dev/null +++ b/packages/logic/src/items/che_명마_07_오환마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_07_오환마', + rawName: '오환마', + slot: 'horse', + statName: 'leadership', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_08_양주마.ts b/packages/logic/src/items/che_명마_08_양주마.ts new file mode 100644 index 0000000..9d6778d --- /dev/null +++ b/packages/logic/src/items/che_명마_08_양주마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_08_양주마', + rawName: '양주마', + slot: 'horse', + statName: 'leadership', + statValue: 8, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_08_흉노마.ts b/packages/logic/src/items/che_명마_08_흉노마.ts new file mode 100644 index 0000000..9420407 --- /dev/null +++ b/packages/logic/src/items/che_명마_08_흉노마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_08_흉노마', + rawName: '흉노마', + slot: 'horse', + statName: 'leadership', + statValue: 8, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_09_과하마.ts b/packages/logic/src/items/che_명마_09_과하마.ts new file mode 100644 index 0000000..4475b4c --- /dev/null +++ b/packages/logic/src/items/che_명마_09_과하마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_09_과하마', + rawName: '과하마', + slot: 'horse', + statName: 'leadership', + statValue: 9, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_09_의남백마.ts b/packages/logic/src/items/che_명마_09_의남백마.ts new file mode 100644 index 0000000..c5a46b6 --- /dev/null +++ b/packages/logic/src/items/che_명마_09_의남백마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_09_의남백마', + rawName: '의남백마', + slot: 'horse', + statName: 'leadership', + statValue: 9, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_10_대완마.ts b/packages/logic/src/items/che_명마_10_대완마.ts new file mode 100644 index 0000000..0141ce3 --- /dev/null +++ b/packages/logic/src/items/che_명마_10_대완마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_10_대완마', + rawName: '대완마', + slot: 'horse', + statName: 'leadership', + statValue: 10, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_10_옥추마.ts b/packages/logic/src/items/che_명마_10_옥추마.ts new file mode 100644 index 0000000..324ee26 --- /dev/null +++ b/packages/logic/src/items/che_명마_10_옥추마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_10_옥추마', + rawName: '옥추마', + slot: 'horse', + statName: 'leadership', + statValue: 10, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_11_서량마.ts b/packages/logic/src/items/che_명마_11_서량마.ts new file mode 100644 index 0000000..3f8ca16 --- /dev/null +++ b/packages/logic/src/items/che_명마_11_서량마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_11_서량마', + rawName: '서량마', + slot: 'horse', + statName: 'leadership', + statValue: 11, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_11_화종마.ts b/packages/logic/src/items/che_명마_11_화종마.ts new file mode 100644 index 0000000..11f789d --- /dev/null +++ b/packages/logic/src/items/che_명마_11_화종마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_11_화종마', + rawName: '화종마', + slot: 'horse', + statName: 'leadership', + statValue: 11, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_12_옥란백용구.ts b/packages/logic/src/items/che_명마_12_옥란백용구.ts new file mode 100644 index 0000000..d290655 --- /dev/null +++ b/packages/logic/src/items/che_명마_12_옥란백용구.ts @@ -0,0 +1,42 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const baseModule = createStatItemModule({ + key: 'che_명마_12_옥란백용구', + rawName: '옥란백용구', + slot: 'horse', + statName: 'leadership', + statValue: 12, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 남은 병력이 적을수록 회피 확률 증가. 최대 +50%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'warAvoidRatio') { + const { leadership } = (context as unknown as GeneralActionContext).general.stats; + const crewL = (context as unknown as GeneralActionContext).general.crew / 100; + const boost = (1 - crewL / leadership) * 0.5; + return (newValue as number) + Math.min(Math.max(boost, 0), 0.5); + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_명마_13_적로.ts b/packages/logic/src/items/che_명마_13_적로.ts new file mode 100644 index 0000000..6e6df3a --- /dev/null +++ b/packages/logic/src/items/che_명마_13_적로.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_13_적로', + rawName: '적로', + slot: 'horse', + statName: 'leadership', + statValue: 13, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_13_절영.ts b/packages/logic/src/items/che_명마_13_절영.ts new file mode 100644 index 0000000..396ed20 --- /dev/null +++ b/packages/logic/src/items/che_명마_13_절영.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_13_절영', + rawName: '절영', + slot: 'horse', + statName: 'leadership', + statValue: 13, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_14_적란마.ts b/packages/logic/src/items/che_명마_14_적란마.ts new file mode 100644 index 0000000..57ccf3e --- /dev/null +++ b/packages/logic/src/items/che_명마_14_적란마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_14_적란마', + rawName: '적란마', + slot: 'horse', + statName: 'leadership', + statValue: 14, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_14_조황비전.ts b/packages/logic/src/items/che_명마_14_조황비전.ts new file mode 100644 index 0000000..c03b344 --- /dev/null +++ b/packages/logic/src/items/che_명마_14_조황비전.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_14_조황비전', + rawName: '조황비전', + slot: 'horse', + statName: 'leadership', + statValue: 14, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_15_적토마.ts b/packages/logic/src/items/che_명마_15_적토마.ts new file mode 100644 index 0000000..642ef00 --- /dev/null +++ b/packages/logic/src/items/che_명마_15_적토마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_15_적토마', + rawName: '적토마', + slot: 'horse', + statName: 'leadership', + statValue: 15, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명마_15_한혈마.ts b/packages/logic/src/items/che_명마_15_한혈마.ts new file mode 100644 index 0000000..48e4970 --- /dev/null +++ b/packages/logic/src/items/che_명마_15_한혈마.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_명마_15_한혈마', + rawName: '한혈마', + slot: 'horse', + statName: 'leadership', + statValue: 15, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_명성_구석.ts b/packages/logic/src/items/che_명성_구석.ts new file mode 100644 index 0000000..528f546 --- /dev/null +++ b/packages/logic/src/items/che_명성_구석.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_명성_구석'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '구석', + name: '구석(명성)', + info: '명성 +20%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'experience') { + return (value as number) * 1.2; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_무기_01_단도.ts b/packages/logic/src/items/che_무기_01_단도.ts new file mode 100644 index 0000000..6b7568c --- /dev/null +++ b/packages/logic/src/items/che_무기_01_단도.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_01_단도', + rawName: '단도', + slot: 'weapon', + statName: 'strength', + statValue: 1, + cost: 1000, + buyable: true, + reqSecu: 1000, +}); diff --git a/packages/logic/src/items/che_무기_03_단극.ts b/packages/logic/src/items/che_무기_03_단극.ts new file mode 100644 index 0000000..fafa34f --- /dev/null +++ b/packages/logic/src/items/che_무기_03_단극.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_03_단극', + rawName: '단극', + slot: 'weapon', + statName: 'strength', + statValue: 3, + cost: 4500, + buyable: true, + reqSecu: 2500, +}); diff --git a/packages/logic/src/items/che_무기_04_목검.ts b/packages/logic/src/items/che_무기_04_목검.ts new file mode 100644 index 0000000..1e7fdcc --- /dev/null +++ b/packages/logic/src/items/che_무기_04_목검.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_04_목검', + rawName: '목검', + slot: 'weapon', + statName: 'strength', + statValue: 4, + cost: 6000, + buyable: true, + reqSecu: 3000, +}); diff --git a/packages/logic/src/items/che_무기_05_죽창.ts b/packages/logic/src/items/che_무기_05_죽창.ts new file mode 100644 index 0000000..5085335 --- /dev/null +++ b/packages/logic/src/items/che_무기_05_죽창.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_05_죽창', + rawName: '죽창', + slot: 'weapon', + statName: 'strength', + statValue: 5, + cost: 7500, + buyable: true, + reqSecu: 3500, +}); diff --git a/packages/logic/src/items/che_무기_06_소부.ts b/packages/logic/src/items/che_무기_06_소부.ts new file mode 100644 index 0000000..103a571 --- /dev/null +++ b/packages/logic/src/items/che_무기_06_소부.ts @@ -0,0 +1,13 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_06_소부', + rawName: '소부', + slot: 'weapon', + statName: 'strength', + statValue: 6, + cost: 9000, + buyable: true, + reqSecu: 4000, +}); diff --git a/packages/logic/src/items/che_무기_07_동추.ts b/packages/logic/src/items/che_무기_07_동추.ts new file mode 100644 index 0000000..0e18c0f --- /dev/null +++ b/packages/logic/src/items/che_무기_07_동추.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_07_동추', + rawName: '동추', + slot: 'weapon', + statName: 'strength', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_07_맥궁.ts b/packages/logic/src/items/che_무기_07_맥궁.ts new file mode 100644 index 0000000..1167d6d --- /dev/null +++ b/packages/logic/src/items/che_무기_07_맥궁.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_07_맥궁', + rawName: '맥궁', + slot: 'weapon', + statName: 'strength', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_07_철쇄.ts b/packages/logic/src/items/che_무기_07_철쇄.ts new file mode 100644 index 0000000..c02cec4 --- /dev/null +++ b/packages/logic/src/items/che_무기_07_철쇄.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_07_철쇄', + rawName: '철쇄', + slot: 'weapon', + statName: 'strength', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_07_철편.ts b/packages/logic/src/items/che_무기_07_철편.ts new file mode 100644 index 0000000..5ad609b --- /dev/null +++ b/packages/logic/src/items/che_무기_07_철편.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_07_철편', + rawName: '철편', + slot: 'weapon', + statName: 'strength', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_08_유성추.ts b/packages/logic/src/items/che_무기_08_유성추.ts new file mode 100644 index 0000000..2a9383f --- /dev/null +++ b/packages/logic/src/items/che_무기_08_유성추.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_08_유성추', + rawName: '유성추', + slot: 'weapon', + statName: 'strength', + statValue: 8, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_08_철질여골.ts b/packages/logic/src/items/che_무기_08_철질여골.ts new file mode 100644 index 0000000..c85a38c --- /dev/null +++ b/packages/logic/src/items/che_무기_08_철질여골.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_08_철질여골', + rawName: '철질여골', + slot: 'weapon', + statName: 'strength', + statValue: 8, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_09_쌍철극.ts b/packages/logic/src/items/che_무기_09_쌍철극.ts new file mode 100644 index 0000000..732346a --- /dev/null +++ b/packages/logic/src/items/che_무기_09_쌍철극.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_09_쌍철극', + rawName: '쌍철극', + slot: 'weapon', + statName: 'strength', + statValue: 9, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_10_대부.ts b/packages/logic/src/items/che_무기_10_대부.ts new file mode 100644 index 0000000..b041479 --- /dev/null +++ b/packages/logic/src/items/che_무기_10_대부.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_10_대부', + rawName: '대부', + slot: 'weapon', + statName: 'strength', + statValue: 10, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_10_삼첨도.ts b/packages/logic/src/items/che_무기_10_삼첨도.ts new file mode 100644 index 0000000..3c81341 --- /dev/null +++ b/packages/logic/src/items/che_무기_10_삼첨도.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_10_삼첨도', + rawName: '삼첨도', + slot: 'weapon', + statName: 'strength', + statValue: 10, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_11_고정도.ts b/packages/logic/src/items/che_무기_11_고정도.ts new file mode 100644 index 0000000..8932d40 --- /dev/null +++ b/packages/logic/src/items/che_무기_11_고정도.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_11_고정도', + rawName: '고정도', + slot: 'weapon', + statName: 'strength', + statValue: 11, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_11_이광궁.ts b/packages/logic/src/items/che_무기_11_이광궁.ts new file mode 100644 index 0000000..7195cee --- /dev/null +++ b/packages/logic/src/items/che_무기_11_이광궁.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_11_이광궁', + rawName: '이광궁', + slot: 'weapon', + statName: 'strength', + statValue: 11, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_12_철척사모.ts b/packages/logic/src/items/che_무기_12_철척사모.ts new file mode 100644 index 0000000..cac185e --- /dev/null +++ b/packages/logic/src/items/che_무기_12_철척사모.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_12_철척사모', + rawName: '철척사모', + slot: 'weapon', + statName: 'strength', + statValue: 12, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_12_칠성검.ts b/packages/logic/src/items/che_무기_12_칠성검.ts new file mode 100644 index 0000000..88ef253 --- /dev/null +++ b/packages/logic/src/items/che_무기_12_칠성검.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_12_칠성검', + rawName: '칠성검', + slot: 'weapon', + statName: 'strength', + statValue: 12, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_13_사모.ts b/packages/logic/src/items/che_무기_13_사모.ts new file mode 100644 index 0000000..fc80afa --- /dev/null +++ b/packages/logic/src/items/che_무기_13_사모.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_13_사모', + rawName: '사모', + slot: 'weapon', + statName: 'strength', + statValue: 13, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_13_양유기궁.ts b/packages/logic/src/items/che_무기_13_양유기궁.ts new file mode 100644 index 0000000..ee1c805 --- /dev/null +++ b/packages/logic/src/items/che_무기_13_양유기궁.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_13_양유기궁', + rawName: '양유기궁', + slot: 'weapon', + statName: 'strength', + statValue: 13, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_14_방천화극.ts b/packages/logic/src/items/che_무기_14_방천화극.ts new file mode 100644 index 0000000..9b6de94 --- /dev/null +++ b/packages/logic/src/items/che_무기_14_방천화극.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_14_방천화극', + rawName: '방천화극', + slot: 'weapon', + statName: 'strength', + statValue: 14, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_14_언월도.ts b/packages/logic/src/items/che_무기_14_언월도.ts new file mode 100644 index 0000000..6337b1b --- /dev/null +++ b/packages/logic/src/items/che_무기_14_언월도.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_14_언월도', + rawName: '언월도', + slot: 'weapon', + statName: 'strength', + statValue: 14, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_15_의천검.ts b/packages/logic/src/items/che_무기_15_의천검.ts new file mode 100644 index 0000000..d14d545 --- /dev/null +++ b/packages/logic/src/items/che_무기_15_의천검.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_15_의천검', + rawName: '의천검', + slot: 'weapon', + statName: 'strength', + statValue: 15, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_무기_15_청홍검.ts b/packages/logic/src/items/che_무기_15_청홍검.ts new file mode 100644 index 0000000..ca271d7 --- /dev/null +++ b/packages/logic/src/items/che_무기_15_청홍검.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_무기_15_청홍검', + rawName: '청홍검', + slot: 'weapon', + statName: 'strength', + statValue: 15, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_부적_태현청생부.ts b/packages/logic/src/items/che_부적_태현청생부.ts new file mode 100644 index 0000000..21863e6 --- /dev/null +++ b/packages/logic/src/items/che_부적_태현청생부.ts @@ -0,0 +1,46 @@ +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 { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import type { WarUnit } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_부적_태현청생부'; + +class CheAmuletTrigger extends BaseWarUnitTrigger { + constructor(unit: WarUnit) { + super(unit, 0); + } + + protected actionWar(self: WarUnit): boolean { + self.activateSkill('저격불가', '부상무효'); + return true; + } +} + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '태현청생부', + name: '태현청생부(부적)', + info: '[전투] 저격 불가, 부상 없음', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === ('injuryProb' as unknown as WarStatName)) { + return (value as number) - 1; + } + return value; + } as NonNullable, + getBattlePhaseTriggerList: (context) => { + if (!context.unit) return null; + return new WarTriggerCaller(new CheAmuletTrigger(context.unit)); + }, +}; diff --git a/packages/logic/src/items/che_불굴_상편.ts b/packages/logic/src/items/che_불굴_상편.ts new file mode 100644 index 0000000..4d78d22 --- /dev/null +++ b/packages/logic/src/items/che_불굴_상편.ts @@ -0,0 +1,28 @@ +import { clamp } from '@sammo-ts/logic/war/utils.js'; +import { WarUnitGeneral } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_불굴_상편'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '상편', + name: '상편(불굴)', + info: '[전투] 남은 병력이 적을수록 공격력 증가. 최대 +60%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getWarPowerMultiplier: (_context, unit, _oppose) => { + if (!(unit instanceof WarUnitGeneral)) { + return [1, 1]; + } + const general = unit.getGeneral(); + const leadership = general.stats.leadership; + const crew = general.crew; + const crewRatio = clamp(crew / (leadership * 100), 0, 1); + return [1 + 0.6 * (1 - crewRatio), 1]; + }, +}; diff --git a/packages/logic/src/items/che_사기_초선화.ts b/packages/logic/src/items/che_사기_초선화.ts new file mode 100644 index 0000000..bc37d95 --- /dev/null +++ b/packages/logic/src/items/che_사기_초선화.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_사기_초선화'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '초선화', + name: '초선화(사기)', + info: '[전투] 사기 보정 +15', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'bonusAtmos') { + return (value as number) + 15; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_사기_춘화첩.ts b/packages/logic/src/items/che_사기_춘화첩.ts new file mode 100644 index 0000000..f0715ba --- /dev/null +++ b/packages/logic/src/items/che_사기_춘화첩.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_사기_춘화첩'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '춘화첩', + name: '춘화첩(사기)', + info: '[전투] 사기 보정 +15', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'bonusAtmos') { + return (value as number) + 15; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_사기_탁주.ts b/packages/logic/src/items/che_사기_탁주.ts new file mode 100644 index 0000000..14fabdf --- /dev/null +++ b/packages/logic/src/items/che_사기_탁주.ts @@ -0,0 +1,39 @@ +import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import type { WarUnit } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_사기_탁주'; + +class CheAtmosIncreaseTrigger extends BaseWarUnitTrigger { + private readonly amount: number; + + constructor(unit: WarUnit, raiseType: number, amount: number) { + super(unit, 0, raiseType); + this.amount = amount; + } + + protected actionWar(self: WarUnit): boolean { + self.addAtmos(this.amount); + this.processConsumableItem(); + return true; + } +} + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '탁주', + name: '탁주(사기)', + info: '[전투] 사기 +30(한도 내). 1회용', + slot: 'item', + cost: 1000, + buyable: true, + consumable: true, + reqSecu: 1000, + unique: false, + getBattleInitTriggerList: (context) => { + if (!context.unit) return null; + return new WarTriggerCaller( + new CheAtmosIncreaseTrigger(context.unit, BaseWarUnitTrigger.TYPE_CONSUMABLE_ITEM, 30) + ); + }, +}; diff --git a/packages/logic/src/items/che_상성보정_과실주.ts b/packages/logic/src/items/che_상성보정_과실주.ts new file mode 100644 index 0000000..66a8ccb --- /dev/null +++ b/packages/logic/src/items/che_상성보정_과실주.ts @@ -0,0 +1,23 @@ +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_상성보정_과실주'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '과실주', + name: '과실주(상성)', + info: '[전투] 대등/유리한 병종 전투시 공격력 +10%, 피해 -10%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getWarPowerMultiplier: (_context, unit, oppose) => { + const attackCoef = unit.getCrewType().getAttackCoef(oppose.getCrewType()); + if (attackCoef < 1) { + return [1, 1]; + } + return [1.1, 0.9]; + }, +}; diff --git a/packages/logic/src/items/che_서적_01_효경전.ts b/packages/logic/src/items/che_서적_01_효경전.ts new file mode 100644 index 0000000..7bfefd7 --- /dev/null +++ b/packages/logic/src/items/che_서적_01_효경전.ts @@ -0,0 +1,40 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const STAT_VALUE = 1; + +const baseModule = createStatItemModule({ + key: 'che_서적_01_효경전', + rawName: '효경전', + slot: 'book', + statName: 'intelligence', + statValue: STAT_VALUE, + cost: 1000, + buyable: true, + reqSecu: 1000, + extraInfo: '[전투] 계략 시도 확률 +1%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'warMagicTrialProb') { + return (newValue as number) + 0.01; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_02_회남자.ts b/packages/logic/src/items/che_서적_02_회남자.ts new file mode 100644 index 0000000..c69de67 --- /dev/null +++ b/packages/logic/src/items/che_서적_02_회남자.ts @@ -0,0 +1,40 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const STAT_VALUE = 2; + +const baseModule = createStatItemModule({ + key: 'che_서적_02_회남자', + rawName: '회남자', + slot: 'book', + statName: 'intelligence', + statValue: STAT_VALUE, + cost: 3000, + buyable: true, + reqSecu: 2000, + extraInfo: '[전투] 계략 시도 확률 +1%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'warMagicTrialProb') { + return (newValue as number) + 0.01; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_04_건상역주.ts b/packages/logic/src/items/che_서적_04_건상역주.ts new file mode 100644 index 0000000..1663ebf --- /dev/null +++ b/packages/logic/src/items/che_서적_04_건상역주.ts @@ -0,0 +1,40 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const STAT_VALUE = 4; + +const baseModule = createStatItemModule({ + key: 'che_서적_04_건상역주', + rawName: '건상역주', + slot: 'book', + statName: 'intelligence', + statValue: STAT_VALUE, + cost: 6000, + buyable: true, + reqSecu: 3000, + extraInfo: '[전투] 계략 시도 확률 +2%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'warMagicTrialProb') { + return (newValue as number) + 0.02; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_05_여씨춘추.ts b/packages/logic/src/items/che_서적_05_여씨춘추.ts new file mode 100644 index 0000000..12d9809 --- /dev/null +++ b/packages/logic/src/items/che_서적_05_여씨춘추.ts @@ -0,0 +1,40 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const STAT_VALUE = 5; + +const baseModule = createStatItemModule({ + key: 'che_서적_05_여씨춘추', + rawName: '여씨춘추', + slot: 'book', + statName: 'intelligence', + statValue: STAT_VALUE, + cost: 7500, + buyable: true, + reqSecu: 3500, + extraInfo: '[전투] 계략 시도 확률 +3%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'warMagicTrialProb') { + return (newValue as number) + 0.03; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_06_사민월령.ts b/packages/logic/src/items/che_서적_06_사민월령.ts new file mode 100644 index 0000000..e91ce1f --- /dev/null +++ b/packages/logic/src/items/che_서적_06_사민월령.ts @@ -0,0 +1,40 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const STAT_VALUE = 6; + +const baseModule = createStatItemModule({ + key: 'che_서적_06_사민월령', + rawName: '사민월령', + slot: 'book', + statName: 'intelligence', + statValue: STAT_VALUE, + cost: 9000, + buyable: true, + reqSecu: 4000, + extraInfo: '[전투] 계략 시도 확률 +3%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'warMagicTrialProb') { + return (newValue as number) + 0.03; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_07_논어.ts b/packages/logic/src/items/che_서적_07_논어.ts new file mode 100644 index 0000000..e1a4e13 --- /dev/null +++ b/packages/logic/src/items/che_서적_07_논어.ts @@ -0,0 +1,33 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const baseModule = createStatItemModule({ + key: 'che_서적_07_논어', + rawName: '논어', + slot: 'book', + statName: 'intelligence', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 상대의 계략 성공 확률 -10%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcOpposeStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + _aux?: unknown + ): unknown { + if (statName === 'warMagicSuccessProb') { + return (value as number) - 0.1; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_07_사마법.ts b/packages/logic/src/items/che_서적_07_사마법.ts new file mode 100644 index 0000000..9272813 --- /dev/null +++ b/packages/logic/src/items/che_서적_07_사마법.ts @@ -0,0 +1,15 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_07_사마법', + rawName: '사마법', + slot: 'book', + statName: 'intelligence', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 상대의 계략을 10% 확률로 되돌림', +}); diff --git a/packages/logic/src/items/che_서적_07_위료자.ts b/packages/logic/src/items/che_서적_07_위료자.ts new file mode 100644 index 0000000..a0e1dd5 --- /dev/null +++ b/packages/logic/src/items/che_서적_07_위료자.ts @@ -0,0 +1,39 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const baseModule = createStatItemModule({ + key: 'che_서적_07_위료자', + rawName: '위료자', + slot: 'book', + statName: 'intelligence', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 계략 시도 확률 +20%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + aux?: unknown + ): unknown { + const newValue = baseModule.onCalcStat!( + context as unknown as GeneralActionContext, + statName as unknown as GeneralStatName, + value as unknown as number, + aux + ); + if (statName === 'warMagicTrialProb') { + return (newValue as number) + 0.2; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_07_한서.ts b/packages/logic/src/items/che_서적_07_한서.ts new file mode 100644 index 0000000..508b15b --- /dev/null +++ b/packages/logic/src/items/che_서적_07_한서.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_07_한서', + rawName: '한서', + slot: 'book', + statName: 'intelligence', + statValue: 7, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_08_사기.ts b/packages/logic/src/items/che_서적_08_사기.ts new file mode 100644 index 0000000..b3d2039 --- /dev/null +++ b/packages/logic/src/items/che_서적_08_사기.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_08_사기', + rawName: '사기', + slot: 'book', + statName: 'intelligence', + statValue: 8, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_09_역경.ts b/packages/logic/src/items/che_서적_09_역경.ts new file mode 100644 index 0000000..ec2b9fa --- /dev/null +++ b/packages/logic/src/items/che_서적_09_역경.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_09_역경', + rawName: '역경', + slot: 'book', + statName: 'intelligence', + statValue: 9, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_09_장자.ts b/packages/logic/src/items/che_서적_09_장자.ts new file mode 100644 index 0000000..e133f21 --- /dev/null +++ b/packages/logic/src/items/che_서적_09_장자.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_09_장자', + rawName: '장자', + slot: 'book', + statName: 'intelligence', + statValue: 9, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_10_구국론.ts b/packages/logic/src/items/che_서적_10_구국론.ts new file mode 100644 index 0000000..8cfb3e4 --- /dev/null +++ b/packages/logic/src/items/che_서적_10_구국론.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_10_구국론', + rawName: '구국론', + slot: 'book', + statName: 'intelligence', + statValue: 10, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_10_시경.ts b/packages/logic/src/items/che_서적_10_시경.ts new file mode 100644 index 0000000..ada2d59 --- /dev/null +++ b/packages/logic/src/items/che_서적_10_시경.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_10_시경', + rawName: '시경', + slot: 'book', + statName: 'intelligence', + statValue: 10, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_11_상군서.ts b/packages/logic/src/items/che_서적_11_상군서.ts new file mode 100644 index 0000000..de6bef4 --- /dev/null +++ b/packages/logic/src/items/che_서적_11_상군서.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_11_상군서', + rawName: '상군서', + slot: 'book', + statName: 'intelligence', + statValue: 11, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_11_춘추전.ts b/packages/logic/src/items/che_서적_11_춘추전.ts new file mode 100644 index 0000000..ab609c1 --- /dev/null +++ b/packages/logic/src/items/che_서적_11_춘추전.ts @@ -0,0 +1,33 @@ +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 { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +const baseModule = createStatItemModule({ + key: 'che_서적_11_춘추전', + rawName: '춘추전', + slot: 'book', + statName: 'intelligence', + statValue: 11, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 상대의 계략 성공 확률 -10%p', +}); + +export const itemModule: ItemModule = { + ...baseModule, + onCalcOpposeStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown, + _aux?: unknown + ): unknown { + if (statName === 'warMagicSuccessProb') { + return (value as number) - 0.1; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_서적_12_맹덕신서.ts b/packages/logic/src/items/che_서적_12_맹덕신서.ts new file mode 100644 index 0000000..bca3195 --- /dev/null +++ b/packages/logic/src/items/che_서적_12_맹덕신서.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_12_맹덕신서', + rawName: '맹덕신서', + slot: 'book', + statName: 'intelligence', + statValue: 12, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_12_산해경.ts b/packages/logic/src/items/che_서적_12_산해경.ts new file mode 100644 index 0000000..1824c09 --- /dev/null +++ b/packages/logic/src/items/che_서적_12_산해경.ts @@ -0,0 +1,15 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_12_산해경', + rawName: '산해경', + slot: 'book', + statName: 'intelligence', + statValue: 12, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, + extraInfo: '[전투] 상대의 계략을 10% 확률로 되돌림', +}); diff --git a/packages/logic/src/items/che_서적_13_관자.ts b/packages/logic/src/items/che_서적_13_관자.ts new file mode 100644 index 0000000..ccf7a0d --- /dev/null +++ b/packages/logic/src/items/che_서적_13_관자.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_13_관자', + rawName: '관자', + slot: 'book', + statName: 'intelligence', + statValue: 13, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_13_병법24편.ts b/packages/logic/src/items/che_서적_13_병법24편.ts new file mode 100644 index 0000000..0626776 --- /dev/null +++ b/packages/logic/src/items/che_서적_13_병법24편.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_13_병법24편', + rawName: '병법24편', + slot: 'book', + statName: 'intelligence', + statValue: 13, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_14_오자병법.ts b/packages/logic/src/items/che_서적_14_오자병법.ts new file mode 100644 index 0000000..ed9e65c --- /dev/null +++ b/packages/logic/src/items/che_서적_14_오자병법.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_14_오자병법', + rawName: '오자병법', + slot: 'book', + statName: 'intelligence', + statValue: 14, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_14_한비자.ts b/packages/logic/src/items/che_서적_14_한비자.ts new file mode 100644 index 0000000..08ba181 --- /dev/null +++ b/packages/logic/src/items/che_서적_14_한비자.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_14_한비자', + rawName: '한비자', + slot: 'book', + statName: 'intelligence', + statValue: 14, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_15_노자.ts b/packages/logic/src/items/che_서적_15_노자.ts new file mode 100644 index 0000000..12a8a29 --- /dev/null +++ b/packages/logic/src/items/che_서적_15_노자.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_15_노자', + rawName: '노자', + slot: 'book', + statName: 'intelligence', + statValue: 15, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_서적_15_손자병법.ts b/packages/logic/src/items/che_서적_15_손자병법.ts new file mode 100644 index 0000000..399c5cb --- /dev/null +++ b/packages/logic/src/items/che_서적_15_손자병법.ts @@ -0,0 +1,14 @@ +import { createStatItemModule } from './base.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = createStatItemModule({ + key: 'che_서적_15_손자병법', + rawName: '손자병법', + slot: 'book', + statName: 'intelligence', + statValue: 15, + cost: 200, + buyable: false, + reqSecu: 0, + unique: true, +}); diff --git a/packages/logic/src/items/che_숙련_동작.ts b/packages/logic/src/items/che_숙련_동작.ts new file mode 100644 index 0000000..fd30c86 --- /dev/null +++ b/packages/logic/src/items/che_숙련_동작.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_숙련_동작'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '동작', + name: '동작(숙련)', + info: '숙련 +20%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === ('addDex' as unknown as GeneralStatName)) { + return (value as number) * 1.2; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_약탈_옥벽.ts b/packages/logic/src/items/che_약탈_옥벽.ts new file mode 100644 index 0000000..58ae82d --- /dev/null +++ b/packages/logic/src/items/che_약탈_옥벽.ts @@ -0,0 +1,122 @@ +import { LogFormat } from '@sammo-ts/logic/logging/types.js'; +import { TriggerPriority } from '@sammo-ts/logic/triggers/core.js'; +import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import { WarUnitGeneral, type WarUnit } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_약탈_옥벽'; + +class CheTheftAttemptTrigger extends BaseWarUnitTrigger { + private readonly ratio: number; + private readonly theftRatio: number; + + constructor(unit: WarUnit, raiseType: number, ratio: number, theftRatio: number) { + super(unit, TriggerPriority.Pre + 400, raiseType); + this.ratio = ratio; + this.theftRatio = theftRatio; + } + + protected actionWar( + self: WarUnit, + oppose: WarUnit, + selfEnv: Record, + _opposeEnv: Record + ): boolean { + if (!(self instanceof WarUnitGeneral)) { + return true; + } + if (self.getPhase() !== 0 && oppose.getPhase() !== 0) { + return true; + } + if (!(oppose instanceof WarUnitGeneral)) { + return true; + } + if (self.hasActivatedSkill('약탈')) { + return true; + } + if (self.hasActivatedSkill('약탈불가')) { + return true; + } + if (!self.rng.nextBool(this.ratio)) { + return true; + } + + self.activateSkill('약탈'); + selfEnv['theftRatio'] = this.theftRatio; + return true; + } +} + +class CheTheftActivateTrigger extends BaseWarUnitTrigger { + constructor(unit: WarUnit, raiseType: number) { + super(unit, TriggerPriority.Post + 350, raiseType); + } + + protected actionWar( + self: WarUnit, + oppose: WarUnit, + selfEnv: Record, + _opposeEnv: Record + ): boolean { + if (!self.hasActivatedSkill('약탈')) { + return true; + } + if (selfEnv['약탈발동']) { + return true; + } + selfEnv['약탈발동'] = true; + + if (!(self instanceof WarUnitGeneral) || !(oppose instanceof WarUnitGeneral)) { + return true; + } + + const theftRatio = (selfEnv['theftRatio'] as number) ?? 0; + const selfGeneral = self.getGeneral(); + const opposeGeneral = oppose.getGeneral(); + + const theftGold = Math.floor(opposeGeneral.gold * theftRatio); + const theftRice = Math.floor(opposeGeneral.rice * theftRatio); + + opposeGeneral.gold = Math.max(0, opposeGeneral.gold - theftGold); + opposeGeneral.rice = Math.max(0, opposeGeneral.rice - theftRice); + + selfGeneral.gold += theftGold; + selfGeneral.rice += theftRice; + + self.getLogger().pushGeneralActionLog('상대를 약탈했다!', LogFormat.PLAIN); + self.getLogger().pushGeneralBattleDetailLog( + `상대에게서 금 ${theftGold.toLocaleString()}, 쌀 ${theftRice.toLocaleString()} 만큼을 약탈했다!`, + LogFormat.PLAIN + ); + oppose.getLogger().pushGeneralActionLog('상대에게 약탈당했다!', LogFormat.PLAIN); + oppose + .getLogger() + .pushGeneralBattleDetailLog( + `상대에게 금 ${theftGold.toLocaleString()}, 쌀 ${theftRice.toLocaleString()} 만큼을 약탈당했다!`, + LogFormat.PLAIN + ); + + this.processConsumableItem(); + return true; + } +} + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '옥벽', + name: '옥벽(약탈)', + info: '[전투] 새로운 상대와 전투 시 20% 확률로 상대 금, 쌀 10% 약탈', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getBattlePhaseTriggerList: (context) => { + if (!context.unit) return null; + return new WarTriggerCaller( + new CheTheftAttemptTrigger(context.unit, BaseWarUnitTrigger.TYPE_ITEM, 0.2, 0.1), + new CheTheftActivateTrigger(context.unit, BaseWarUnitTrigger.TYPE_ITEM) + ); + }, +}; diff --git a/packages/logic/src/items/che_의술_상한잡병론.ts b/packages/logic/src/items/che_의술_상한잡병론.ts new file mode 100644 index 0000000..0c355e0 --- /dev/null +++ b/packages/logic/src/items/che_의술_상한잡병론.ts @@ -0,0 +1,19 @@ +import { GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js'; +import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/che_도시치료.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = { + key: 'che_의술_상한잡병론', + rawName: '상한잡병론', + name: '상한잡병론(의술)', + info: '[의술] 매달 도시의 부상병을 치료. 치료 효율 50% 향상', + slot: 'book', + cost: 500, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getPreTurnExecuteTriggerList: (context) => { + return new GeneralTriggerCaller(new CheUisulCityHealTrigger(context.general, 1.5)); + }, +}; diff --git a/packages/logic/src/items/che_의술_정력견혈산.ts b/packages/logic/src/items/che_의술_정력견혈산.ts new file mode 100644 index 0000000..b771b6c --- /dev/null +++ b/packages/logic/src/items/che_의술_정력견혈산.ts @@ -0,0 +1,19 @@ +import { GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js'; +import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/che_도시치료.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = { + key: 'che_의술_정력견혈산', + rawName: '정력견혈산', + name: '정력견혈산(의술)', + info: '[의술] 매달 도시의 부상병을 치료. 치료 효율 100% 향상', + slot: 'book', + cost: 500, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getPreTurnExecuteTriggerList: (context) => { + return new GeneralTriggerCaller(new CheUisulCityHealTrigger(context.general, 2)); + }, +}; diff --git a/packages/logic/src/items/che_의술_청낭서.ts b/packages/logic/src/items/che_의술_청낭서.ts new file mode 100644 index 0000000..0497584 --- /dev/null +++ b/packages/logic/src/items/che_의술_청낭서.ts @@ -0,0 +1,19 @@ +import { GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js'; +import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/che_도시치료.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = { + key: 'che_의술_청낭서', + rawName: '청낭서', + name: '청낭서(의술)', + info: '[의술] 매달 도시의 부상병을 치료. 치료 효율 50% 향상', + slot: 'book', + cost: 500, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getPreTurnExecuteTriggerList: (context) => { + return new GeneralTriggerCaller(new CheUisulCityHealTrigger(context.general, 1.5)); + }, +}; diff --git a/packages/logic/src/items/che_의술_태평청령.ts b/packages/logic/src/items/che_의술_태평청령.ts new file mode 100644 index 0000000..648fec3 --- /dev/null +++ b/packages/logic/src/items/che_의술_태평청령.ts @@ -0,0 +1,19 @@ +import { GeneralTriggerCaller } from '@sammo-ts/logic/triggers/general.js'; +import { CheUisulCityHealTrigger } from '@sammo-ts/logic/triggers/generalTriggers/che_도시치료.js'; +import type { ItemModule } from './types.js'; + +export const itemModule: ItemModule = { + key: 'che_의술_태평청령', + rawName: '태평청령', + name: '태평청령(의술)', + info: '[의술] 매달 도시의 부상병을 치료. 치료 효율 50% 향상', + slot: 'book', + cost: 500, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getPreTurnExecuteTriggerList: (context) => { + return new GeneralTriggerCaller(new CheUisulCityHealTrigger(context.general, 1.5)); + }, +}; diff --git a/packages/logic/src/items/che_저격_매화수전.ts b/packages/logic/src/items/che_저격_매화수전.ts new file mode 100644 index 0000000..660fad2 --- /dev/null +++ b/packages/logic/src/items/che_저격_매화수전.ts @@ -0,0 +1,28 @@ +import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import { CheSnipingActivateTrigger, CheSnipingAttemptTrigger } from '@sammo-ts/logic/war/triggers/che_저격.js'; +import { BaseWarUnitTrigger } from '@sammo-ts/logic/war/triggers.js'; +import type { ItemModule } from './types.js'; + +const RAISE_TYPE = BaseWarUnitTrigger.TYPE_ITEM + BaseWarUnitTrigger.TYPE_DEDUP_TYPE_BASE * 304; + +export const itemModule: ItemModule = { + key: 'che_저격_매화수전', + rawName: '매화수전', + name: '매화수전(저격)', + info: '[전투] 계략 시도 단계에서 저격 확률 50%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: true, + getBattlePhaseTriggerList: (context) => { + if (!context.unit) { + return null; + } + return new WarTriggerCaller( + new CheSnipingAttemptTrigger(context.unit, RAISE_TYPE, 0.5, 20, 40), + new CheSnipingActivateTrigger(context.unit, RAISE_TYPE) + ); + }, +}; diff --git a/packages/logic/src/items/che_저격_비도.ts b/packages/logic/src/items/che_저격_비도.ts new file mode 100644 index 0000000..a8ac303 --- /dev/null +++ b/packages/logic/src/items/che_저격_비도.ts @@ -0,0 +1,28 @@ +import { WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import { CheSnipingActivateTrigger, CheSnipingAttemptTrigger } from '@sammo-ts/logic/war/triggers/che_저격.js'; +import { BaseWarUnitTrigger } from '@sammo-ts/logic/war/triggers.js'; +import type { ItemModule } from './types.js'; + +const RAISE_TYPE = BaseWarUnitTrigger.TYPE_ITEM + BaseWarUnitTrigger.TYPE_DEDUP_TYPE_BASE * 305; + +export const itemModule: ItemModule = { + key: 'che_저격_비도', + rawName: '비도', + name: '비도(저격)', + info: '[전투] 계략 시도 단계에서 저격 확률 50%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: true, + getBattlePhaseTriggerList: (context) => { + if (!context.unit) { + return null; + } + return new WarTriggerCaller( + new CheSnipingAttemptTrigger(context.unit, RAISE_TYPE, 0.5, 20, 40), + new CheSnipingActivateTrigger(context.unit, RAISE_TYPE) + ); + }, +}; diff --git a/packages/logic/src/items/che_저격_수극.ts b/packages/logic/src/items/che_저격_수극.ts new file mode 100644 index 0000000..59a7cd5 --- /dev/null +++ b/packages/logic/src/items/che_저격_수극.ts @@ -0,0 +1,25 @@ +import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import { CheSnipingAttemptTrigger, CheSnipingActivateTrigger } from '@sammo-ts/logic/war/triggers/che_저격.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_저격_수극'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '수극', + name: '수극(저격)', + info: '[전투] 전투 개시 시 저격. 1회용', + slot: 'item', + cost: 1000, + buyable: true, + consumable: true, + reqSecu: 1000, + unique: false, + getBattlePhaseTriggerList: (context) => { + if (!context.unit) return null; + return new WarTriggerCaller( + new CheSnipingAttemptTrigger(context.unit, BaseWarUnitTrigger.TYPE_CONSUMABLE_ITEM, 1, 20, 40), + new CheSnipingActivateTrigger(context.unit, BaseWarUnitTrigger.TYPE_CONSUMABLE_ITEM) + ); + }, +}; diff --git a/packages/logic/src/items/che_저지_삼황내문.ts b/packages/logic/src/items/che_저지_삼황내문.ts new file mode 100644 index 0000000..81bab1c --- /dev/null +++ b/packages/logic/src/items/che_저지_삼황내문.ts @@ -0,0 +1,98 @@ +import { LogFormat } from '@sammo-ts/logic/logging/types.js'; +import { TriggerPriority } from '@sammo-ts/logic/triggers/core.js'; +import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import { WarUnitGeneral, type WarUnit } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_저지_삼황내문'; + +class CheHaltTrigger extends BaseWarUnitTrigger { + constructor(unit: WarUnit) { + super(unit, TriggerPriority.Post); + } + + protected actionWar( + self: WarUnit, + oppose: WarUnit, + selfEnv: Record, + _opposeEnv: Record + ): boolean { + if (!self.hasActivatedSkill('저지')) { + return true; + } + + if (selfEnv['저지발동']) { + return true; + } + selfEnv['저지발동'] = true; + + self.addPhase(-1); + oppose.addPhase(-1); + if (self.getPhase() < self.getMaxPhase()) { + oppose.addBonusPhase(-1); + } + + self.getLogger().pushGeneralBattleDetailLog('상대를 저지했다!', LogFormat.PLAIN); + oppose.getLogger().pushGeneralBattleDetailLog('저지당했다!', LogFormat.PLAIN); + + const calcDamage = oppose.getWarPower() * 0.9; + if (self instanceof WarUnitGeneral) { + self.addDex(oppose.getCrewType(), oppose.getWarPower() * 0.9); + self.addDex(self.getCrewType(), calcDamage); + + self.addLevelExp(calcDamage / 50); + let rice = self.calcRiceConsumption(calcDamage); + rice *= 0.25; + const general = self.getGeneral(); + general.rice = Math.max(0, general.rice - rice); + } + + self.setWarPowerMultiply(0); + oppose.setWarPowerMultiply(0); + + return false; + } +} + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '삼황내문', + name: '삼황내문(저지)', + info: '[전투] 수비 시 첫 페이즈 저지, 50% 확률로 2 페이즈 저지', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getBattlePhaseTriggerList: (context) => { + const unit = context.unit; + if (!unit || unit.isAttacker()) { + return null; + } + + if (unit.getPhase() > 0) { + return null; + } + const haltCount = unit.hasActivatedSkillOnLog('저지'); + if (haltCount >= 2) { + return null; + } + if (haltCount === 1 && unit.getPhase() === 0 && !unit.rng.nextBool(0.5)) { + return null; + } + + return new WarTriggerCaller( + new (class extends BaseWarUnitTrigger { + constructor(u: WarUnit) { + super(u, TriggerPriority.Pre); + } + protected actionWar(u: WarUnit): boolean { + u.activateSkill('특수', '저지'); + return true; + } + })(unit), + new CheHaltTrigger(unit) + ); + }, +}; diff --git a/packages/logic/src/items/che_전략_평만지장도.ts b/packages/logic/src/items/che_전략_평만지장도.ts new file mode 100644 index 0000000..e14d992 --- /dev/null +++ b/packages/logic/src/items/che_전략_평만지장도.ts @@ -0,0 +1,22 @@ +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_전략_평만지장도'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '평만지장도', + name: '평만지장도(전략)', + info: '[전략] 국가전략 사용시 재사용 대기 기간 -20%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStrategic: (_context, _turnType, varType, value) => { + if (varType === 'delay') { + return Math.round(value * 0.8); + } + return value; + }, +}; diff --git a/packages/logic/src/items/che_조달_주판.ts b/packages/logic/src/items/che_조달_주판.ts new file mode 100644 index 0000000..4be42e7 --- /dev/null +++ b/packages/logic/src/items/che_조달_주판.ts @@ -0,0 +1,23 @@ +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_조달_주판'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '주판', + name: '주판(조달)', + info: '[내정] 물자조달 성공 확률 +20%p, 물자조달 획득량 +100%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcDomestic: (_context, turnType, varType, value) => { + if (turnType === '조달') { + if (varType === 'success') return value + 0.2; + if (varType === 'score') return value * 2; + } + return value; + }, +}; diff --git a/packages/logic/src/items/che_진압_박혁론.ts b/packages/logic/src/items/che_진압_박혁론.ts new file mode 100644 index 0000000..4ae4a0b --- /dev/null +++ b/packages/logic/src/items/che_진압_박혁론.ts @@ -0,0 +1,33 @@ +import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import type { WarUnit } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_진압_박혁론'; + +class CheSuppressTrigger extends BaseWarUnitTrigger { + constructor(unit: WarUnit) { + super(unit, 0); // Priority 0 or matching legacy + } + + protected actionWar(self: WarUnit): boolean { + self.activateSkill('반계불가', '격노불가'); + return true; + } +} + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '박혁론', + name: '박혁론(진압)', + info: '[전투] 상대의 계략 되돌림, 격노 불가', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getBattlePhaseTriggerList: (context) => { + if (!context.unit) return null; + return new WarTriggerCaller(new CheSuppressTrigger(context.unit)); + }, +}; diff --git a/packages/logic/src/items/che_집중_전국책.ts b/packages/logic/src/items/che_집중_전국책.ts new file mode 100644 index 0000000..87dc2fb --- /dev/null +++ b/packages/logic/src/items/che_집중_전국책.ts @@ -0,0 +1,27 @@ +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 { ItemModule } from './types.js'; + +export const itemModule: ItemModule = { + key: 'che_집중_전국책', + rawName: '전국책', + name: '전국책(집중)', + info: '[전투] 계략 성공 시 대미지 +30%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: true, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warMagicSuccessDamage') { + return (value as number) * 1.3; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_징병_낙주.ts b/packages/logic/src/items/che_징병_낙주.ts new file mode 100644 index 0000000..a06688b --- /dev/null +++ b/packages/logic/src/items/che_징병_낙주.ts @@ -0,0 +1,38 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_징병_낙주'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '낙주', + name: '낙주(징병)', + info: '[군사] 징·모병비 -30%
[기타] 통솔 순수 능력치 보정 +15%, 징병/모병/소집해제 시 인구 변동 없음', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcDomestic: (_context, turnType, varType, value) => { + if (turnType === '징병' || turnType === '모병') { + if (varType === 'cost') return value * 0.7; + } + if (turnType === '징집인구' && varType === 'score') { + return 0; + } + return value; + }, + onCalcStat: function ( + context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'leadership') { + return (value as number) + (context as unknown as GeneralActionContext).general.stats.leadership * 0.15; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_척사_오악진형도.ts b/packages/logic/src/items/che_척사_오악진형도.ts new file mode 100644 index 0000000..275ae5b --- /dev/null +++ b/packages/logic/src/items/che_척사_오악진형도.ts @@ -0,0 +1,28 @@ +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_척사_오악진형도'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '오악진형도', + name: '오악진형도(척사)', + info: '[전투] 지역·도시 병종 상대로 대미지 +15%, 아군 피해 -15%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + getWarPowerMultiplier: (_context, _unit, oppose) => { + const opposeCrewType = oppose.getCrewType(); + // In Sammo, region/city units usually have reqCities or reqRegions in crewType. + // We'll check if those properties exist and have at least one element. + if ( + (opposeCrewType.reqCities && opposeCrewType.reqCities.length > 0) || + (opposeCrewType.reqRegions && opposeCrewType.reqRegions.length > 0) + ) { + return [1.15, 0.85]; + } + return [1, 1]; + }, +}; diff --git a/packages/logic/src/items/che_필살_둔갑천서.ts b/packages/logic/src/items/che_필살_둔갑천서.ts new file mode 100644 index 0000000..614d8aa --- /dev/null +++ b/packages/logic/src/items/che_필살_둔갑천서.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_필살_둔갑천서'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '둔갑천서', + name: '둔갑천서(필살)', + info: '[전투] 필살 확률 +20%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warCriticalRatio') { + return (value as number) + 0.2; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_행동_서촉지형도.ts b/packages/logic/src/items/che_행동_서촉지형도.ts new file mode 100644 index 0000000..e32ccb8 --- /dev/null +++ b/packages/logic/src/items/che_행동_서촉지형도.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_행동_서촉지형도'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '서촉지형도', + name: '서촉지형도(행동)', + info: '[전투] 공격 시 페이즈 + 2', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'initWarPhase') { + return (value as number) + 2; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_환술_논어집해.ts b/packages/logic/src/items/che_환술_논어집해.ts new file mode 100644 index 0000000..63a3dfe --- /dev/null +++ b/packages/logic/src/items/che_환술_논어집해.ts @@ -0,0 +1,31 @@ +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 { ItemModule } from './types.js'; + +export const itemModule: ItemModule = { + key: 'che_환술_논어집해', + rawName: '논어집해', + name: '논어집해(환술)', + info: '[전투] 계략 성공 확률 +10%p, 계략 성공 시 대미지 +20%', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: true, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + let newValue = value; + if (statName === 'warMagicSuccessProb') { + newValue = (newValue as number) + 0.1; + } + if (statName === 'warMagicSuccessDamage') { + newValue = (newValue as number) * 1.2; + } + return newValue; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_회피_태평요술.ts b/packages/logic/src/items/che_회피_태평요술.ts new file mode 100644 index 0000000..b7fe615 --- /dev/null +++ b/packages/logic/src/items/che_회피_태평요술.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_회피_태평요술'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '태평요술', + name: '태평요술(회피)', + info: '[전투] 회피 확률 +20%p', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'warAvoidRatio') { + return (value as number) + 0.2; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_훈련_단결도.ts b/packages/logic/src/items/che_훈련_단결도.ts new file mode 100644 index 0000000..f1befdd --- /dev/null +++ b/packages/logic/src/items/che_훈련_단결도.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_훈련_단결도'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '단결도', + name: '단결도(훈련)', + info: '[전투] 훈련 보정 +15', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'bonusTrain') { + return (value as number) + 15; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_훈련_철벽서.ts b/packages/logic/src/items/che_훈련_철벽서.ts new file mode 100644 index 0000000..8e0d552 --- /dev/null +++ b/packages/logic/src/items/che_훈련_철벽서.ts @@ -0,0 +1,29 @@ +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 { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_훈련_철벽서'; + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '철벽서', + name: '철벽서(훈련)', + info: '[전투] 훈련 보정 +15', + slot: 'item', + cost: 200, + buyable: false, + consumable: false, + reqSecu: 0, + unique: false, + onCalcStat: function ( + _context: GeneralActionContext | WarActionContext, + statName: GeneralStatName | WarStatName, + value: unknown + ): unknown { + if (statName === 'bonusTrain') { + return (value as number) + 15; + } + return value; + } as NonNullable, +}; diff --git a/packages/logic/src/items/che_훈련_청주.ts b/packages/logic/src/items/che_훈련_청주.ts new file mode 100644 index 0000000..363eee1 --- /dev/null +++ b/packages/logic/src/items/che_훈련_청주.ts @@ -0,0 +1,39 @@ +import { BaseWarUnitTrigger, WarTriggerCaller } from '@sammo-ts/logic/war/triggers.js'; +import type { WarUnit } from '@sammo-ts/logic/war/units.js'; +import type { ItemModule } from './types.js'; + +const ITEM_KEY = 'che_훈련_청주'; + +class CheTrainIncreaseTrigger extends BaseWarUnitTrigger { + private readonly amount: number; + + constructor(unit: WarUnit, raiseType: number, amount: number) { + super(unit, 0, raiseType); + this.amount = amount; + } + + protected actionWar(self: WarUnit): boolean { + self.addTrain(this.amount); + this.processConsumableItem(); + return true; + } +} + +export const itemModule: ItemModule = { + key: ITEM_KEY, + rawName: '청주', + name: '청주(훈련)', + info: '[전투] 훈련 +40(한도 내). 1회용', + slot: 'item', + cost: 1000, + buyable: true, + consumable: true, + reqSecu: 1000, + unique: false, + getBattleInitTriggerList: (context) => { + if (!context.unit) return null; + return new WarTriggerCaller( + new CheTrainIncreaseTrigger(context.unit, BaseWarUnitTrigger.TYPE_CONSUMABLE_ITEM, 40) + ); + }, +}; diff --git a/packages/logic/src/items/index.ts b/packages/logic/src/items/index.ts index b53f5fe..65f0870 100644 --- a/packages/logic/src/items/index.ts +++ b/packages/logic/src/items/index.ts @@ -19,15 +19,129 @@ import type { ItemModule, ItemModuleExport } from './types.js'; import { listEquippedItemKeys } from './utils.js'; export const ITEM_KEYS = [ - 'che_명마_06_흑색마', - 'che_무기_02_단궁', - 'che_서적_03_변도론', - 'che_치료_환약', - 'che_명마_12_사륜거', - 'che_무기_09_동호비궁', - 'che_서적_08_전론', - 'che_보물_도기', + 'che_간파_노군입산부', + 'che_격노_구정신단경', + 'che_계략_삼략', + 'che_계략_육도', + 'che_계략_이추', + 'che_계략_향낭', + 'che_공성_묵자', + 'che_내정_납금박산로', + 'che_농성_위공자병법', + 'che_농성_주서음부', + 'che_능력치_무력_두강주', + 'che_능력치_지력_이강주', + 'che_능력치_통솔_보령압주', 'che_명마_01_노기', + 'che_명마_02_조랑', + 'che_명마_03_노새', + 'che_명마_04_나귀', + 'che_명마_05_갈색마', + 'che_명마_06_흑색마', + 'che_명마_07_기주마', + 'che_명마_07_백마', + 'che_명마_07_백상', + 'che_명마_07_오환마', + 'che_명마_08_양주마', + 'che_명마_08_흉노마', + 'che_명마_09_과하마', + 'che_명마_09_의남백마', + 'che_명마_10_대완마', + 'che_명마_10_옥추마', + 'che_명마_11_서량마', + 'che_명마_11_화종마', + 'che_명마_12_사륜거', + 'che_명마_12_옥란백용구', + 'che_명마_13_적로', + 'che_명마_13_절영', + 'che_명마_14_적란마', + 'che_명마_14_조황비전', + 'che_명마_15_적토마', + 'che_명마_15_한혈마', + 'che_명성_구석', + 'che_무기_01_단도', + 'che_무기_02_단궁', + 'che_무기_03_단극', + 'che_무기_04_목검', + 'che_무기_05_죽창', + 'che_무기_06_소부', + 'che_무기_07_동추', + 'che_무기_07_맥궁', + 'che_무기_07_철쇄', + 'che_무기_07_철편', + 'che_무기_08_유성추', + 'che_무기_08_철질여골', + 'che_무기_09_동호비궁', + 'che_무기_09_쌍철극', + 'che_무기_10_대부', + 'che_무기_10_삼첨도', + 'che_무기_11_고정도', + 'che_무기_11_이광궁', + 'che_무기_12_철척사모', + 'che_무기_12_칠성검', + 'che_무기_13_사모', + 'che_무기_13_양유기궁', + 'che_무기_14_방천화극', + 'che_무기_14_언월도', + 'che_무기_15_의천검', + 'che_무기_15_청홍검', + 'che_보물_도기', + 'che_부적_태현청생부', + 'che_불굴_상편', + 'che_사기_초선화', + 'che_사기_춘화첩', + 'che_사기_탁주', + 'che_상성보정_과실주', + 'che_서적_01_효경전', + 'che_서적_02_회남자', + 'che_서적_03_변도론', + 'che_서적_04_건상역주', + 'che_서적_05_여씨춘추', + 'che_서적_06_사민월령', + 'che_서적_07_논어', + 'che_서적_07_사마법', + 'che_서적_07_위료자', + 'che_서적_07_한서', + 'che_서적_08_사기', + 'che_서적_08_전론', + 'che_서적_09_역경', + 'che_서적_09_장자', + 'che_서적_10_구국론', + 'che_서적_10_시경', + 'che_서적_11_상군서', + 'che_서적_11_춘추전', + 'che_서적_12_맹덕신서', + 'che_서적_12_산해경', + 'che_서적_13_관자', + 'che_서적_13_병법24편', + 'che_서적_14_오자병법', + 'che_서적_14_한비자', + 'che_서적_15_노자', + 'che_서적_15_손자병법', + 'che_숙련_동작', + 'che_약탈_옥벽', + 'che_의술_상한잡병론', + 'che_의술_정력견혈산', + 'che_의술_청낭서', + 'che_의술_태평청령', + 'che_저격_매화수전', + 'che_저격_비도', + 'che_저격_수극', + 'che_저지_삼황내문', + 'che_전략_평만지장도', + 'che_조달_주판', + 'che_진압_박혁론', + 'che_집중_전국책', + 'che_징병_낙주', + 'che_척사_오악진형도', + 'che_치료_환약', + 'che_필살_둔갑천서', + 'che_행동_서촉지형도', + 'che_환술_논어집해', + 'che_회피_태평요술', + 'che_훈련_단결도', + 'che_훈련_철벽서', + 'che_훈련_청주', ] as const; export type ItemKey = (typeof ITEM_KEYS)[number]; @@ -35,15 +149,129 @@ export type ItemKey = (typeof ITEM_KEYS)[number]; export type ItemImporter = () => Promise; const defaultImporters: Record = { - che_명마_06_흑색마: async () => import('./che_명마_06_흑색마.js'), - che_무기_02_단궁: async () => import('./che_무기_02_단궁.js'), - che_서적_03_변도론: async () => import('./che_서적_03_변도론.js'), - che_치료_환약: async () => import('./che_치료_환약.js'), - che_명마_12_사륜거: async () => import('./che_명마_12_사륜거.js'), - che_무기_09_동호비궁: async () => import('./che_무기_09_동호비궁.js'), - che_서적_08_전론: async () => import('./che_서적_08_전론.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_명마_01_노기: async () => import('./che_명마_01_노기.js'), + che_명마_02_조랑: async () => import('./che_명마_02_조랑.js'), + che_명마_03_노새: async () => import('./che_명마_03_노새.js'), + che_명마_04_나귀: async () => import('./che_명마_04_나귀.js'), + che_명마_05_갈색마: async () => import('./che_명마_05_갈색마.js'), + che_명마_06_흑색마: async () => import('./che_명마_06_흑색마.js'), + che_명마_07_기주마: async () => import('./che_명마_07_기주마.js'), + che_명마_07_백마: async () => import('./che_명마_07_백마.js'), + che_명마_07_백상: async () => import('./che_명마_07_백상.js'), + che_명마_07_오환마: async () => import('./che_명마_07_오환마.js'), + che_명마_08_양주마: async () => import('./che_명마_08_양주마.js'), + che_명마_08_흉노마: async () => import('./che_명마_08_흉노마.js'), + che_명마_09_과하마: async () => import('./che_명마_09_과하마.js'), + che_명마_09_의남백마: async () => import('./che_명마_09_의남백마.js'), + che_명마_10_대완마: async () => import('./che_명마_10_대완마.js'), + che_명마_10_옥추마: async () => import('./che_명마_10_옥추마.js'), + che_명마_11_서량마: async () => import('./che_명마_11_서량마.js'), + che_명마_11_화종마: async () => import('./che_명마_11_화종마.js'), + che_명마_12_사륜거: async () => import('./che_명마_12_사륜거.js'), + che_명마_12_옥란백용구: async () => import('./che_명마_12_옥란백용구.js'), + che_명마_13_적로: async () => import('./che_명마_13_적로.js'), + che_명마_13_절영: async () => import('./che_명마_13_절영.js'), + che_명마_14_적란마: async () => import('./che_명마_14_적란마.js'), + che_명마_14_조황비전: async () => import('./che_명마_14_조황비전.js'), + che_명마_15_적토마: async () => import('./che_명마_15_적토마.js'), + che_명마_15_한혈마: async () => import('./che_명마_15_한혈마.js'), + che_명성_구석: async () => import('./che_명성_구석.js'), + che_무기_01_단도: async () => import('./che_무기_01_단도.js'), + che_무기_02_단궁: async () => import('./che_무기_02_단궁.js'), + che_무기_03_단극: async () => import('./che_무기_03_단극.js'), + che_무기_04_목검: async () => import('./che_무기_04_목검.js'), + che_무기_05_죽창: async () => import('./che_무기_05_죽창.js'), + che_무기_06_소부: async () => import('./che_무기_06_소부.js'), + che_무기_07_동추: async () => import('./che_무기_07_동추.js'), + che_무기_07_맥궁: async () => import('./che_무기_07_맥궁.js'), + che_무기_07_철쇄: async () => import('./che_무기_07_철쇄.js'), + che_무기_07_철편: async () => import('./che_무기_07_철편.js'), + che_무기_08_유성추: async () => import('./che_무기_08_유성추.js'), + che_무기_08_철질여골: async () => import('./che_무기_08_철질여골.js'), + che_무기_09_동호비궁: async () => import('./che_무기_09_동호비궁.js'), + che_무기_09_쌍철극: async () => import('./che_무기_09_쌍철극.js'), + che_무기_10_대부: async () => import('./che_무기_10_대부.js'), + che_무기_10_삼첨도: async () => import('./che_무기_10_삼첨도.js'), + che_무기_11_고정도: async () => import('./che_무기_11_고정도.js'), + che_무기_11_이광궁: async () => import('./che_무기_11_이광궁.js'), + che_무기_12_철척사모: async () => import('./che_무기_12_철척사모.js'), + che_무기_12_칠성검: async () => import('./che_무기_12_칠성검.js'), + che_무기_13_사모: async () => import('./che_무기_13_사모.js'), + che_무기_13_양유기궁: async () => import('./che_무기_13_양유기궁.js'), + che_무기_14_방천화극: async () => import('./che_무기_14_방천화극.js'), + che_무기_14_언월도: async () => import('./che_무기_14_언월도.js'), + che_무기_15_의천검: async () => import('./che_무기_15_의천검.js'), + che_무기_15_청홍검: async () => import('./che_무기_15_청홍검.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_서적_01_효경전: async () => import('./che_서적_01_효경전.js'), + che_서적_02_회남자: async () => import('./che_서적_02_회남자.js'), + che_서적_03_변도론: async () => import('./che_서적_03_변도론.js'), + che_서적_04_건상역주: async () => import('./che_서적_04_건상역주.js'), + che_서적_05_여씨춘추: async () => import('./che_서적_05_여씨춘추.js'), + che_서적_06_사민월령: async () => import('./che_서적_06_사민월령.js'), + che_서적_07_논어: async () => import('./che_서적_07_논어.js'), + che_서적_07_사마법: async () => import('./che_서적_07_사마법.js'), + che_서적_07_위료자: async () => import('./che_서적_07_위료자.js'), + che_서적_07_한서: async () => import('./che_서적_07_한서.js'), + che_서적_08_사기: async () => import('./che_서적_08_사기.js'), + che_서적_08_전론: async () => import('./che_서적_08_전론.js'), + che_서적_09_역경: async () => import('./che_서적_09_역경.js'), + che_서적_09_장자: async () => import('./che_서적_09_장자.js'), + che_서적_10_구국론: async () => import('./che_서적_10_구국론.js'), + che_서적_10_시경: async () => import('./che_서적_10_시경.js'), + che_서적_11_상군서: async () => import('./che_서적_11_상군서.js'), + che_서적_11_춘추전: async () => import('./che_서적_11_춘추전.js'), + che_서적_12_맹덕신서: async () => import('./che_서적_12_맹덕신서.js'), + che_서적_12_산해경: async () => import('./che_서적_12_산해경.js'), + che_서적_13_관자: async () => import('./che_서적_13_관자.js'), + che_서적_13_병법24편: async () => import('./che_서적_13_병법24편.js'), + che_서적_14_오자병법: async () => import('./che_서적_14_오자병법.js'), + che_서적_14_한비자: async () => import('./che_서적_14_한비자.js'), + che_서적_15_노자: async () => import('./che_서적_15_노자.js'), + che_서적_15_손자병법: async () => import('./che_서적_15_손자병법.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'), + che_훈련_단결도: async () => import('./che_훈련_단결도.js'), + che_훈련_철벽서: async () => import('./che_훈련_철벽서.js'), + che_훈련_청주: async () => import('./che_훈련_청주.js'), }; export const isItemKey = (value: string): value is ItemKey => ITEM_KEYS.includes(value as ItemKey); diff --git a/packages/logic/src/triggers/generalTriggers/che_도시치료.ts b/packages/logic/src/triggers/generalTriggers/che_도시치료.ts index e650c2d..553cb9c 100644 --- a/packages/logic/src/triggers/generalTriggers/che_도시치료.ts +++ b/packages/logic/src/triggers/generalTriggers/che_도시치료.ts @@ -27,7 +27,10 @@ export class CheUisulCityHealTrigger< > extends BaseGeneralTrigger { public readonly priority = TriggerPriority.Begin + 10; - public constructor(general: General) { + public constructor( + general: General, + private multiplier: number = 1 + ) { super(general); } @@ -52,7 +55,7 @@ export class CheUisulCityHealTrigger< return true; }); - const healed = candidates.filter(() => rng.nextBool(HEAL_PROBABILITY)); + const healed = candidates.filter(() => rng.nextBool(HEAL_PROBABILITY * this.multiplier)); for (const patient of healed) { patient.injury = 0; diff --git a/packages/logic/src/triggers/types.ts b/packages/logic/src/triggers/types.ts index c422608..e472c94 100644 --- a/packages/logic/src/triggers/types.ts +++ b/packages/logic/src/triggers/types.ts @@ -16,7 +16,8 @@ export type TriggerDomesticActionType = | '인구' | '기술' | '모병' - | '단련'; + | '단련' + | '조달'; export type TriggerDomesticVarType = 'cost' | 'score' | 'success' | 'fail' | 'train' | 'atmos' | 'rice' | 'probability'; @@ -26,7 +27,14 @@ export type TriggerStrategicVarType = 'delay' | 'globalDelay'; export type TriggerNationalIncomeType = 'gold' | 'rice' | 'pop'; -export type GeneralStatName = 'leadership' | 'strength' | 'intelligence' | 'experience' | 'dedication'; +export type GeneralStatName = + | 'leadership' + | 'strength' + | 'intelligence' + | 'experience' + | 'dedication' + | 'sabotageDefence' + | 'sabotageAttack'; export type WarStatName = | GeneralStatName