Add Fu Pass entry chapter
This commit is contained in:
@@ -31,6 +31,10 @@ import {
|
||||
nineteenthBattleMap,
|
||||
nineteenthBattleUnits,
|
||||
nineteenthBattleVictoryPages,
|
||||
twentyEighthBattleBonds,
|
||||
twentyEighthBattleMap,
|
||||
twentyEighthBattleUnits,
|
||||
twentyEighthBattleVictoryPages,
|
||||
tenthBattleBonds,
|
||||
tenthBattleMap,
|
||||
tenthBattleUnits,
|
||||
@@ -140,7 +144,8 @@ export type BattleScenarioId =
|
||||
| 'twenty-fourth-battle-guiyang-persuasion'
|
||||
| 'twenty-fifth-battle-wuling-mountain-road'
|
||||
| 'twenty-sixth-battle-changsha-veteran'
|
||||
| 'twenty-seventh-battle-yizhou-relief-road';
|
||||
| 'twenty-seventh-battle-yizhou-relief-road'
|
||||
| 'twenty-eighth-battle-fu-pass-entry';
|
||||
|
||||
export type BattleObjectiveKind = 'defeat-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
|
||||
|
||||
@@ -1701,6 +1706,69 @@ export const twentySeventhBattleScenario: BattleScenarioDefinition = {
|
||||
nextCampScene: 'CampScene'
|
||||
};
|
||||
|
||||
export const twentyEighthBattleScenario: BattleScenarioDefinition = {
|
||||
id: 'twenty-eighth-battle-fu-pass-entry',
|
||||
title: '부수관 진입전',
|
||||
victoryConditionLabel: '고패 퇴각',
|
||||
defeatConditionLabel: '유비 또는 제갈량 퇴각',
|
||||
openingObjectiveLines: [
|
||||
'익주 원군로를 연 유비군은 부수관의 첫 문 앞에 섰습니다. 고패는 좁은 협곡과 성루 궁병을 이용해 원군의 명분을 관문 앞에서 묶으려 합니다.',
|
||||
'이번 전투부터 방통이 출전 후보에 들어옵니다. 와룡과 봉추를 함께 세우면 계책은 강해지지만, 전열과 보급 선택이 더 날카로워집니다.',
|
||||
'유비와 제갈량을 지키며 고패를 물러나게 하면 익주 내부 인재 법정이 군영에 합류합니다.'
|
||||
],
|
||||
map: twentyEighthBattleMap,
|
||||
units: twentyEighthBattleUnits,
|
||||
bonds: twentyEighthBattleBonds,
|
||||
mapTextureKey: 'battle-map-twenty-eighth',
|
||||
leaderUnitId: 'fupass-leader-gao-pei',
|
||||
quickVictoryTurnLimit: 37,
|
||||
baseVictoryGold: 3980,
|
||||
objectives: [
|
||||
{
|
||||
id: 'leader',
|
||||
kind: 'defeat-leader',
|
||||
label: '고패 퇴각',
|
||||
rewardGold: 2520,
|
||||
unitId: 'fupass-leader-gao-pei'
|
||||
},
|
||||
{
|
||||
id: 'liu-bei',
|
||||
kind: 'keep-unit-alive',
|
||||
label: '유비 생존',
|
||||
rewardGold: 740,
|
||||
unitId: 'liu-bei'
|
||||
},
|
||||
{
|
||||
id: 'zhuge-liang',
|
||||
kind: 'keep-unit-alive',
|
||||
label: '제갈량 생존',
|
||||
rewardGold: 1020,
|
||||
unitId: 'zhuge-liang'
|
||||
},
|
||||
{
|
||||
id: 'fu-pass-village',
|
||||
kind: 'secure-terrain',
|
||||
label: '부수관 마을 안정',
|
||||
rewardGold: 1220,
|
||||
terrain: 'village'
|
||||
},
|
||||
{
|
||||
id: 'quick',
|
||||
kind: 'quick-victory',
|
||||
label: '37턴 이내 승리',
|
||||
rewardGold: 960,
|
||||
maxTurn: 37
|
||||
}
|
||||
],
|
||||
defeatConditions: [
|
||||
{ kind: 'unit-defeated', unitId: 'liu-bei' },
|
||||
{ kind: 'unit-defeated', unitId: 'zhuge-liang' }
|
||||
],
|
||||
itemRewards: ['콩 13', '상처약 9', '탁주 6', '부수관 보급표 +1', '법정 합류'],
|
||||
victoryPages: twentyEighthBattleVictoryPages,
|
||||
nextCampScene: 'CampScene'
|
||||
};
|
||||
|
||||
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
|
||||
|
||||
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
|
||||
@@ -1730,7 +1798,8 @@ export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition>
|
||||
'twenty-fourth-battle-guiyang-persuasion': twentyFourthBattleScenario,
|
||||
'twenty-fifth-battle-wuling-mountain-road': twentyFifthBattleScenario,
|
||||
'twenty-sixth-battle-changsha-veteran': twentySixthBattleScenario,
|
||||
'twenty-seventh-battle-yizhou-relief-road': twentySeventhBattleScenario
|
||||
'twenty-seventh-battle-yizhou-relief-road': twentySeventhBattleScenario,
|
||||
'twenty-eighth-battle-fu-pass-entry': twentyEighthBattleScenario
|
||||
};
|
||||
|
||||
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
seventeenthBattleScenario,
|
||||
tenthBattleScenario,
|
||||
thirteenthBattleScenario,
|
||||
twentyEighthBattleScenario,
|
||||
twentyFirstBattleScenario,
|
||||
twentySecondBattleScenario,
|
||||
twentyThirdBattleScenario,
|
||||
@@ -63,6 +64,8 @@ import {
|
||||
tenthBattleVictoryPages,
|
||||
thirteenthBattleIntroPages,
|
||||
thirteenthBattleVictoryPages,
|
||||
twentyEighthBattleIntroPages,
|
||||
twentyEighthBattleVictoryPages,
|
||||
twentyFirstBattleIntroPages,
|
||||
twentyFirstBattleVictoryPages,
|
||||
twentySecondBattleIntroPages,
|
||||
@@ -375,13 +378,24 @@ const sortieFlows: Record<string, SortieFlow> = {
|
||||
},
|
||||
[twentySeventhBattleScenario.id]: {
|
||||
afterBattleId: twentySeventhBattleScenario.id,
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '부수관 진입 준비',
|
||||
eyebrow: '다음 전장',
|
||||
title: twentyEighthBattleScenario.title,
|
||||
description:
|
||||
'익주 원군로가 열리고 방통이 합류했습니다. 이제 유비군은 촉의 깊은 산문과 부수관으로 들어가기 전, 와룡과 봉추의 계책을 함께 다듬어야 합니다.',
|
||||
rewardHint: '다음 장: 부수관 진입 준비 중',
|
||||
pages: twentySeventhBattleVictoryPages,
|
||||
unavailableNotice: '부수관 이후 익주 심부 장은 다음 작업에서 이어집니다. 군영에서 방통과 기존 무장들의 공명도를 올리고 다음 대장정의 출전 후보를 정비하십시오.'
|
||||
'익주 원군로가 열리고 방통이 합류했습니다. 이제 와룡과 봉추를 함께 편성할지 고민하며, 촉의 깊은 산문인 부수관으로 들어가야 합니다.',
|
||||
rewardHint: `예상 보상: ${twentyEighthBattleScenario.title} 개방 / 법정 합류`,
|
||||
nextBattleId: twentyEighthBattleScenario.id,
|
||||
campaignStep: 'twenty-eighth-battle',
|
||||
pages: [...twentySeventhBattleVictoryPages, ...twentyEighthBattleIntroPages]
|
||||
},
|
||||
[twentyEighthBattleScenario.id]: {
|
||||
afterBattleId: twentyEighthBattleScenario.id,
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '낙성 진입 준비',
|
||||
description:
|
||||
'부수관이 열리고 법정이 합류했습니다. 이제 유비군은 익주 안쪽의 마음과 길을 동시에 읽으며 낙성으로 이어지는 더 어려운 전장을 준비해야 합니다.',
|
||||
rewardHint: '다음 장: 낙성 진입 준비 중',
|
||||
pages: twentyEighthBattleVictoryPages,
|
||||
unavailableNotice: '낙성 이후 익주 심부 장은 다음 작업에서 이어집니다. 군영에서 법정과 방통의 공명도를 올리고 다음 관문을 준비하십시오.'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1766,6 +1766,68 @@ export const twentySeventhBattleVictoryPages: StoryPage[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const twentyEighthBattleIntroPages: StoryPage[] = [
|
||||
{
|
||||
id: 'twenty-eighth-fu-pass-shadow',
|
||||
bgm: 'story-dark',
|
||||
chapter: '부수관의 그림자',
|
||||
background: 'story-three-heroes',
|
||||
speaker: '방통',
|
||||
text: '익주 원군로는 열렸으나 부수관은 아직 닫혀 있습니다. 고패가 관문 병력을 모아 길을 끊으면, 우리 명분은 산문 앞에서 멈출 것입니다.'
|
||||
},
|
||||
{
|
||||
id: 'twenty-eighth-fa-zheng-message',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '익주 내부의 손',
|
||||
background: 'story-liu-bei',
|
||||
speaker: '제갈량',
|
||||
text: '익주 안쪽에서 법정이라는 인물이 은밀히 소식을 보냈습니다. 그는 유장의 답답한 정치를 걱정하며, 부수관을 넘을 길목을 알려 주겠다고 합니다.'
|
||||
},
|
||||
{
|
||||
id: 'twenty-eighth-roster-pressure',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '와룡과 봉추의 첫 편성',
|
||||
background: 'story-militia',
|
||||
speaker: '마량',
|
||||
text: '이번 전투부터 방통도 출전 후보가 됩니다. 책사 둘을 모두 데려가면 관문 계책은 강해지지만, 전열과 보급 중 하나가 얇아질 수 있습니다.'
|
||||
},
|
||||
{
|
||||
id: 'twenty-eighth-fu-pass-sortie',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '부수관 진입전',
|
||||
background: 'story-sortie',
|
||||
speaker: '유비',
|
||||
portrait: 'liuBei',
|
||||
text: '관문을 부수는 일보다 중요한 것은, 그 너머의 백성이 우리를 어떻게 기억하느냐요. 방통의 기책과 제갈량의 큰 판을 살려 부수관의 길을 열겠소.'
|
||||
}
|
||||
];
|
||||
|
||||
export const twentyEighthBattleVictoryPages: StoryPage[] = [
|
||||
{
|
||||
id: 'twenty-eighth-victory-pass-open',
|
||||
bgm: 'militia-theme',
|
||||
chapter: '부수관이 열리다',
|
||||
background: 'story-sortie',
|
||||
text: '고패의 관문 병력이 물러나고 부수관의 첫 문이 열렸습니다. 유비군은 관문 창고를 봉인하고 마을의 곡식을 지켜, 익주 내부의 의심을 조금 누그러뜨렸습니다.'
|
||||
},
|
||||
{
|
||||
id: 'twenty-eighth-fa-zheng-joins',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '법정의 합류',
|
||||
background: 'story-liu-bei',
|
||||
speaker: '법정',
|
||||
text: '익주는 험한 땅이지만, 더 험한 것은 닫힌 마음입니다. 주공께서 그 마음을 함부로 베지 않으신다면, 이 법정이 안쪽 길을 밝히겠습니다.'
|
||||
},
|
||||
{
|
||||
id: 'twenty-eighth-next-luo-castle',
|
||||
bgm: 'story-dark',
|
||||
chapter: '낙성으로 이어지는 길',
|
||||
background: 'story-three-heroes',
|
||||
speaker: '방통',
|
||||
text: '부수관은 문에 불과합니다. 낙성으로 이어지는 길에는 더 깊은 매복과 더 복잡한 마음이 기다립니다. 이제 법정의 내부 정보까지 함께 써야 합니다.'
|
||||
}
|
||||
];
|
||||
|
||||
export const firstBattleMap: BattleMap = {
|
||||
width: 20,
|
||||
height: 18,
|
||||
@@ -2073,6 +2135,12 @@ export const twentySeventhBattleMap: BattleMap = {
|
||||
terrain: createTwentySeventhBattleTerrain()
|
||||
};
|
||||
|
||||
export const twentyEighthBattleMap: BattleMap = {
|
||||
width: 56,
|
||||
height: 38,
|
||||
terrain: createTwentyEighthBattleTerrain()
|
||||
};
|
||||
|
||||
export const firstBattleUnits: UnitData[] = [
|
||||
{
|
||||
id: 'liu-bei',
|
||||
@@ -4170,6 +4238,30 @@ export const yizhouRecruitUnits: UnitData[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const fuPassRecruitUnits: UnitData[] = [
|
||||
{
|
||||
id: 'fa-zheng',
|
||||
name: '법정',
|
||||
faction: 'ally',
|
||||
className: '익주 모사',
|
||||
classKey: 'strategist',
|
||||
level: 17,
|
||||
exp: 0,
|
||||
hp: 38,
|
||||
maxHp: 38,
|
||||
attack: 9,
|
||||
move: 4,
|
||||
stats: { might: 42, intelligence: 94, leadership: 84, agility: 70, luck: 80 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'white-feather-fan', level: 2, exp: 18 },
|
||||
armor: { itemId: 'cloth-armor', level: 2, exp: 16 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 8,
|
||||
y: 25
|
||||
}
|
||||
];
|
||||
|
||||
const eighthBattleAllyPositions: Record<string, { x: number; y: number }> = {
|
||||
'liu-bei': { x: 2, y: 17 },
|
||||
'guan-yu': { x: 3, y: 17 },
|
||||
@@ -11105,6 +11197,458 @@ export const twentySeventhBattleUnits: UnitData[] = [
|
||||
}
|
||||
];
|
||||
|
||||
const twentyEighthBattleAllyPositions: Record<string, { x: number; y: number }> = {
|
||||
'liu-bei': { x: 4, y: 32 },
|
||||
'guan-yu': { x: 6, y: 31 },
|
||||
'zhang-fei': { x: 5, y: 34 },
|
||||
'jian-yong': { x: 3, y: 35 },
|
||||
'mi-zhu': { x: 4, y: 36 },
|
||||
'sun-qian': { x: 7, y: 35 },
|
||||
'zhao-yun': { x: 8, y: 32 },
|
||||
'zhuge-liang': { x: 5, y: 32 },
|
||||
'ma-liang': { x: 8, y: 36 },
|
||||
'yi-ji': { x: 9, y: 34 },
|
||||
'gong-zhi': { x: 10, y: 36 },
|
||||
'huang-zhong': { x: 7, y: 33 },
|
||||
'wei-yan': { x: 10, y: 31 },
|
||||
'pang-tong': { x: 9, y: 33 }
|
||||
};
|
||||
|
||||
export const twentyEighthBattleUnits: UnitData[] = [
|
||||
...[
|
||||
...firstBattleUnits.filter((unit) => unit.faction === 'ally'),
|
||||
...xuzhouRecruitUnits,
|
||||
...caoBreakRecruitUnits,
|
||||
...liuBiaoRecruitUnits,
|
||||
...zhugeRecruitUnits,
|
||||
...jingzhouRecruitUnits,
|
||||
...guiyangRecruitUnits,
|
||||
...wulingRecruitUnits,
|
||||
...changshaRecruitUnits,
|
||||
...yizhouRecruitUnits
|
||||
].map((unit) => placeScenarioUnit(unit, twentyEighthBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
|
||||
{
|
||||
id: 'fupass-scout-a',
|
||||
name: '부수관 척후',
|
||||
faction: 'enemy',
|
||||
className: '관문 척후',
|
||||
classKey: 'bandit',
|
||||
level: 44,
|
||||
exp: 68,
|
||||
hp: 112,
|
||||
maxHp: 112,
|
||||
attack: 43,
|
||||
move: 4,
|
||||
stats: { might: 134, intelligence: 96, leadership: 110, agility: 126, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 5, exp: 6 },
|
||||
armor: { itemId: 'rebel-vest', level: 4, exp: 40 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 16,
|
||||
y: 32
|
||||
},
|
||||
{
|
||||
id: 'fupass-scout-b',
|
||||
name: '부수관 척후',
|
||||
faction: 'enemy',
|
||||
className: '서문 척후',
|
||||
classKey: 'bandit',
|
||||
level: 44,
|
||||
exp: 68,
|
||||
hp: 112,
|
||||
maxHp: 112,
|
||||
attack: 43,
|
||||
move: 4,
|
||||
stats: { might: 134, intelligence: 96, leadership: 110, agility: 126, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 5, exp: 6 },
|
||||
armor: { itemId: 'rebel-vest', level: 4, exp: 40 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 21,
|
||||
y: 30
|
||||
},
|
||||
{
|
||||
id: 'fupass-infantry-a',
|
||||
name: '부수관 보병',
|
||||
faction: 'enemy',
|
||||
className: '산문 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 45,
|
||||
exp: 70,
|
||||
hp: 154,
|
||||
maxHp: 154,
|
||||
attack: 48,
|
||||
move: 3,
|
||||
stats: { might: 150, intelligence: 96, leadership: 128, agility: 104, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 18 },
|
||||
armor: { itemId: 'lamellar-armor', level: 5, exp: 8 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 25,
|
||||
y: 29
|
||||
},
|
||||
{
|
||||
id: 'fupass-infantry-b',
|
||||
name: '부수관 보병',
|
||||
faction: 'enemy',
|
||||
className: '협곡 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 45,
|
||||
exp: 70,
|
||||
hp: 154,
|
||||
maxHp: 154,
|
||||
attack: 48,
|
||||
move: 3,
|
||||
stats: { might: 150, intelligence: 96, leadership: 128, agility: 104, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 18 },
|
||||
armor: { itemId: 'lamellar-armor', level: 5, exp: 8 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 30,
|
||||
y: 26
|
||||
},
|
||||
{
|
||||
id: 'fupass-infantry-c',
|
||||
name: '부수관 보병',
|
||||
faction: 'enemy',
|
||||
className: '관문 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 162,
|
||||
maxHp: 162,
|
||||
attack: 50,
|
||||
move: 3,
|
||||
stats: { might: 154, intelligence: 98, leadership: 132, agility: 106, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 26 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 14 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 38,
|
||||
y: 23
|
||||
},
|
||||
{
|
||||
id: 'fupass-infantry-d',
|
||||
name: '부수관 보병',
|
||||
faction: 'enemy',
|
||||
className: '성문 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 162,
|
||||
maxHp: 162,
|
||||
attack: 50,
|
||||
move: 3,
|
||||
stats: { might: 154, intelligence: 98, leadership: 132, agility: 106, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 26 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 14 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 44,
|
||||
y: 19
|
||||
},
|
||||
{
|
||||
id: 'fupass-archer-a',
|
||||
name: '부수관 궁병',
|
||||
faction: 'enemy',
|
||||
className: '산루 궁병',
|
||||
classKey: 'archer',
|
||||
level: 45,
|
||||
exp: 70,
|
||||
hp: 112,
|
||||
maxHp: 112,
|
||||
attack: 45,
|
||||
move: 3,
|
||||
stats: { might: 108, intelligence: 108, leadership: 114, agility: 122, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 5, exp: 14 },
|
||||
armor: { itemId: 'cloth-armor', level: 5, exp: 4 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 30,
|
||||
y: 22
|
||||
},
|
||||
{
|
||||
id: 'fupass-archer-b',
|
||||
name: '부수관 궁병',
|
||||
faction: 'enemy',
|
||||
className: '관문 궁병',
|
||||
classKey: 'archer',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 116,
|
||||
maxHp: 116,
|
||||
attack: 46,
|
||||
move: 3,
|
||||
stats: { might: 110, intelligence: 110, leadership: 116, agility: 124, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 5, exp: 22 },
|
||||
armor: { itemId: 'cloth-armor', level: 5, exp: 10 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 42,
|
||||
y: 16
|
||||
},
|
||||
{
|
||||
id: 'fupass-archer-c',
|
||||
name: '부수관 궁병',
|
||||
faction: 'enemy',
|
||||
className: '성루 궁병',
|
||||
classKey: 'archer',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 116,
|
||||
maxHp: 116,
|
||||
attack: 46,
|
||||
move: 3,
|
||||
stats: { might: 110, intelligence: 110, leadership: 116, agility: 124, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 5, exp: 22 },
|
||||
armor: { itemId: 'cloth-armor', level: 5, exp: 10 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 50,
|
||||
y: 20
|
||||
},
|
||||
{
|
||||
id: 'fupass-cavalry-a',
|
||||
name: '부수관 기병',
|
||||
faction: 'enemy',
|
||||
className: '고개 기병',
|
||||
classKey: 'cavalry',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 162,
|
||||
maxHp: 162,
|
||||
attack: 51,
|
||||
move: 5,
|
||||
stats: { might: 154, intelligence: 98, leadership: 130, agility: 126, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 28 },
|
||||
armor: { itemId: 'lamellar-armor', level: 5, exp: 16 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 23,
|
||||
y: 34
|
||||
},
|
||||
{
|
||||
id: 'fupass-cavalry-b',
|
||||
name: '부수관 기병',
|
||||
faction: 'enemy',
|
||||
className: '관문 기병',
|
||||
classKey: 'cavalry',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 162,
|
||||
maxHp: 162,
|
||||
attack: 51,
|
||||
move: 5,
|
||||
stats: { might: 154, intelligence: 98, leadership: 130, agility: 126, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 28 },
|
||||
armor: { itemId: 'lamellar-armor', level: 5, exp: 16 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 40,
|
||||
y: 29
|
||||
},
|
||||
{
|
||||
id: 'fupass-cavalry-c',
|
||||
name: '부수관 기병',
|
||||
faction: 'enemy',
|
||||
className: '성문 기병',
|
||||
classKey: 'cavalry',
|
||||
level: 47,
|
||||
exp: 74,
|
||||
hp: 170,
|
||||
maxHp: 170,
|
||||
attack: 53,
|
||||
move: 5,
|
||||
stats: { might: 158, intelligence: 100, leadership: 134, agility: 128, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 36 },
|
||||
armor: { itemId: 'lamellar-armor', level: 5, exp: 24 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 49,
|
||||
y: 27
|
||||
},
|
||||
{
|
||||
id: 'fupass-guard-a',
|
||||
name: '고패 친위대',
|
||||
faction: 'enemy',
|
||||
className: '관문 친위대',
|
||||
classKey: 'yellowTurban',
|
||||
level: 47,
|
||||
exp: 74,
|
||||
hp: 174,
|
||||
maxHp: 174,
|
||||
attack: 53,
|
||||
move: 3,
|
||||
stats: { might: 160, intelligence: 100, leadership: 138, agility: 108, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 40 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 26 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 47,
|
||||
y: 17
|
||||
},
|
||||
{
|
||||
id: 'fupass-guard-b',
|
||||
name: '고패 친위대',
|
||||
faction: 'enemy',
|
||||
className: '성문 친위대',
|
||||
classKey: 'yellowTurban',
|
||||
level: 47,
|
||||
exp: 74,
|
||||
hp: 174,
|
||||
maxHp: 174,
|
||||
attack: 53,
|
||||
move: 3,
|
||||
stats: { might: 160, intelligence: 100, leadership: 138, agility: 108, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 5, exp: 40 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 26 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 51,
|
||||
y: 19
|
||||
},
|
||||
{
|
||||
id: 'fupass-strategist-a',
|
||||
name: '부수관 책사',
|
||||
faction: 'enemy',
|
||||
className: '관문 책사',
|
||||
classKey: 'archer',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 116,
|
||||
maxHp: 116,
|
||||
attack: 46,
|
||||
move: 3,
|
||||
stats: { might: 94, intelligence: 124, leadership: 116, agility: 100, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 5, exp: 24 },
|
||||
armor: { itemId: 'cloth-armor', level: 5, exp: 12 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 43,
|
||||
y: 14
|
||||
},
|
||||
{
|
||||
id: 'fupass-strategist-b',
|
||||
name: '부수관 책사',
|
||||
faction: 'enemy',
|
||||
className: '성문 책사',
|
||||
classKey: 'archer',
|
||||
level: 46,
|
||||
exp: 72,
|
||||
hp: 116,
|
||||
maxHp: 116,
|
||||
attack: 46,
|
||||
move: 3,
|
||||
stats: { might: 94, intelligence: 124, leadership: 116, agility: 100, luck: 88 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 5, exp: 24 },
|
||||
armor: { itemId: 'cloth-armor', level: 5, exp: 12 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 51,
|
||||
y: 23
|
||||
},
|
||||
{
|
||||
id: 'fupass-ambusher-a',
|
||||
name: '산길 복병',
|
||||
faction: 'enemy',
|
||||
className: '서쪽 복병',
|
||||
classKey: 'bandit',
|
||||
level: 45,
|
||||
exp: 70,
|
||||
hp: 120,
|
||||
maxHp: 120,
|
||||
attack: 45,
|
||||
move: 4,
|
||||
stats: { might: 140, intelligence: 98, leadership: 112, agility: 128, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 5, exp: 18 },
|
||||
armor: { itemId: 'rebel-vest', level: 5, exp: 4 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 31,
|
||||
y: 34
|
||||
},
|
||||
{
|
||||
id: 'fupass-ambusher-b',
|
||||
name: '산길 복병',
|
||||
faction: 'enemy',
|
||||
className: '북쪽 복병',
|
||||
classKey: 'bandit',
|
||||
level: 45,
|
||||
exp: 70,
|
||||
hp: 120,
|
||||
maxHp: 120,
|
||||
attack: 45,
|
||||
move: 4,
|
||||
stats: { might: 140, intelligence: 98, leadership: 112, agility: 128, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 5, exp: 18 },
|
||||
armor: { itemId: 'rebel-vest', level: 5, exp: 4 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 35,
|
||||
y: 8
|
||||
},
|
||||
{
|
||||
id: 'fupass-ambusher-c',
|
||||
name: '산길 복병',
|
||||
faction: 'enemy',
|
||||
className: '남쪽 복병',
|
||||
classKey: 'bandit',
|
||||
level: 45,
|
||||
exp: 70,
|
||||
hp: 120,
|
||||
maxHp: 120,
|
||||
attack: 45,
|
||||
move: 4,
|
||||
stats: { might: 140, intelligence: 98, leadership: 112, agility: 128, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 5, exp: 18 },
|
||||
armor: { itemId: 'rebel-vest', level: 5, exp: 4 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 45,
|
||||
y: 31
|
||||
},
|
||||
{
|
||||
id: 'fupass-leader-gao-pei',
|
||||
name: '고패',
|
||||
faction: 'enemy',
|
||||
className: '부수관 수장',
|
||||
classKey: 'rebelLeader',
|
||||
level: 48,
|
||||
exp: 78,
|
||||
hp: 222,
|
||||
maxHp: 222,
|
||||
attack: 55,
|
||||
move: 4,
|
||||
stats: { might: 162, intelligence: 116, leadership: 144, agility: 110, luck: 90 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'leader-axe', level: 5, exp: 34 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 30 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 52,
|
||||
y: 18
|
||||
}
|
||||
];
|
||||
|
||||
export const firstBattleBonds: BattleBond[] = [
|
||||
{
|
||||
id: 'liu-bei__guan-yu',
|
||||
@@ -11375,6 +11919,33 @@ export const yizhouRecruitBonds: BattleBond[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const fuPassRecruitBonds: BattleBond[] = [
|
||||
{
|
||||
id: 'liu-bei__fa-zheng',
|
||||
unitIds: ['liu-bei', 'fa-zheng'],
|
||||
title: '익주 내부의 길',
|
||||
level: 34,
|
||||
exp: 0,
|
||||
description: '유비의 명분과 법정의 내부 정보가 만나, 익주의 닫힌 마음과 관문을 함께 열어 갑니다.'
|
||||
},
|
||||
{
|
||||
id: 'pang-tong__fa-zheng',
|
||||
unitIds: ['pang-tong', 'fa-zheng'],
|
||||
title: '봉추와 내부책',
|
||||
level: 32,
|
||||
exp: 0,
|
||||
description: '방통의 과감한 기책과 법정의 익주 사정이 맞물려, 적이 숨긴 길목을 먼저 흔듭니다.'
|
||||
},
|
||||
{
|
||||
id: 'zhuge-liang__fa-zheng',
|
||||
unitIds: ['zhuge-liang', 'fa-zheng'],
|
||||
title: '큰 판과 속내',
|
||||
level: 30,
|
||||
exp: 0,
|
||||
description: '제갈량의 큰 전략과 법정의 내부 정세 판단이 더해져, 익주 공략의 무리한 피를 줄입니다.'
|
||||
}
|
||||
];
|
||||
|
||||
export const secondBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||
export const thirdBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||
export const fourthBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||
@@ -11407,6 +11978,7 @@ export const twentyFourthBattleBonds: BattleBond[] = [...twentyThirdBattleBonds,
|
||||
export const twentyFifthBattleBonds: BattleBond[] = [...twentyFourthBattleBonds, ...guiyangRecruitBonds].map(cloneBattleBondForScenario);
|
||||
export const twentySixthBattleBonds: BattleBond[] = [...twentyFifthBattleBonds, ...wulingRecruitBonds].map(cloneBattleBondForScenario);
|
||||
export const twentySeventhBattleBonds: BattleBond[] = [...twentySixthBattleBonds, ...changshaRecruitBonds].map(cloneBattleBondForScenario);
|
||||
export const twentyEighthBattleBonds: BattleBond[] = [...twentySeventhBattleBonds, ...yizhouRecruitBonds].map(cloneBattleBondForScenario);
|
||||
|
||||
function createEighthBattleTerrain(): TerrainType[][] {
|
||||
return Array.from({ length: 22 }, (_, y) =>
|
||||
@@ -12428,6 +13000,62 @@ function createTwentySeventhBattleTerrain(): TerrainType[][] {
|
||||
);
|
||||
}
|
||||
|
||||
function createTwentyEighthBattleTerrain(): TerrainType[][] {
|
||||
return Array.from({ length: 38 }, (_, y) =>
|
||||
Array.from({ length: 56 }, (_, x): TerrainType => {
|
||||
if (x <= 4 && y >= 31) {
|
||||
return 'camp';
|
||||
}
|
||||
if ((x >= 46 && x <= 54 && y >= 13 && y <= 22) || (x >= 42 && x <= 48 && y >= 10 && y <= 15)) {
|
||||
return 'fort';
|
||||
}
|
||||
if ((x >= 17 && x <= 20 && y >= 28 && y <= 30) || (x >= 32 && x <= 34 && y >= 24 && y <= 26) || (x >= 39 && x <= 41 && y >= 18 && y <= 20)) {
|
||||
return 'village';
|
||||
}
|
||||
if (
|
||||
(y >= 33 && x >= 4 && x <= 15) ||
|
||||
(x >= 14 && x <= 25 && y >= 29 && y <= 33) ||
|
||||
(x >= 24 && x <= 34 && y >= 25 && y <= 29) ||
|
||||
(x >= 33 && x <= 42 && y >= 20 && y <= 25) ||
|
||||
(x >= 41 && x <= 50 && y >= 16 && y <= 20) ||
|
||||
(x >= 49 && x <= 53 && y >= 17 && y <= 19)
|
||||
) {
|
||||
return 'road';
|
||||
}
|
||||
if ((x === 12 || x === 13) && y >= 0 && y <= 27) {
|
||||
return 'river';
|
||||
}
|
||||
if ((x === 30 || x === 31) && y >= 2 && y <= 23) {
|
||||
return 'river';
|
||||
}
|
||||
if ((x === 38 || x === 39) && y >= 28 && y <= 37) {
|
||||
return 'river';
|
||||
}
|
||||
if (
|
||||
(x >= 4 && x <= 17 && y >= 8 && y <= 22) ||
|
||||
(x >= 18 && x <= 29 && y >= 11 && y <= 23) ||
|
||||
(x >= 31 && x <= 44 && y >= 28 && y <= 37) ||
|
||||
(x >= 43 && x <= 55 && y >= 24 && y <= 36)
|
||||
) {
|
||||
return 'forest';
|
||||
}
|
||||
if (
|
||||
(x >= 0 && x <= 10 && y <= 12) ||
|
||||
(x >= 19 && x <= 29 && y <= 10) ||
|
||||
(x >= 31 && x <= 45 && y >= 3 && y <= 13) ||
|
||||
(x >= 48 && x <= 55 && y <= 12) ||
|
||||
(x >= 23 && x <= 33 && y >= 31 && y <= 37)
|
||||
) {
|
||||
return 'hill';
|
||||
}
|
||||
if ((x <= 2 && y <= 30) || (x >= 54 && y >= 22) || (x >= 44 && x <= 46 && y <= 9)) {
|
||||
return 'cliff';
|
||||
}
|
||||
return 'plain';
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
|
||||
return {
|
||||
...cloneUnitForScenario(unit),
|
||||
|
||||
@@ -35,6 +35,7 @@ const unitTexture: Record<string, string> = {
|
||||
'huang-zhong': 'unit-rebel-archer',
|
||||
'wei-yan': 'unit-guan-yu',
|
||||
'pang-tong': 'unit-liu-bei',
|
||||
'fa-zheng': 'unit-liu-bei',
|
||||
'rebel-a': 'unit-rebel',
|
||||
'rebel-b': 'unit-rebel',
|
||||
'rebel-c': 'unit-rebel-archer',
|
||||
@@ -336,7 +337,27 @@ const unitTexture: Record<string, string> = {
|
||||
'yizhou-strategist-b': 'unit-rebel-archer',
|
||||
'yizhou-ambusher-a': 'unit-rebel',
|
||||
'yizhou-ambusher-b': 'unit-rebel',
|
||||
'yizhou-leader-yang-huai': 'unit-rebel-leader'
|
||||
'yizhou-leader-yang-huai': 'unit-rebel-leader',
|
||||
'fupass-scout-a': 'unit-rebel',
|
||||
'fupass-scout-b': 'unit-rebel',
|
||||
'fupass-infantry-a': 'unit-rebel',
|
||||
'fupass-infantry-b': 'unit-rebel',
|
||||
'fupass-infantry-c': 'unit-rebel',
|
||||
'fupass-infantry-d': 'unit-rebel',
|
||||
'fupass-archer-a': 'unit-rebel-archer',
|
||||
'fupass-archer-b': 'unit-rebel-archer',
|
||||
'fupass-archer-c': 'unit-rebel-archer',
|
||||
'fupass-cavalry-a': 'unit-rebel-cavalry',
|
||||
'fupass-cavalry-b': 'unit-rebel-cavalry',
|
||||
'fupass-cavalry-c': 'unit-rebel-cavalry',
|
||||
'fupass-guard-a': 'unit-rebel',
|
||||
'fupass-guard-b': 'unit-rebel',
|
||||
'fupass-strategist-a': 'unit-rebel-archer',
|
||||
'fupass-strategist-b': 'unit-rebel-archer',
|
||||
'fupass-ambusher-a': 'unit-rebel',
|
||||
'fupass-ambusher-b': 'unit-rebel',
|
||||
'fupass-ambusher-c': 'unit-rebel',
|
||||
'fupass-leader-gao-pei': 'unit-rebel-leader'
|
||||
};
|
||||
|
||||
const unitTextureByClass: Partial<Record<UnitClassKey, string>> = {
|
||||
@@ -763,7 +784,8 @@ const unitStrategyIds: Record<string, string[]> = {
|
||||
'gong-zhi': ['encourage'],
|
||||
'huang-zhong': ['encourage'],
|
||||
'wei-yan': ['roar'],
|
||||
'pang-tong': ['aid', 'encourage', 'fireTactic']
|
||||
'pang-tong': ['aid', 'encourage', 'fireTactic'],
|
||||
'fa-zheng': ['aid', 'encourage', 'fireTactic']
|
||||
};
|
||||
|
||||
const initialItemStocks: Record<string, Record<string, number>> = {
|
||||
@@ -780,7 +802,8 @@ const initialItemStocks: Record<string, Record<string, number>> = {
|
||||
'gong-zhi': { bean: 2 },
|
||||
'huang-zhong': { bean: 1, wine: 1 },
|
||||
'wei-yan': { bean: 2 },
|
||||
'pang-tong': { bean: 1, salve: 1, wine: 1 }
|
||||
'pang-tong': { bean: 1, salve: 1, wine: 1 },
|
||||
'fa-zheng': { bean: 1, salve: 1, wine: 1 }
|
||||
};
|
||||
|
||||
const attackRangeByClass: Partial<Record<UnitClassKey, number>> = {
|
||||
@@ -1134,7 +1157,27 @@ const enemyAiByUnitId: Record<string, EnemyAiBehavior> = {
|
||||
'yizhou-strategist-b': 'hold',
|
||||
'yizhou-ambusher-a': 'aggressive',
|
||||
'yizhou-ambusher-b': 'aggressive',
|
||||
'yizhou-leader-yang-huai': 'guard'
|
||||
'yizhou-leader-yang-huai': 'guard',
|
||||
'fupass-scout-a': 'aggressive',
|
||||
'fupass-scout-b': 'aggressive',
|
||||
'fupass-infantry-a': 'guard',
|
||||
'fupass-infantry-b': 'guard',
|
||||
'fupass-infantry-c': 'guard',
|
||||
'fupass-infantry-d': 'guard',
|
||||
'fupass-archer-a': 'hold',
|
||||
'fupass-archer-b': 'hold',
|
||||
'fupass-archer-c': 'hold',
|
||||
'fupass-cavalry-a': 'aggressive',
|
||||
'fupass-cavalry-b': 'aggressive',
|
||||
'fupass-cavalry-c': 'aggressive',
|
||||
'fupass-guard-a': 'guard',
|
||||
'fupass-guard-b': 'guard',
|
||||
'fupass-strategist-a': 'hold',
|
||||
'fupass-strategist-b': 'hold',
|
||||
'fupass-ambusher-a': 'aggressive',
|
||||
'fupass-ambusher-b': 'aggressive',
|
||||
'fupass-ambusher-c': 'aggressive',
|
||||
'fupass-leader-gao-pei': 'guard'
|
||||
};
|
||||
|
||||
const defaultEnemyAiByClass: Partial<Record<UnitClassKey, EnemyAiBehavior>> = {
|
||||
|
||||
@@ -17,6 +17,7 @@ import seventeenthBattleMapUrl from '../../assets/images/battle/seventeenth-batt
|
||||
import tenthBattleMapUrl from '../../assets/images/battle/tenth-battle-map.svg';
|
||||
import thirteenthBattleMapUrl from '../../assets/images/battle/thirteenth-battle-map.svg';
|
||||
import thirdBattleMapUrl from '../../assets/images/battle/third-battle-map.svg';
|
||||
import twentyEighthBattleMapUrl from '../../assets/images/battle/twenty-eighth-battle-map.svg';
|
||||
import twentyFirstBattleMapUrl from '../../assets/images/battle/twenty-first-battle-map.svg';
|
||||
import twentySecondBattleMapUrl from '../../assets/images/battle/twenty-second-battle-map.svg';
|
||||
import twentyThirdBattleMapUrl from '../../assets/images/battle/twenty-third-battle-map.svg';
|
||||
@@ -112,6 +113,7 @@ export class BootScene extends Phaser.Scene {
|
||||
this.load.image('battle-map-twenty-fifth', twentyFifthBattleMapUrl);
|
||||
this.load.image('battle-map-twenty-sixth', twentySixthBattleMapUrl);
|
||||
this.load.image('battle-map-twenty-seventh', twentySeventhBattleMapUrl);
|
||||
this.load.image('battle-map-twenty-eighth', twentyEighthBattleMapUrl);
|
||||
this.load.image('portrait-liu-bei', liuBeiPortraitUrl);
|
||||
this.load.image('portrait-guan-yu', guanYuPortraitUrl);
|
||||
this.load.image('portrait-zhang-fei', zhangFeiPortraitUrl);
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
changshaRecruitUnits,
|
||||
firstBattleBonds,
|
||||
firstBattleUnits,
|
||||
fuPassRecruitBonds,
|
||||
fuPassRecruitUnits,
|
||||
guiyangRecruitBonds,
|
||||
guiyangRecruitUnits,
|
||||
jingzhouRecruitBonds,
|
||||
@@ -310,9 +312,10 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
|
||||
'twenty-fourth-battle-guiyang-persuasion',
|
||||
'twenty-fifth-battle-wuling-mountain-road',
|
||||
'twenty-sixth-battle-changsha-veteran',
|
||||
'twenty-seventh-battle-yizhou-relief-road'
|
||||
'twenty-seventh-battle-yizhou-relief-road',
|
||||
'twenty-eighth-battle-fu-pass-entry'
|
||||
],
|
||||
nextHints: ['형주 방위', '익주 진입', '방통 합류']
|
||||
nextHints: ['형주 방위', '익주 진입', '방통·법정 합류']
|
||||
},
|
||||
{
|
||||
id: 'shu-han',
|
||||
@@ -351,7 +354,8 @@ const campBattleIds = {
|
||||
twentyFourth: 'twenty-fourth-battle-guiyang-persuasion',
|
||||
twentyFifth: 'twenty-fifth-battle-wuling-mountain-road',
|
||||
twentySixth: 'twenty-sixth-battle-changsha-veteran',
|
||||
twentySeventh: 'twenty-seventh-battle-yizhou-relief-road'
|
||||
twentySeventh: 'twenty-seventh-battle-yizhou-relief-road',
|
||||
twentyEighth: 'twenty-eighth-battle-fu-pass-entry'
|
||||
} as const;
|
||||
|
||||
const requiredSortieUnitIds = new Set(['liu-bei']);
|
||||
@@ -650,6 +654,18 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
|
||||
{ unitId: 'mi-zhu', reason: '큰 로스터 전투에서 회복 도구와 보급 안정성이 빛납니다.' }
|
||||
],
|
||||
note: '익주 원군로는 열세 명 중 여섯 명만 고르는 전장입니다. 황충·위연을 시험할지, 기존 책사와 보급을 두껍게 둘지 직접 선택하십시오.'
|
||||
},
|
||||
'twenty-eighth-battle-fu-pass-entry': {
|
||||
maxUnits: 6,
|
||||
recommended: [
|
||||
{ unitId: 'liu-bei', reason: '부수관 진입 명분과 패배 조건의 중심입니다.' },
|
||||
{ unitId: 'pang-tong', reason: '부수관 관문을 흔드는 기책 담당이며 이번 전투의 새 선택 축입니다.' },
|
||||
{ unitId: 'zhuge-liang', reason: '관문 돌파와 보급선을 함께 보는 큰 판의 핵심입니다.' },
|
||||
{ unitId: 'wei-yan', reason: '좁은 관문 전열을 빠르게 흔들 돌파 역할입니다.' },
|
||||
{ unitId: 'huang-zhong', reason: '성루 궁병과 산비탈 적을 안정적으로 견제합니다.' },
|
||||
{ unitId: 'zhao-yun', reason: '협곡 기병과 복병을 빠르게 끊는 기동 핵심입니다.' }
|
||||
],
|
||||
note: '부수관 진입전은 열네 명 중 여섯 명만 고르는 전장입니다. 방통을 데려가면 계책은 강해지지만, 보급이나 전열 후보를 한 명 줄여야 합니다.'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2921,6 +2937,87 @@ const campDialogues: CampDialogue[] = [
|
||||
rewardExp: 9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'liu-fa-after-fupass',
|
||||
title: '익주 내부의 길',
|
||||
availableAfterBattleIds: [campBattleIds.twentyEighth],
|
||||
unitIds: ['liu-bei', 'fa-zheng'],
|
||||
bondId: 'liu-bei__fa-zheng',
|
||||
rewardExp: 30,
|
||||
lines: [
|
||||
'법정: 익주 사람들은 강한 군보다 약속을 지키는 군을 더 오래 기억합니다.',
|
||||
'유비: 그래서 관문 창고를 봉했소. 길을 열어도 백성의 밥그릇을 건드리면 마음은 닫히오.',
|
||||
'법정: 그렇다면 저는 그 마음이 어디서 열리고 닫히는지 알려 드리겠습니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'ask-fa-zheng-people',
|
||||
label: '익주 민심을 묻는다',
|
||||
response: '법정은 관문보다 먼저 설득해야 할 마을과 사람의 이름을 적었다.',
|
||||
rewardExp: 12
|
||||
},
|
||||
{
|
||||
id: 'promise-yizhou-discipline',
|
||||
label: '군율을 약속한다',
|
||||
response: '유비가 군율을 다시 못박자, 법정은 안쪽 길을 밝히겠다고 답했다.',
|
||||
rewardExp: 11
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'pang-fa-after-fupass',
|
||||
title: '봉추와 내부책',
|
||||
availableAfterBattleIds: [campBattleIds.twentyEighth],
|
||||
unitIds: ['pang-tong', 'fa-zheng'],
|
||||
bondId: 'pang-tong__fa-zheng',
|
||||
rewardExp: 28,
|
||||
lines: [
|
||||
'방통: 안쪽 사정을 아는 사람이 있으니, 이제 문을 두드릴지 흔들지 결정하기 쉬워졌군요.',
|
||||
'법정: 흔들어야 할 문도 있고, 조용히 열어야 할 문도 있습니다. 순서를 틀리면 익주가 피로 답할 것입니다.',
|
||||
'방통: 그러면 그 순서를 당신이, 그 틈을 제가 보겠습니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'mark-hidden-gates',
|
||||
label: '숨은 문을 표시한다',
|
||||
response: '법정은 익주 내부의 숨은 길목을 표시했고, 방통은 그 길목을 흔드는 계책을 덧붙였다.',
|
||||
rewardExp: 11
|
||||
},
|
||||
{
|
||||
id: 'set-bold-and-soft-plan',
|
||||
label: '강온책을 나눈다',
|
||||
response: '두 사람은 강하게 압박할 곳과 조용히 설득할 곳을 분리했다.',
|
||||
rewardExp: 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'zhuge-fa-after-fupass',
|
||||
title: '큰 판과 속내',
|
||||
availableAfterBattleIds: [campBattleIds.twentyEighth],
|
||||
unitIds: ['zhuge-liang', 'fa-zheng'],
|
||||
bondId: 'zhuge-liang__fa-zheng',
|
||||
rewardExp: 28,
|
||||
lines: [
|
||||
'제갈량: 익주는 지세가 험하니 길을 얻어도 마음을 잃으면 오래 지키기 어렵습니다.',
|
||||
'법정: 그래서 저는 안쪽 사람들의 두려움과 불만을 함께 보려 합니다.',
|
||||
'제갈량: 큰 판에 그 속내를 더하면, 피를 줄이는 길도 보일 것입니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'combine-map-and-sentiment',
|
||||
label: '지도와 민심을 합친다',
|
||||
response: '제갈량의 지도 위에 법정의 사람 이름이 더해지자, 익주 공략의 다음 순서가 또렷해졌다.',
|
||||
rewardExp: 11
|
||||
},
|
||||
{
|
||||
id: 'prepare-luo-castle-letter',
|
||||
label: '낙성 서찰을 준비한다',
|
||||
response: '두 책사는 다음 성으로 보낼 글과 병력 배치의 순서를 함께 정했다.',
|
||||
rewardExp: 10
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -3670,6 +3767,66 @@ const campVisits: CampVisitDefinition[] = [
|
||||
itemRewards: ['관문 유인 초안 1']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'fu-pass-storehouse-seal',
|
||||
title: '부수관 창고 봉인',
|
||||
location: '부수관 창고',
|
||||
availableAfterBattleIds: [campBattleIds.twentyEighth],
|
||||
bondId: 'liu-bei__fa-zheng',
|
||||
description: '법정의 조언에 따라 부수관 창고를 함부로 열지 않고 장부와 민심을 먼저 정리합니다.',
|
||||
lines: [
|
||||
'법정: 익주 사람들은 창고 문이 열리는 순간을 보고 새 주인을 판단할 것입니다.',
|
||||
'유비: 병사들이 배고파도 백성의 곡식을 빼앗아서는 안 되오. 장부를 먼저 세우겠소.',
|
||||
'창고 앞에 모인 사람들은 병사들이 물러서고 장부가 펼쳐지는 모습을 조용히 지켜보았습니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'seal-storehouse-ledger',
|
||||
label: '장부를 먼저 세운다',
|
||||
response: '법정은 창고 장부를 정리했고, 유비군은 필요한 보급만 표시해 주민의 불안을 줄였다.',
|
||||
bondExp: 24,
|
||||
itemRewards: ['부수관 창고 장부 1']
|
||||
},
|
||||
{
|
||||
id: 'guard-storehouse-night',
|
||||
label: '야간 경계를 세운다',
|
||||
response: '창고를 노리는 잔병을 막아 내자, 부수관 주민들은 유비군이 약속을 지킨다는 말을 전하기 시작했다.',
|
||||
bondExp: 20,
|
||||
gold: 260,
|
||||
itemRewards: ['콩 4']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'luo-castle-entry-council',
|
||||
title: '낙성 진입 회의',
|
||||
location: '부수관 군막',
|
||||
availableAfterBattleIds: [campBattleIds.twentyEighth],
|
||||
bondId: 'pang-tong__fa-zheng',
|
||||
description: '방통과 법정이 낙성으로 이어지는 길을 두고 빠른 기책과 내부 설득의 균형을 조율합니다.',
|
||||
lines: [
|
||||
'방통: 빠르게 움직이면 낙성 앞의 적이 미처 모이지 못합니다.',
|
||||
'법정: 그러나 빠른 길일수록 뒤에 남는 사람의 마음이 상합니다. 누가 남고 누가 따를지 먼저 보아야 합니다.',
|
||||
'두 사람의 말이 부딪히자, 군막 안의 지도 위에는 빠른 길과 조심스러운 길이 동시에 그어졌습니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'prepare-fast-luo-entry',
|
||||
label: '빠른 진입로를 잡는다',
|
||||
response: '방통은 협곡을 통과하는 빠른 진입로를 표시했고, 법정은 그 길의 반발을 줄일 연락책을 붙였다.',
|
||||
bondExp: 24,
|
||||
itemRewards: ['낙성 진입 초안 1']
|
||||
},
|
||||
{
|
||||
id: 'prepare-soft-luo-entry',
|
||||
label: '내부 설득을 우선한다',
|
||||
response: '법정은 설득해야 할 호족과 관리의 이름을 적었고, 방통은 그 사이를 흔들 유인책을 더했다.',
|
||||
bondExp: 22,
|
||||
gold: 280,
|
||||
itemRewards: ['익주 연락 명단 1']
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -3755,6 +3912,37 @@ export class CampScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
if (battleId === campBattleIds.twentyEighth) {
|
||||
this.campaign = ensureCampaignRosterUnits(
|
||||
[
|
||||
...xuzhouRecruitUnits,
|
||||
...caoBreakRecruitUnits,
|
||||
...liuBiaoRecruitUnits,
|
||||
...zhugeRecruitUnits,
|
||||
...jingzhouRecruitUnits,
|
||||
...guiyangRecruitUnits,
|
||||
...wulingRecruitUnits,
|
||||
...changshaRecruitUnits,
|
||||
...yizhouRecruitUnits,
|
||||
...fuPassRecruitUnits
|
||||
],
|
||||
[
|
||||
...xuzhouRecruitBonds,
|
||||
...caoBreakRecruitBonds,
|
||||
...liuBiaoRecruitBonds,
|
||||
...zhugeRecruitBonds,
|
||||
...jingzhouRecruitBonds,
|
||||
...guiyangRecruitBonds,
|
||||
...wulingRecruitBonds,
|
||||
...changshaRecruitBonds,
|
||||
...yizhouRecruitBonds,
|
||||
...fuPassRecruitBonds
|
||||
]
|
||||
);
|
||||
this.report = this.campaign.firstBattleReport ?? this.report;
|
||||
return;
|
||||
}
|
||||
|
||||
if (battleId === campBattleIds.twentySeventh) {
|
||||
this.campaign = ensureCampaignRosterUnits(
|
||||
[
|
||||
@@ -3932,6 +4120,9 @@ export class CampScene extends Phaser.Scene {
|
||||
|
||||
private currentCampTitle() {
|
||||
const battleId = this.currentCampBattleId();
|
||||
if (battleId === campBattleIds.twentyEighth) {
|
||||
return '부수관 진입 후 군영';
|
||||
}
|
||||
if (battleId === campBattleIds.twentySeventh) {
|
||||
return '익주 원군로 후 군영';
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
seventeenthBattleScenario,
|
||||
tenthBattleScenario,
|
||||
thirteenthBattleScenario,
|
||||
twentyEighthBattleScenario,
|
||||
twentyFirstBattleScenario,
|
||||
twentySecondBattleScenario,
|
||||
twentyThirdBattleScenario,
|
||||
@@ -353,7 +354,8 @@ export class TitleScene extends Phaser.Scene {
|
||||
campaign.step === 'twenty-fourth-camp' ||
|
||||
campaign.step === 'twenty-fifth-camp' ||
|
||||
campaign.step === 'twenty-sixth-camp' ||
|
||||
campaign.step === 'twenty-seventh-camp'
|
||||
campaign.step === 'twenty-seventh-camp' ||
|
||||
campaign.step === 'twenty-eighth-camp'
|
||||
) {
|
||||
this.scene.start('CampScene');
|
||||
return;
|
||||
@@ -494,6 +496,11 @@ export class TitleScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
if (campaign.step === 'twenty-eighth-battle') {
|
||||
this.scene.start('BattleScene', { battleId: twentyEighthBattleScenario.id });
|
||||
return;
|
||||
}
|
||||
|
||||
if (campaign.step === 'first-victory-story') {
|
||||
this.scene.start('StoryScene', { pages: firstBattleVictoryPages, nextScene: 'TitleScene' });
|
||||
return;
|
||||
|
||||
@@ -95,7 +95,9 @@ export type CampaignStep =
|
||||
| 'twenty-sixth-battle'
|
||||
| 'twenty-sixth-camp'
|
||||
| 'twenty-seventh-battle'
|
||||
| 'twenty-seventh-camp';
|
||||
| 'twenty-seventh-camp'
|
||||
| 'twenty-eighth-battle'
|
||||
| 'twenty-eighth-camp';
|
||||
|
||||
export type CampaignUnitProgressSnapshot = {
|
||||
unitId: string;
|
||||
@@ -184,7 +186,8 @@ const campaignBattleSteps: Record<string, { victory: CampaignStep; retry: Campai
|
||||
'twenty-fourth-battle-guiyang-persuasion': { victory: 'twenty-fourth-camp', retry: 'twenty-fourth-battle' },
|
||||
'twenty-fifth-battle-wuling-mountain-road': { victory: 'twenty-fifth-camp', retry: 'twenty-fifth-battle' },
|
||||
'twenty-sixth-battle-changsha-veteran': { victory: 'twenty-sixth-camp', retry: 'twenty-sixth-battle' },
|
||||
'twenty-seventh-battle-yizhou-relief-road': { victory: 'twenty-seventh-camp', retry: 'twenty-seventh-battle' }
|
||||
'twenty-seventh-battle-yizhou-relief-road': { victory: 'twenty-seventh-camp', retry: 'twenty-seventh-battle' },
|
||||
'twenty-eighth-battle-fu-pass-entry': { victory: 'twenty-eighth-camp', retry: 'twenty-eighth-battle' }
|
||||
};
|
||||
|
||||
export type CampaignSaveSlotSummary = {
|
||||
|
||||
Reference in New Issue
Block a user