Add Sishui vanguard campaign battle

This commit is contained in:
2026-06-22 23:57:49 +09:00
parent 421b95011e
commit fe93b70a56
9 changed files with 594 additions and 15 deletions

View File

@@ -374,6 +374,60 @@ export const fourthBattleVictoryPages: StoryPage[] = [
}
];
export const fifthBattleIntroPages: StoryPage[] = [
{
id: 'fifth-coalition-rumor',
bgm: 'militia-theme',
chapter: '반동탁의 격문',
background: 'story-militia',
text: '황건의 불길이 잦아들자 조정에는 또 다른 폭풍이 일었다. 동탁이 낙양을 장악했다는 소식과 함께, 각지의 제후들이 반동탁의 격문에 응하기 시작했다.'
},
{
id: 'fifth-liu-bei-choice',
bgm: 'battle-prep',
chapter: '새로운 대의',
background: 'story-liu-bei',
speaker: '유비',
portrait: 'liuBei',
text: '백성을 괴롭히는 난을 막았다 하나, 조정이 어지러우면 천하는 다시 피를 흘린다. 우리는 더 큰 흐름 속으로 들어가야 한다.'
},
{
id: 'fifth-gongsun-zan',
bgm: 'battle-prep',
chapter: '공손찬의 진영',
background: 'story-three-heroes',
speaker: '관우',
portrait: 'guanYu',
text: '공손찬의 군영에 합류하면 연합군의 움직임을 가까이서 볼 수 있습니다. 그러나 동탁군도 사수관 앞길을 막고 있습니다.'
},
{
id: 'fifth-sishui-sortie',
bgm: 'battle-prep',
chapter: '사수관 전초전',
background: 'story-sortie',
speaker: '장비',
portrait: 'zhangFei',
text: '동탁군이든 황건적이든 백성을 짓밟는 놈들은 똑같소. 사수관 앞길부터 뚫어 봅시다!'
}
];
export const fifthBattleVictoryPages: StoryPage[] = [
{
id: 'fifth-victory-sishui',
bgm: 'militia-theme',
chapter: '사수관의 문턱',
background: 'story-sortie',
text: '동탁군의 전초 부대가 물러서자 연합군 진영에 세 형제의 이름이 다시 한 번 전해졌다.'
},
{
id: 'fifth-victory-next',
bgm: 'battle-prep',
chapter: '공손찬 의탁',
background: 'story-militia',
text: '사수관 앞 전초전은 끝났지만, 반동탁의 싸움은 이제 막 시작되었다. 유비는 공손찬의 군영에서 다음 기회를 기다린다.'
}
];
export const firstBattleMap: BattleMap = {
width: 20,
height: 18,
@@ -480,6 +534,33 @@ export const fourthBattleMap: BattleMap = {
]
};
export const fifthBattleMap: BattleMap = {
width: 24,
height: 20,
terrain: [
['hill', 'hill', 'forest', 'plain', 'plain', 'road', 'road', 'plain', 'hill', 'hill', 'forest', 'plain', 'plain', 'fort', 'fort', 'plain', 'hill', 'hill', 'forest', 'forest', 'plain', 'plain', 'hill', 'hill'],
['hill', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'hill', 'plain', 'plain', 'plain', 'road', 'fort', 'fort', 'road', 'plain', 'hill', 'forest', 'plain', 'plain', 'plain', 'plain', 'hill'],
['plain', 'plain', 'forest', 'plain', 'road', 'plain', 'plain', 'forest', 'plain', 'plain', 'hill', 'plain', 'road', 'road', 'road', 'road', 'plain', 'plain', 'plain', 'forest', 'plain', 'hill', 'plain', 'plain'],
['plain', 'forest', 'forest', 'plain', 'road', 'plain', 'hill', 'forest', 'plain', 'plain', 'hill', 'plain', 'plain', 'road', 'plain', 'road', 'plain', 'hill', 'plain', 'forest', 'plain', 'plain', 'plain', 'plain'],
['plain', 'plain', 'forest', 'road', 'road', 'plain', 'hill', 'plain', 'plain', 'forest', 'plain', 'plain', 'river', 'river', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'forest', 'plain', 'plain', 'hill'],
['plain', 'plain', 'plain', 'road', 'plain', 'plain', 'plain', 'plain', 'forest', 'plain', 'plain', 'plain', 'river', 'river', 'plain', 'plain', 'road', 'plain', 'village', 'plain', 'forest', 'forest', 'plain', 'hill'],
['forest', 'plain', 'plain', 'road', 'plain', 'hill', 'hill', 'plain', 'forest', 'plain', 'plain', 'plain', 'plain', 'river', 'river', 'plain', 'road', 'plain', 'village', 'plain', 'plain', 'forest', 'plain', 'plain'],
['forest', 'plain', 'road', 'road', 'plain', 'plain', 'hill', 'plain', 'plain', 'plain', 'forest', 'plain', 'plain', 'river', 'river', 'plain', 'road', 'road', 'plain', 'plain', 'hill', 'plain', 'plain', 'plain'],
['plain', 'plain', 'road', 'plain', 'plain', 'forest', 'plain', 'plain', 'hill', 'plain', 'forest', 'plain', 'plain', 'plain', 'river', 'river', 'plain', 'road', 'plain', 'plain', 'hill', 'plain', 'forest', 'plain'],
['plain', 'road', 'road', 'plain', 'forest', 'forest', 'plain', 'plain', 'hill', 'plain', 'plain', 'road', 'plain', 'plain', 'plain', 'river', 'river', 'road', 'road', 'plain', 'plain', 'plain', 'forest', 'plain'],
['road', 'road', 'plain', 'plain', 'forest', 'plain', 'plain', 'hill', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'river', 'river', 'road', 'plain', 'plain', 'hill', 'plain', 'plain'],
['plain', 'road', 'plain', 'forest', 'plain', 'plain', 'hill', 'plain', 'plain', 'forest', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'river', 'river', 'plain', 'plain', 'hill', 'plain', 'plain'],
['plain', 'road', 'plain', 'forest', 'forest', 'plain', 'plain', 'plain', 'hill', 'plain', 'forest', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'river', 'river', 'plain', 'plain', 'plain', 'plain'],
['plain', 'road', 'plain', 'plain', 'plain', 'hill', 'plain', 'forest', 'plain', 'plain', 'plain', 'forest', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'river', 'river', 'plain', 'hill', 'plain'],
['camp', 'road', 'road', 'plain', 'plain', 'hill', 'plain', 'forest', 'forest', 'plain', 'plain', 'plain', 'hill', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'river', 'river', 'plain', 'plain'],
['camp', 'camp', 'road', 'plain', 'forest', 'plain', 'plain', 'plain', 'forest', 'plain', 'plain', 'hill', 'plain', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'river', 'river', 'plain'],
['plain', 'camp', 'road', 'road', 'plain', 'plain', 'forest', 'plain', 'plain', 'plain', 'hill', 'plain', 'plain', 'forest', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'river', 'plain'],
['plain', 'plain', 'camp', 'road', 'plain', 'forest', 'plain', 'plain', 'plain', 'hill', 'plain', 'plain', 'forest', 'forest', 'plain', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain', 'plain'],
['plain', 'plain', 'plain', 'road', 'road', 'plain', 'forest', 'forest', 'plain', 'plain', 'plain', 'hill', 'plain', 'forest', 'forest', 'plain', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'plain', 'plain'],
['plain', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'forest', 'forest', 'plain', 'plain', 'plain', 'hill', 'plain', 'plain', 'forest', 'plain', 'plain', 'plain', 'plain', 'road', 'road', 'plain', 'plain']
]
};
export const firstBattleUnits: UnitData[] = [
{
id: 'liu-bei',
@@ -1548,6 +1629,249 @@ export const fourthBattleUnits: UnitData[] = [
}
];
const fifthBattleAllyPositions: Record<string, { x: number; y: number }> = {
'liu-bei': { x: 2, y: 16 },
'guan-yu': { x: 3, y: 16 },
'zhang-fei': { x: 2, y: 17 }
};
export const fifthBattleUnits: UnitData[] = [
...firstBattleUnits
.filter((unit) => unit.faction === 'ally')
.map((unit) => placeScenarioUnit(unit, fifthBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
{
id: 'sishui-vanguard-a',
name: '서량 선봉',
faction: 'enemy',
className: '동탁 보병',
classKey: 'yellowTurban',
level: 5,
exp: 30,
hp: 32,
maxHp: 32,
attack: 10,
move: 3,
stats: { might: 68, intelligence: 38, leadership: 52, agility: 55, luck: 44 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 4 },
armor: { itemId: 'rebel-vest', level: 1, exp: 16 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 6,
y: 14
},
{
id: 'sishui-vanguard-b',
name: '서량 선봉',
faction: 'enemy',
className: '동탁 보병',
classKey: 'yellowTurban',
level: 5,
exp: 30,
hp: 32,
maxHp: 32,
attack: 10,
move: 3,
stats: { might: 68, intelligence: 37, leadership: 52, agility: 54, luck: 44 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 4 },
armor: { itemId: 'rebel-vest', level: 1, exp: 16 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 8,
y: 12
},
{
id: 'sishui-raider-a',
name: '산길 척후',
faction: 'enemy',
className: '척후병',
classKey: 'bandit',
level: 5,
exp: 32,
hp: 30,
maxHp: 30,
attack: 11,
move: 4,
stats: { might: 70, intelligence: 42, leadership: 48, agility: 66, luck: 52 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 8 },
armor: { itemId: 'rebel-vest', level: 1, exp: 16 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 5,
y: 9
},
{
id: 'sishui-archer-a',
name: '사수관 궁병',
faction: 'enemy',
className: '서량 궁병',
classKey: 'archer',
level: 5,
exp: 32,
hp: 27,
maxHp: 27,
attack: 11,
move: 3,
stats: { might: 63, intelligence: 50, leadership: 51, agility: 64, luck: 49 },
equipment: {
weapon: { itemId: 'short-bow', level: 2, exp: 8 },
armor: { itemId: 'cloth-armor', level: 1, exp: 16 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 10,
y: 10
},
{
id: 'sishui-cavalry-a',
name: '서량 기병',
faction: 'enemy',
className: '서량 경기병',
classKey: 'cavalry',
level: 6,
exp: 34,
hp: 36,
maxHp: 36,
attack: 12,
move: 5,
stats: { might: 74, intelligence: 38, leadership: 54, agility: 76, luck: 50 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 10 },
armor: { itemId: 'rebel-vest', level: 2, exp: 2 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 12,
y: 9
},
{
id: 'sishui-guard-a',
name: '관문 수비병',
faction: 'enemy',
className: '동탁 보병',
classKey: 'yellowTurban',
level: 6,
exp: 34,
hp: 35,
maxHp: 35,
attack: 11,
move: 3,
stats: { might: 72, intelligence: 40, leadership: 56, agility: 56, luck: 48 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 12 },
armor: { itemId: 'rebel-vest', level: 2, exp: 2 },
accessory: { itemId: 'yellow-scarf-charm', level: 1, exp: 0 }
},
x: 14,
y: 7
},
{
id: 'sishui-archer-b',
name: '관문 궁병',
faction: 'enemy',
className: '서량 궁병',
classKey: 'archer',
level: 6,
exp: 36,
hp: 28,
maxHp: 28,
attack: 12,
move: 3,
stats: { might: 65, intelligence: 52, leadership: 53, agility: 65, luck: 50 },
equipment: {
weapon: { itemId: 'short-bow', level: 2, exp: 12 },
armor: { itemId: 'cloth-armor', level: 1, exp: 18 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 16,
y: 6
},
{
id: 'sishui-cavalry-b',
name: '서량 기병',
faction: 'enemy',
className: '서량 경기병',
classKey: 'cavalry',
level: 6,
exp: 36,
hp: 37,
maxHp: 37,
attack: 12,
move: 5,
stats: { might: 75, intelligence: 39, leadership: 55, agility: 77, luck: 51 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 12 },
armor: { itemId: 'rebel-vest', level: 2, exp: 4 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 18,
y: 10
},
{
id: 'sishui-guard-b',
name: '관문 수비병',
faction: 'enemy',
className: '동탁 보병',
classKey: 'yellowTurban',
level: 6,
exp: 36,
hp: 36,
maxHp: 36,
attack: 11,
move: 3,
stats: { might: 73, intelligence: 40, leadership: 57, agility: 56, luck: 49 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 14 },
armor: { itemId: 'rebel-vest', level: 2, exp: 4 },
accessory: { itemId: 'yellow-scarf-charm', level: 1, exp: 0 }
},
x: 16,
y: 3
},
{
id: 'sishui-gate-guard',
name: '관문 친위병',
faction: 'enemy',
className: '동탁 보병',
classKey: 'yellowTurban',
level: 6,
exp: 38,
hp: 38,
maxHp: 38,
attack: 12,
move: 3,
stats: { might: 76, intelligence: 42, leadership: 60, agility: 57, luck: 50 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 18 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 8 },
accessory: { itemId: 'yellow-scarf-charm', level: 1, exp: 0 }
},
x: 14,
y: 1
},
{
id: 'sishui-leader-hu-zhen',
name: '호진',
faction: 'enemy',
className: '동탁 장수',
classKey: 'rebelLeader',
level: 7,
exp: 44,
hp: 50,
maxHp: 50,
attack: 14,
move: 3,
stats: { might: 80, intelligence: 55, leadership: 72, agility: 60, luck: 54 },
equipment: {
weapon: { itemId: 'leader-axe', level: 2, exp: 20 },
armor: { itemId: 'lamellar-armor', level: 2, exp: 10 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 15,
y: 1
}
];
export const firstBattleBonds: BattleBond[] = [
{
id: 'liu-bei__guan-yu',
@@ -1578,6 +1902,7 @@ export const firstBattleBonds: BattleBond[] = [
export const secondBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
export const thirdBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
export const fourthBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
export const fifthBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
return {