Add Fu Pass entry chapter

This commit is contained in:
2026-06-23 09:14:41 +09:00
parent 17cbaab55d
commit 8349d1044f
11 changed files with 1260 additions and 34 deletions

View File

@@ -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];

View File

@@ -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: '낙성 이후 익주 심부 장은 다음 작업에서 이어집니다. 군영에서 법정과 방통의 공명도를 올리고 다음 관문을 준비하십시오.'
}
};

View File

@@ -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),

View File

@@ -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>> = {

View File

@@ -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);

View File

@@ -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 '익주 원군로 후 군영';
}

View File

@@ -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;

View File

@@ -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 = {