Add Yuan Shao refuge road chapter

This commit is contained in:
2026-06-23 04:23:14 +09:00
parent 09c1390ba5
commit 821cebde0e
11 changed files with 873 additions and 18 deletions

View File

@@ -941,6 +941,71 @@ export const fourteenthBattleVictoryPages: StoryPage[] = [
}
];
export const fifteenthBattleIntroPages: StoryPage[] = [
{
id: 'fifteenth-yuan-envoy-rumor',
bgm: 'story-dark',
chapter: '북쪽의 초대',
background: 'story-militia',
speaker: '손건',
text: '원소 진영에서 사자가 내려왔습니다. 조조를 떠난 주공을 받아들일 뜻은 있으나, 북상로 곳곳에는 조조군 추격대가 깔려 있습니다.'
},
{
id: 'fifteenth-liu-bei-under-yuan-shadow',
bgm: 'battle-prep',
chapter: '원소 의탁',
background: 'story-liu-bei',
speaker: '유비',
portrait: 'liuBei',
text: '원소의 깃발 아래로 들어가는 일은 뜻을 접는 일이 아니다. 지금은 큰 세력의 틈에서 백성을 지킬 시간을 얻어야 한다.'
},
{
id: 'fifteenth-guan-yu-pursuit-road',
bgm: 'battle-prep',
chapter: '추격로',
background: 'story-three-heroes',
speaker: '관우',
portrait: 'guanYu',
text: '추격대가 강가와 고갯길을 나누어 막고 있습니다. 채양의 군세를 물리치고 접선지를 확보해야 원소 진영과 이어질 수 있습니다.'
},
{
id: 'fifteenth-yuan-road-sortie',
bgm: 'battle-prep',
chapter: '북상 전투',
background: 'story-sortie',
speaker: '장비',
portrait: 'zhangFei',
text: '쫓아오는 놈들이 조조의 명이라 떠들어도 결국 길을 막는 적일 뿐입니다. 형님, 이번엔 북쪽 길을 시원하게 열어 봅시다!'
}
];
export const fifteenthBattleVictoryPages: StoryPage[] = [
{
id: 'fifteenth-victory-pursuit-breaks',
bgm: 'militia-theme',
chapter: '추격을 끊다',
background: 'story-sortie',
text: '채양의 추격대가 흩어지자 북상로의 먼지가 잠시 가라앉았다. 유비군은 원소의 사자가 기다리는 접선지에 닿을 수 있었다.'
},
{
id: 'fifteenth-yuan-camp-opens',
bgm: 'story-dark',
chapter: '원소의 장막',
background: 'story-militia',
speaker: '간옹',
text: '원소의 진영은 넓고 군세는 크지만, 그만큼 말과 눈도 많습니다. 몸을 맡기되 마음까지 맡기지는 말아야 하겠지요.'
},
{
id: 'fifteenth-road-to-liu-biao',
bgm: 'battle-prep',
chapter: '다음 의탁의 그림자',
background: 'story-liu-bei',
speaker: '유비',
portrait: 'liuBei',
text: '큰 깃발 아래에서도 우리의 뜻은 작아져서는 안 된다. 원소의 군영에서 기회를 살피고, 다시 백성을 지킬 길을 찾아야 한다.'
}
];
export const firstBattleMap: BattleMap = {
width: 20,
height: 18,
@@ -1170,6 +1235,12 @@ export const fourteenthBattleMap: BattleMap = {
terrain: createFourteenthBattleTerrain()
};
export const fifteenthBattleMap: BattleMap = {
width: 34,
height: 24,
terrain: createFifteenthBattleTerrain()
};
export const firstBattleUnits: UnitData[] = [
{
id: 'liu-bei',
@@ -5004,6 +5075,378 @@ export const fourteenthBattleUnits: UnitData[] = [
}
];
const fifteenthBattleAllyPositions: Record<string, { x: number; y: number }> = {
'liu-bei': { x: 3, y: 18 },
'guan-yu': { x: 4, y: 17 },
'zhang-fei': { x: 4, y: 19 },
'jian-yong': { x: 5, y: 18 },
'mi-zhu': { x: 3, y: 20 },
'sun-qian': { x: 5, y: 20 }
};
export const fifteenthBattleUnits: UnitData[] = [
...[...firstBattleUnits.filter((unit) => unit.faction === 'ally'), ...xuzhouRecruitUnits, ...caoBreakRecruitUnits].map((unit) =>
placeScenarioUnit(unit, fifteenthBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })
),
{
id: 'yuan-refuge-scout-a',
name: '조조군 척후',
faction: 'enemy',
className: '추격 척후',
classKey: 'bandit',
level: 15,
exp: 92,
hp: 54,
maxHp: 54,
attack: 20,
move: 4,
stats: { might: 90, intelligence: 62, leadership: 68, agility: 88, luck: 62 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 68 },
armor: { itemId: 'rebel-vest', level: 2, exp: 30 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 10,
y: 16
},
{
id: 'yuan-refuge-scout-b',
name: '조조군 척후',
faction: 'enemy',
className: '추격 척후',
classKey: 'bandit',
level: 15,
exp: 92,
hp: 54,
maxHp: 54,
attack: 20,
move: 4,
stats: { might: 90, intelligence: 62, leadership: 68, agility: 88, luck: 62 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 68 },
armor: { itemId: 'rebel-vest', level: 2, exp: 30 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 12,
y: 20
},
{
id: 'yuan-refuge-infantry-a',
name: '조조 보병',
faction: 'enemy',
className: '추격 보병',
classKey: 'yellowTurban',
level: 15,
exp: 94,
hp: 62,
maxHp: 62,
attack: 20,
move: 3,
stats: { might: 92, intelligence: 62, leadership: 80, agility: 70, luck: 61 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 70 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 32 },
accessory: { itemId: 'yellow-scarf-charm', level: 1, exp: 0 }
},
x: 15,
y: 12
},
{
id: 'yuan-refuge-infantry-b',
name: '조조 보병',
faction: 'enemy',
className: '추격 보병',
classKey: 'yellowTurban',
level: 15,
exp: 94,
hp: 62,
maxHp: 62,
attack: 20,
move: 3,
stats: { might: 92, intelligence: 62, leadership: 80, agility: 70, luck: 61 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 70 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 32 },
accessory: { itemId: 'yellow-scarf-charm', level: 1, exp: 0 }
},
x: 17,
y: 14
},
{
id: 'yuan-refuge-infantry-c',
name: '조조 보병',
faction: 'enemy',
className: '추격 보병',
classKey: 'yellowTurban',
level: 16,
exp: 96,
hp: 64,
maxHp: 64,
attack: 21,
move: 3,
stats: { might: 94, intelligence: 63, leadership: 82, agility: 71, luck: 62 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 72 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 34 },
accessory: { itemId: 'yellow-scarf-charm', level: 1, exp: 0 }
},
x: 20,
y: 10
},
{
id: 'yuan-refuge-infantry-d',
name: '조조 보병',
faction: 'enemy',
className: '추격 보병',
classKey: 'yellowTurban',
level: 16,
exp: 96,
hp: 64,
maxHp: 64,
attack: 21,
move: 3,
stats: { might: 94, intelligence: 63, leadership: 82, agility: 71, luck: 62 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 72 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 34 },
accessory: { itemId: 'yellow-scarf-charm', level: 1, exp: 0 }
},
x: 23,
y: 15
},
{
id: 'yuan-refuge-archer-a',
name: '조조 궁병',
faction: 'enemy',
className: '추격 궁병',
classKey: 'archer',
level: 15,
exp: 94,
hp: 50,
maxHp: 50,
attack: 20,
move: 3,
stats: { might: 83, intelligence: 74, leadership: 72, agility: 84, luck: 62 },
equipment: {
weapon: { itemId: 'short-bow', level: 2, exp: 68 },
armor: { itemId: 'cloth-armor', level: 2, exp: 30 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 18,
y: 8
},
{
id: 'yuan-refuge-archer-b',
name: '조조 궁병',
faction: 'enemy',
className: '추격 궁병',
classKey: 'archer',
level: 15,
exp: 94,
hp: 50,
maxHp: 50,
attack: 20,
move: 3,
stats: { might: 83, intelligence: 74, leadership: 72, agility: 84, luck: 62 },
equipment: {
weapon: { itemId: 'short-bow', level: 2, exp: 68 },
armor: { itemId: 'cloth-armor', level: 2, exp: 30 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 23,
y: 8
},
{
id: 'yuan-refuge-archer-c',
name: '조조 궁병',
faction: 'enemy',
className: '추격 궁병',
classKey: 'archer',
level: 16,
exp: 96,
hp: 52,
maxHp: 52,
attack: 21,
move: 3,
stats: { might: 84, intelligence: 75, leadership: 73, agility: 85, luck: 63 },
equipment: {
weapon: { itemId: 'short-bow', level: 2, exp: 70 },
armor: { itemId: 'cloth-armor', level: 2, exp: 32 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 27,
y: 13
},
{
id: 'yuan-refuge-cavalry-a',
name: '조조 기병',
faction: 'enemy',
className: '추격 기병',
classKey: 'cavalry',
level: 16,
exp: 98,
hp: 68,
maxHp: 68,
attack: 23,
move: 5,
stats: { might: 98, intelligence: 58, leadership: 76, agility: 92, luck: 64 },
equipment: {
weapon: { itemId: 'iron-spear', level: 2, exp: 72 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 34 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 14,
y: 18
},
{
id: 'yuan-refuge-cavalry-b',
name: '조조 기병',
faction: 'enemy',
className: '추격 기병',
classKey: 'cavalry',
level: 16,
exp: 98,
hp: 68,
maxHp: 68,
attack: 23,
move: 5,
stats: { might: 98, intelligence: 58, leadership: 76, agility: 92, luck: 64 },
equipment: {
weapon: { itemId: 'iron-spear', level: 2, exp: 72 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 34 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 19,
y: 19
},
{
id: 'yuan-refuge-cavalry-c',
name: '조조 기병',
faction: 'enemy',
className: '추격 기병',
classKey: 'cavalry',
level: 16,
exp: 98,
hp: 68,
maxHp: 68,
attack: 23,
move: 5,
stats: { might: 98, intelligence: 58, leadership: 76, agility: 92, luck: 64 },
equipment: {
weapon: { itemId: 'iron-spear', level: 2, exp: 72 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 34 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 25,
y: 19
},
{
id: 'yuan-refuge-guard-a',
name: '북상로 수비대',
faction: 'enemy',
className: '관문 수비대',
classKey: 'yellowTurban',
level: 16,
exp: 98,
hp: 70,
maxHp: 70,
attack: 22,
move: 3,
stats: { might: 96, intelligence: 64, leadership: 84, agility: 70, luck: 62 },
equipment: {
weapon: { itemId: 'iron-spear', level: 2, exp: 74 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 36 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 27,
y: 9
},
{
id: 'yuan-refuge-guard-b',
name: '북상로 수비대',
faction: 'enemy',
className: '관문 수비대',
classKey: 'yellowTurban',
level: 16,
exp: 98,
hp: 70,
maxHp: 70,
attack: 22,
move: 3,
stats: { might: 96, intelligence: 64, leadership: 84, agility: 70, luck: 62 },
equipment: {
weapon: { itemId: 'iron-spear', level: 2, exp: 74 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 36 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 29,
y: 12
},
{
id: 'yuan-refuge-guard-c',
name: '북상로 수비대',
faction: 'enemy',
className: '관문 수비대',
classKey: 'yellowTurban',
level: 16,
exp: 98,
hp: 70,
maxHp: 70,
attack: 22,
move: 3,
stats: { might: 96, intelligence: 64, leadership: 84, agility: 70, luck: 62 },
equipment: {
weapon: { itemId: 'iron-spear', level: 2, exp: 74 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 36 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 30,
y: 15
},
{
id: 'yuan-refuge-strategist-a',
name: '조조군 참모',
faction: 'enemy',
className: '추격 참모',
classKey: 'archer',
level: 16,
exp: 98,
hp: 54,
maxHp: 54,
attack: 22,
move: 3,
stats: { might: 70, intelligence: 88, leadership: 78, agility: 76, luck: 66 },
equipment: {
weapon: { itemId: 'short-bow', level: 2, exp: 72 },
armor: { itemId: 'cloth-armor', level: 2, exp: 34 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 26,
y: 11
},
{
id: 'yuan-refuge-leader-cai-yang',
name: '채양',
faction: 'enemy',
className: '조조군 추격장',
classKey: 'rebelLeader',
level: 18,
exp: 12,
hp: 92,
maxHp: 92,
attack: 26,
move: 4,
stats: { might: 104, intelligence: 58, leadership: 90, agility: 82, luck: 64 },
equipment: {
weapon: { itemId: 'iron-spear', level: 3, exp: 18 },
armor: { itemId: 'reinforced-lamellar', level: 2, exp: 42 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 31,
y: 12
}
];
export const firstBattleBonds: BattleBond[] = [
{
id: 'liu-bei__guan-yu',
@@ -5084,6 +5527,7 @@ export const thirteenthBattleBonds: BattleBond[] = twelfthBattleBonds.map(cloneB
export const fourteenthBattleBonds: BattleBond[] = [...thirteenthBattleBonds, ...caoBreakRecruitBonds].map(
cloneBattleBondForScenario
);
export const fifteenthBattleBonds: BattleBond[] = fourteenthBattleBonds.map(cloneBattleBondForScenario);
function createEighthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 22 }, (_, y) =>
@@ -5388,6 +5832,58 @@ function createFourteenthBattleTerrain(): TerrainType[][] {
);
}
function createFifteenthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 24 }, (_, y) =>
Array.from({ length: 34 }, (_, x): TerrainType => {
if (x <= 2 && y >= 17 && y <= 21) {
return 'camp';
}
if ((x >= 27 && x <= 32 && y >= 8 && y <= 15) || (x >= 30 && x <= 33 && y >= 5 && y <= 7)) {
return 'fort';
}
if ((x >= 9 && x <= 11 && y >= 15 && y <= 17) || (x >= 20 && x <= 22 && y >= 7 && y <= 9)) {
return 'village';
}
if ((x === 14 || x === 15) && y >= 1 && y <= 22) {
return 'river';
}
if ((x === 24 || x === 25) && y >= 2 && y <= 20) {
return 'river';
}
if (
(y === 18 && x >= 2 && x <= 17) ||
(y === 14 && x >= 13 && x <= 28) ||
(y === 10 && x >= 21 && x <= 32) ||
(x === 29 && y >= 8 && y <= 17)
) {
return 'road';
}
if ((x >= 5 && x <= 17 && y === 23 - x) || (x >= 12 && x <= 28 && y === x - 7)) {
return 'road';
}
if (
(x <= 8 && y <= 7) ||
(x >= 4 && x <= 11 && y >= 9 && y <= 13) ||
(x >= 2 && x <= 8 && y >= 14 && y <= 16) ||
(x >= 27 && y >= 18 && y <= 22)
) {
return 'forest';
}
if (
(x >= 6 && x <= 12 && y >= 2 && y <= 5) ||
(x >= 18 && x <= 22 && y >= 18 && y <= 22) ||
(x >= 29 && x <= 33 && y >= 1 && y <= 4)
) {
return 'hill';
}
if ((x >= 32 && y <= 8) || (x >= 32 && y >= 16) || (x <= 1 && y <= 4)) {
return 'cliff';
}
return 'plain';
})
);
}
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
return {
...cloneUnitForScenario(unit),