Add Yi Province relief road chapter

This commit is contained in:
2026-06-23 08:55:39 +09:00
parent 2402e1c38f
commit 17cbaab55d
11 changed files with 1251 additions and 49 deletions

View File

@@ -1704,6 +1704,68 @@ export const twentySixthBattleVictoryPages: StoryPage[] = [
}
];
export const twentySeventhBattleIntroPages: StoryPage[] = [
{
id: 'twenty-seventh-yizhou-request',
bgm: 'story-dark',
chapter: '익주에서 온 요청',
background: 'story-three-heroes',
speaker: '손건',
text: '익주의 유장이 한중 장로의 압박을 두려워하여 원군을 청했습니다. 형주 남부를 안정시킨 지금, 이 요청은 촉으로 향하는 첫 문이 될 수 있습니다.'
},
{
id: 'twenty-seventh-pang-tong-rumor',
bgm: 'battle-prep',
chapter: '봉추의 그림자',
background: 'story-liu-bei',
speaker: '제갈량',
text: '익주로 들어가는 길목에는 봉추라 불리는 방통이 머문다는 소문이 있습니다. 그가 뜻을 함께한다면, 산과 관문으로 막힌 촉의 길도 달리 보일 것입니다.'
},
{
id: 'twenty-seventh-gate-warning',
bgm: 'story-dark',
chapter: '원군로의 관문',
background: 'story-militia',
speaker: '마량',
text: '양회가 이끄는 전초 병력이 원군로를 막고 있습니다. 길목의 마을을 지켜 명분을 잃지 않고, 산길의 척후를 먼저 끊어야 합니다.'
},
{
id: 'twenty-seventh-yizhou-sortie',
bgm: 'battle-prep',
chapter: '익주 원군로',
background: 'story-sortie',
speaker: '유비',
portrait: 'liuBei',
text: '우리는 익주를 빼앗으러 가는 것이 아니라, 백성을 지키라는 부름에 응하는 것이오. 군율을 세우고 길을 열어 봉추의 마음까지 얻어 봅시다.'
}
];
export const twentySeventhBattleVictoryPages: StoryPage[] = [
{
id: 'twenty-seventh-victory-road-open',
bgm: 'militia-theme',
chapter: '익주의 길이 열리다',
background: 'story-sortie',
text: '양회의 전초 병력이 물러나고 익주 원군로가 열렸습니다. 유비군은 마을의 창고를 건드리지 않고 길목을 안정시켜, 원군이라는 명분을 분명히 세웠습니다.'
},
{
id: 'twenty-seventh-pang-tong-joins',
bgm: 'battle-prep',
chapter: '방통의 합류',
background: 'story-liu-bei',
speaker: '방통',
text: '인의를 말로만 내세우는 군은 많으나, 길목의 작은 마을까지 지키며 움직이는 군은 드뭅니다. 이 방통, 촉으로 향하는 험한 길을 함께 보겠습니다.'
},
{
id: 'twenty-seventh-next-fu-pass',
bgm: 'story-dark',
chapter: '부수관을 바라보다',
background: 'story-three-heroes',
speaker: '제갈량',
text: '봉추가 합류하니 익주의 지세와 사람의 마음을 함께 읽을 수 있게 되었습니다. 다음 길은 부수관과 낙성으로 이어지는 더 깊은 산문입니다.'
}
];
export const firstBattleMap: BattleMap = {
width: 20,
height: 18,
@@ -2005,6 +2067,12 @@ export const twentySixthBattleMap: BattleMap = {
terrain: createTwentySixthBattleTerrain()
};
export const twentySeventhBattleMap: BattleMap = {
width: 54,
height: 36,
terrain: createTwentySeventhBattleTerrain()
};
export const firstBattleUnits: UnitData[] = [
{
id: 'liu-bei',
@@ -4078,6 +4146,30 @@ export const changshaRecruitUnits: UnitData[] = [
}
];
export const yizhouRecruitUnits: UnitData[] = [
{
id: 'pang-tong',
name: '방통',
faction: 'ally',
className: '봉추 책사',
classKey: 'strategist',
level: 16,
exp: 0,
hp: 36,
maxHp: 36,
attack: 9,
move: 4,
stats: { might: 44, intelligence: 96, leadership: 88, agility: 72, luck: 82 },
equipment: {
weapon: { itemId: 'white-feather-fan', level: 2, exp: 16 },
armor: { itemId: 'cloth-armor', level: 2, exp: 12 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 8,
y: 24
}
];
const eighthBattleAllyPositions: Record<string, { x: number; y: number }> = {
'liu-bei': { x: 2, y: 17 },
'guan-yu': { x: 3, y: 17 },
@@ -10584,6 +10676,435 @@ export const twentySixthBattleUnits: UnitData[] = [
}
];
const twentySeventhBattleAllyPositions: Record<string, { x: number; y: number }> = {
'liu-bei': { x: 4, y: 30 },
'guan-yu': { x: 6, y: 29 },
'zhang-fei': { x: 5, y: 32 },
'jian-yong': { x: 3, y: 33 },
'mi-zhu': { x: 4, y: 34 },
'sun-qian': { x: 7, y: 33 },
'zhao-yun': { x: 8, y: 30 },
'zhuge-liang': { x: 5, y: 30 },
'ma-liang': { x: 8, y: 34 },
'yi-ji': { x: 9, y: 32 },
'gong-zhi': { x: 10, y: 34 },
'huang-zhong': { x: 7, y: 31 },
'wei-yan': { x: 9, y: 29 }
};
export const twentySeventhBattleUnits: UnitData[] = [
...[
...firstBattleUnits.filter((unit) => unit.faction === 'ally'),
...xuzhouRecruitUnits,
...caoBreakRecruitUnits,
...liuBiaoRecruitUnits,
...zhugeRecruitUnits,
...jingzhouRecruitUnits,
...guiyangRecruitUnits,
...wulingRecruitUnits,
...changshaRecruitUnits
].map((unit) => placeScenarioUnit(unit, twentySeventhBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
{
id: 'yizhou-scout-a',
name: '익주 척후',
faction: 'enemy',
className: '산길 척후',
classKey: 'bandit',
level: 41,
exp: 62,
hp: 106,
maxHp: 106,
attack: 40,
move: 4,
stats: { might: 128, intelligence: 92, leadership: 104, agility: 120, luck: 84 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 4, exp: 42 },
armor: { itemId: 'rebel-vest', level: 4, exp: 28 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 16,
y: 30
},
{
id: 'yizhou-scout-b',
name: '익주 척후',
faction: 'enemy',
className: '관문 척후',
classKey: 'bandit',
level: 41,
exp: 62,
hp: 106,
maxHp: 106,
attack: 40,
move: 4,
stats: { might: 128, intelligence: 92, leadership: 104, agility: 120, luck: 84 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 4, exp: 42 },
armor: { itemId: 'rebel-vest', level: 4, exp: 28 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 20,
y: 28
},
{
id: 'yizhou-infantry-a',
name: '익주 보병',
faction: 'enemy',
className: '원군로 보병',
classKey: 'yellowTurban',
level: 42,
exp: 64,
hp: 140,
maxHp: 140,
attack: 44,
move: 3,
stats: { might: 142, intelligence: 92, leadership: 120, agility: 100, luck: 84 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 58 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 42 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 24,
y: 27
},
{
id: 'yizhou-infantry-b',
name: '익주 보병',
faction: 'enemy',
className: '고개 보병',
classKey: 'yellowTurban',
level: 42,
exp: 64,
hp: 140,
maxHp: 140,
attack: 44,
move: 3,
stats: { might: 142, intelligence: 92, leadership: 120, agility: 100, luck: 84 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 58 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 42 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 28,
y: 24
},
{
id: 'yizhou-infantry-c',
name: '익주 보병',
faction: 'enemy',
className: '관문 보병',
classKey: 'yellowTurban',
level: 43,
exp: 66,
hp: 148,
maxHp: 148,
attack: 46,
move: 3,
stats: { might: 146, intelligence: 94, leadership: 124, agility: 102, luck: 84 },
equipment: {
weapon: { itemId: 'iron-spear', level: 5, exp: 8 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 48 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 35,
y: 21
},
{
id: 'yizhou-infantry-d',
name: '익주 보병',
faction: 'enemy',
className: '성문 보병',
classKey: 'yellowTurban',
level: 43,
exp: 66,
hp: 148,
maxHp: 148,
attack: 46,
move: 3,
stats: { might: 146, intelligence: 94, leadership: 124, agility: 102, luck: 84 },
equipment: {
weapon: { itemId: 'iron-spear', level: 5, exp: 8 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 48 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 40,
y: 17
},
{
id: 'yizhou-archer-a',
name: '익주 궁병',
faction: 'enemy',
className: '산비탈 궁병',
classKey: 'archer',
level: 42,
exp: 64,
hp: 104,
maxHp: 104,
attack: 42,
move: 3,
stats: { might: 102, intelligence: 102, leadership: 108, agility: 116, luck: 86 },
equipment: {
weapon: { itemId: 'short-bow', level: 4, exp: 54 },
armor: { itemId: 'cloth-armor', level: 4, exp: 34 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 30,
y: 21
},
{
id: 'yizhou-archer-b',
name: '익주 궁병',
faction: 'enemy',
className: '관문 궁병',
classKey: 'archer',
level: 43,
exp: 66,
hp: 108,
maxHp: 108,
attack: 43,
move: 3,
stats: { might: 104, intelligence: 104, leadership: 110, agility: 118, luck: 86 },
equipment: {
weapon: { itemId: 'short-bow', level: 5, exp: 4 },
armor: { itemId: 'cloth-armor', level: 4, exp: 38 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 42,
y: 15
},
{
id: 'yizhou-archer-c',
name: '익주 궁병',
faction: 'enemy',
className: '성루 궁병',
classKey: 'archer',
level: 43,
exp: 66,
hp: 108,
maxHp: 108,
attack: 43,
move: 3,
stats: { might: 104, intelligence: 104, leadership: 110, agility: 118, luck: 86 },
equipment: {
weapon: { itemId: 'short-bow', level: 5, exp: 4 },
armor: { itemId: 'cloth-armor', level: 4, exp: 38 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 47,
y: 19
},
{
id: 'yizhou-cavalry-a',
name: '익주 기병',
faction: 'enemy',
className: '원군로 기병',
classKey: 'cavalry',
level: 43,
exp: 66,
hp: 148,
maxHp: 148,
attack: 47,
move: 5,
stats: { might: 146, intelligence: 92, leadership: 120, agility: 120, luck: 86 },
equipment: {
weapon: { itemId: 'iron-spear', level: 5, exp: 10 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 44 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 22,
y: 31
},
{
id: 'yizhou-cavalry-b',
name: '익주 기병',
faction: 'enemy',
className: '산문 기병',
classKey: 'cavalry',
level: 43,
exp: 66,
hp: 148,
maxHp: 148,
attack: 47,
move: 5,
stats: { might: 146, intelligence: 92, leadership: 120, agility: 120, luck: 86 },
equipment: {
weapon: { itemId: 'iron-spear', level: 5, exp: 10 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 44 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 37,
y: 28
},
{
id: 'yizhou-cavalry-c',
name: '익주 기병',
faction: 'enemy',
className: '성문 기병',
classKey: 'cavalry',
level: 44,
exp: 68,
hp: 154,
maxHp: 154,
attack: 49,
move: 5,
stats: { might: 150, intelligence: 94, leadership: 124, agility: 122, luck: 86 },
equipment: {
weapon: { itemId: 'iron-spear', level: 5, exp: 18 },
armor: { itemId: 'lamellar-armor', level: 5, exp: 4 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 45,
y: 25
},
{
id: 'yizhou-guard-a',
name: '양회 친위대',
faction: 'enemy',
className: '관문 친위대',
classKey: 'yellowTurban',
level: 44,
exp: 68,
hp: 158,
maxHp: 158,
attack: 49,
move: 3,
stats: { might: 152, intelligence: 96, leadership: 128, agility: 104, luck: 86 },
equipment: {
weapon: { itemId: 'iron-spear', level: 5, exp: 20 },
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 8 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 46,
y: 15
},
{
id: 'yizhou-guard-b',
name: '양회 친위대',
faction: 'enemy',
className: '성문 친위대',
classKey: 'yellowTurban',
level: 44,
exp: 68,
hp: 158,
maxHp: 158,
attack: 49,
move: 3,
stats: { might: 152, intelligence: 96, leadership: 128, agility: 104, luck: 86 },
equipment: {
weapon: { itemId: 'iron-spear', level: 5, exp: 20 },
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 8 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 49,
y: 17
},
{
id: 'yizhou-strategist-a',
name: '익주 책사',
faction: 'enemy',
className: '관문 책사',
classKey: 'archer',
level: 43,
exp: 66,
hp: 108,
maxHp: 108,
attack: 43,
move: 3,
stats: { might: 92, intelligence: 120, leadership: 112, agility: 98, luck: 86 },
equipment: {
weapon: { itemId: 'short-bow', level: 5, exp: 4 },
armor: { itemId: 'cloth-armor', level: 4, exp: 38 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 41,
y: 13
},
{
id: 'yizhou-strategist-b',
name: '익주 책사',
faction: 'enemy',
className: '성문 책사',
classKey: 'archer',
level: 43,
exp: 66,
hp: 108,
maxHp: 108,
attack: 43,
move: 3,
stats: { might: 92, intelligence: 120, leadership: 112, agility: 98, luck: 86 },
equipment: {
weapon: { itemId: 'short-bow', level: 5, exp: 4 },
armor: { itemId: 'cloth-armor', level: 4, exp: 38 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 48,
y: 21
},
{
id: 'yizhou-ambusher-a',
name: '복병',
faction: 'enemy',
className: '숲길 복병',
classKey: 'bandit',
level: 42,
exp: 64,
hp: 112,
maxHp: 112,
attack: 42,
move: 4,
stats: { might: 132, intelligence: 94, leadership: 106, agility: 124, luck: 84 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 4, exp: 48 },
armor: { itemId: 'rebel-vest', level: 4, exp: 32 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 31,
y: 30
},
{
id: 'yizhou-ambusher-b',
name: '복병',
faction: 'enemy',
className: '고개 복병',
classKey: 'bandit',
level: 42,
exp: 64,
hp: 112,
maxHp: 112,
attack: 42,
move: 4,
stats: { might: 132, intelligence: 94, leadership: 106, agility: 124, luck: 84 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 4, exp: 48 },
armor: { itemId: 'rebel-vest', level: 4, exp: 32 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 36,
y: 8
},
{
id: 'yizhou-leader-yang-huai',
name: '양회',
faction: 'enemy',
className: '익주 관문장',
classKey: 'rebelLeader',
level: 45,
exp: 72,
hp: 204,
maxHp: 204,
attack: 50,
move: 4,
stats: { might: 150, intelligence: 112, leadership: 136, agility: 106, luck: 88 },
equipment: {
weapon: { itemId: 'leader-axe', level: 5, exp: 20 },
armor: { itemId: 'reinforced-lamellar', level: 5, exp: 16 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 50,
y: 16
}
];
export const firstBattleBonds: BattleBond[] = [
{
id: 'liu-bei__guan-yu',
@@ -10827,6 +11348,33 @@ export const changshaRecruitBonds: BattleBond[] = [
}
];
export const yizhouRecruitBonds: BattleBond[] = [
{
id: 'liu-bei__pang-tong',
unitIds: ['liu-bei', 'pang-tong'],
title: '봉추가 보는 인의',
level: 36,
exp: 0,
description: '유비의 인의와 방통의 날카로운 지략이 만나, 익주의 산문을 명분과 속도로 함께 열어 갑니다.'
},
{
id: 'zhuge-liang__pang-tong',
unitIds: ['zhuge-liang', 'pang-tong'],
title: '와룡과 봉추',
level: 34,
exp: 0,
description: '제갈량의 큰 판과 방통의 과감한 계책이 맞물려, 어려운 지형에서도 새로운 돌파구를 찾아냅니다.'
},
{
id: 'huang-zhong__pang-tong',
unitIds: ['huang-zhong', 'pang-tong'],
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);
@@ -10858,6 +11406,7 @@ export const twentyThirdBattleBonds: BattleBond[] = [...twentySecondBattleBonds]
export const twentyFourthBattleBonds: BattleBond[] = [...twentyThirdBattleBonds, ...jingzhouRecruitBonds].map(cloneBattleBondForScenario);
export const twentyFifthBattleBonds: BattleBond[] = [...twentyFourthBattleBonds, ...guiyangRecruitBonds].map(cloneBattleBondForScenario);
export const twentySixthBattleBonds: BattleBond[] = [...twentyFifthBattleBonds, ...wulingRecruitBonds].map(cloneBattleBondForScenario);
export const twentySeventhBattleBonds: BattleBond[] = [...twentySixthBattleBonds, ...changshaRecruitBonds].map(cloneBattleBondForScenario);
function createEighthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 22 }, (_, y) =>
@@ -11823,6 +12372,62 @@ function createTwentySixthBattleTerrain(): TerrainType[][] {
);
}
function createTwentySeventhBattleTerrain(): TerrainType[][] {
return Array.from({ length: 36 }, (_, y) =>
Array.from({ length: 54 }, (_, x): TerrainType => {
if (x <= 4 && y >= 29) {
return 'camp';
}
if ((x >= 45 && x <= 52 && y >= 12 && y <= 20) || (x >= 41 && x <= 47 && y >= 9 && y <= 14)) {
return 'fort';
}
if ((x >= 18 && x <= 20 && y >= 27 && y <= 29) || (x >= 32 && x <= 34 && y >= 22 && y <= 24) || (x >= 38 && x <= 40 && y >= 16 && y <= 18)) {
return 'village';
}
if (
(y >= 31 && x >= 4 && x <= 15) ||
(x >= 14 && x <= 24 && y >= 27 && y <= 31) ||
(x >= 23 && x <= 33 && y >= 23 && y <= 27) ||
(x >= 32 && x <= 40 && y >= 18 && y <= 23) ||
(x >= 39 && x <= 48 && y >= 14 && y <= 18) ||
(x >= 47 && x <= 51 && y >= 15 && y <= 17)
) {
return 'road';
}
if ((x === 12 || x === 13) && y >= 0 && y <= 25) {
return 'river';
}
if ((x === 29 || x === 30) && y >= 4 && y <= 21) {
return 'river';
}
if ((x === 36 || x === 37) && y >= 25 && y <= 35) {
return 'river';
}
if (
(x >= 4 && x <= 16 && y >= 8 && y <= 20) ||
(x >= 17 && x <= 28 && y >= 10 && y <= 21) ||
(x >= 31 && x <= 42 && y >= 25 && y <= 35) ||
(x >= 41 && x <= 53 && y >= 22 && y <= 33)
) {
return 'forest';
}
if (
(x >= 0 && x <= 10 && y <= 11) ||
(x >= 20 && x <= 28 && y <= 9) ||
(x >= 31 && x <= 43 && y >= 4 && y <= 12) ||
(x >= 47 && x <= 53 && y <= 11) ||
(x >= 22 && x <= 31 && y >= 29 && y <= 35)
) {
return 'hill';
}
if ((x <= 2 && y <= 28) || (x >= 52 && y >= 20) || (x >= 43 && x <= 45 && y <= 8)) {
return 'cliff';
}
return 'plain';
})
);
}
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
return {
...cloneUnitForScenario(unit),