Add Jing Province entry chapter

This commit is contained in:
2026-06-23 07:42:11 +09:00
parent 302f0e0a76
commit d26a16d2a1
11 changed files with 1120 additions and 29 deletions

View File

@@ -1448,6 +1448,68 @@ export const twentySecondBattleVictoryPages: StoryPage[] = [
}
];
export const twentyThirdBattleIntroPages: StoryPage[] = [
{
id: 'twenty-third-jingzhou-cause',
bgm: 'militia-theme',
chapter: '형주 남부의 문',
background: 'story-militia',
speaker: '유비',
portrait: 'liuBei',
text: '적벽의 불길은 조조를 막았지만 백성이 기대어 살 땅은 아직 없소. 형주 남부의 군현을 힘으로 짓밟지 말고, 먼저 길과 민심을 열어야 하오.'
},
{
id: 'twenty-third-zhuge-plan',
bgm: 'battle-prep',
chapter: '군현을 여는 계책',
background: 'story-three-heroes',
speaker: '제갈량',
text: '영릉의 유도는 아직 마음을 정하지 못했고, 형도영은 길목을 막아 자신의 힘을 보이려 합니다. 그를 물리치되 백성을 다치게 하지 않으면 형주 남부가 움직일 것입니다.'
},
{
id: 'twenty-third-ma-liang-rumor',
bgm: 'story-dark',
chapter: '백미의 소문',
background: 'story-liu-bei',
speaker: '손건',
text: '형주 선비들 사이에 마량이라는 이름이 오갑니다. 눈썹이 희어 백미라 불리는 사람인데, 남부 군현의 민심과 길을 누구보다 잘 안다고 합니다.'
},
{
id: 'twenty-third-jingzhou-sortie',
bgm: 'battle-prep',
chapter: '형주 남부 진입전',
background: 'story-sortie',
speaker: '제갈량',
text: '형도영의 가병이 남부 길목과 마을을 막고 있습니다. 성급히 몰아붙이면 백성이 흩어지니, 전열을 세우고 마을을 지키며 길목을 확보하십시오.'
}
];
export const twentyThirdBattleVictoryPages: StoryPage[] = [
{
id: 'twenty-third-victory-southern-road',
bgm: 'militia-theme',
chapter: '남부 길목이 열리다',
background: 'story-sortie',
text: '형도영이 물러서자 남부 군현으로 이어지는 길이 열렸습니다. 유비군은 약탈 없이 마을을 안정시키며 적벽 이후 처음으로 머물 땅의 윤곽을 얻었습니다.'
},
{
id: 'twenty-third-ma-liang-joins',
bgm: 'battle-prep',
chapter: '마량의 합류',
background: 'story-militia',
speaker: '마량',
text: '주공께서 백성을 먼저 살피셨다는 말을 들었습니다. 형주 남부의 길과 사람을 잇는 일이라면, 제 작은 글과 말도 보탬이 될 것입니다.'
},
{
id: 'twenty-third-next-commandery',
bgm: 'story-dark',
chapter: '군현을 차례로',
background: 'story-three-heroes',
speaker: '제갈량',
text: '영릉의 문은 열렸지만 형주 남부 전체가 움직인 것은 아닙니다. 계양, 무릉, 장사까지 차례로 설득하고 지켜야 비로소 근거지가 됩니다.'
}
];
export const firstBattleMap: BattleMap = {
width: 20,
height: 18,
@@ -1725,6 +1787,12 @@ export const twentySecondBattleMap: BattleMap = {
terrain: createTwentySecondBattleTerrain()
};
export const twentyThirdBattleMap: BattleMap = {
width: 46,
height: 32,
terrain: createTwentyThirdBattleTerrain()
};
export const firstBattleUnits: UnitData[] = [
{
id: 'liu-bei',
@@ -3681,6 +3749,30 @@ export const zhugeRecruitUnits: UnitData[] = [
}
];
export const jingzhouRecruitUnits: UnitData[] = [
{
id: 'ma-liang',
name: '마량',
faction: 'ally',
className: '백미 책사',
classKey: 'strategist',
level: 11,
exp: 0,
hp: 30,
maxHp: 30,
attack: 8,
move: 4,
stats: { might: 36, intelligence: 92, leadership: 80, agility: 70, luck: 88 },
equipment: {
weapon: { itemId: 'white-feather-fan', level: 1, exp: 10 },
armor: { itemId: 'cloth-armor', level: 2, exp: 8 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 7,
y: 22
}
];
const eighthBattleAllyPositions: Record<string, { x: number; y: number }> = {
'liu-bei': { x: 2, y: 17 },
'guan-yu': { x: 3, y: 17 },
@@ -8600,6 +8692,384 @@ export const twentySecondBattleUnits: UnitData[] = [
}
];
const twentyThirdBattleAllyPositions: Record<string, { x: number; y: number }> = {
'liu-bei': { x: 4, y: 25 },
'guan-yu': { x: 6, y: 23 },
'zhang-fei': { x: 6, y: 27 },
'jian-yong': { x: 3, y: 28 },
'mi-zhu': { x: 5, y: 29 },
'sun-qian': { x: 8, y: 25 },
'zhao-yun': { x: 8, y: 22 },
'zhuge-liang': { x: 6, y: 24 }
};
export const twentyThirdBattleUnits: UnitData[] = [
...[
...firstBattleUnits.filter((unit) => unit.faction === 'ally'),
...xuzhouRecruitUnits,
...caoBreakRecruitUnits,
...liuBiaoRecruitUnits,
...zhugeRecruitUnits
].map((unit) => placeScenarioUnit(unit, twentyThirdBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
{
id: 'jing-south-scout-a',
name: '형주 남부 척후',
faction: 'enemy',
className: '남부 척후',
classKey: 'bandit',
level: 30,
exp: 48,
hp: 82,
maxHp: 82,
attack: 33,
move: 4,
stats: { might: 114, intelligence: 84, leadership: 90, agility: 110, luck: 76 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 4, exp: 18 },
armor: { itemId: 'rebel-vest', level: 4, exp: 8 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 13,
y: 24
},
{
id: 'jing-south-scout-b',
name: '형주 남부 척후',
faction: 'enemy',
className: '마을 척후',
classKey: 'bandit',
level: 30,
exp: 48,
hp: 82,
maxHp: 82,
attack: 33,
move: 4,
stats: { might: 114, intelligence: 84, leadership: 90, agility: 110, luck: 76 },
equipment: {
weapon: { itemId: 'yellow-turban-saber', level: 4, exp: 18 },
armor: { itemId: 'rebel-vest', level: 4, exp: 8 },
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
},
x: 14,
y: 28
},
{
id: 'jing-south-infantry-a',
name: '영릉 가병',
faction: 'enemy',
className: '영릉 가병',
classKey: 'yellowTurban',
level: 31,
exp: 50,
hp: 108,
maxHp: 108,
attack: 35,
move: 3,
stats: { might: 124, intelligence: 84, leadership: 104, agility: 92, luck: 76 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 30 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 18 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 18,
y: 22
},
{
id: 'jing-south-infantry-b',
name: '영릉 가병',
faction: 'enemy',
className: '마을 가병',
classKey: 'yellowTurban',
level: 31,
exp: 50,
hp: 108,
maxHp: 108,
attack: 35,
move: 3,
stats: { might: 124, intelligence: 84, leadership: 104, agility: 92, luck: 76 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 30 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 18 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 20,
y: 25
},
{
id: 'jing-south-infantry-c',
name: '영릉 가병',
faction: 'enemy',
className: '관문 가병',
classKey: 'yellowTurban',
level: 31,
exp: 52,
hp: 110,
maxHp: 110,
attack: 35,
move: 3,
stats: { might: 125, intelligence: 85, leadership: 106, agility: 92, luck: 76 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 34 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 20 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 28,
y: 18
},
{
id: 'jing-south-infantry-d',
name: '영릉 가병',
faction: 'enemy',
className: '관문 가병',
classKey: 'yellowTurban',
level: 31,
exp: 52,
hp: 110,
maxHp: 110,
attack: 35,
move: 3,
stats: { might: 125, intelligence: 85, leadership: 106, agility: 92, luck: 76 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 34 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 20 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 30,
y: 21
},
{
id: 'jing-south-archer-a',
name: '영릉 궁병',
faction: 'enemy',
className: '마을 궁병',
classKey: 'archer',
level: 30,
exp: 48,
hp: 80,
maxHp: 80,
attack: 34,
move: 3,
stats: { might: 108, intelligence: 98, leadership: 94, agility: 106, luck: 78 },
equipment: {
weapon: { itemId: 'short-bow', level: 4, exp: 26 },
armor: { itemId: 'cloth-armor', level: 4, exp: 16 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 18,
y: 18
},
{
id: 'jing-south-archer-b',
name: '영릉 궁병',
faction: 'enemy',
className: '언덕 궁병',
classKey: 'archer',
level: 31,
exp: 50,
hp: 82,
maxHp: 82,
attack: 35,
move: 3,
stats: { might: 110, intelligence: 100, leadership: 96, agility: 108, luck: 78 },
equipment: {
weapon: { itemId: 'short-bow', level: 4, exp: 32 },
armor: { itemId: 'cloth-armor', level: 4, exp: 20 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 25,
y: 16
},
{
id: 'jing-south-archer-c',
name: '영릉 궁병',
faction: 'enemy',
className: '성채 궁병',
classKey: 'archer',
level: 31,
exp: 52,
hp: 84,
maxHp: 84,
attack: 35,
move: 3,
stats: { might: 110, intelligence: 100, leadership: 96, agility: 108, luck: 78 },
equipment: {
weapon: { itemId: 'short-bow', level: 4, exp: 36 },
armor: { itemId: 'cloth-armor', level: 4, exp: 22 },
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
},
x: 36,
y: 14
},
{
id: 'jing-south-cavalry-a',
name: '영릉 기병',
faction: 'enemy',
className: '남부 기병',
classKey: 'cavalry',
level: 31,
exp: 52,
hp: 116,
maxHp: 116,
attack: 37,
move: 5,
stats: { might: 130, intelligence: 84, leadership: 104, agility: 122, luck: 78 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 40 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 24 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 17,
y: 29
},
{
id: 'jing-south-cavalry-b',
name: '영릉 기병',
faction: 'enemy',
className: '남부 기병',
classKey: 'cavalry',
level: 31,
exp: 52,
hp: 116,
maxHp: 116,
attack: 37,
move: 5,
stats: { might: 130, intelligence: 84, leadership: 104, agility: 122, luck: 78 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 40 },
armor: { itemId: 'lamellar-armor', level: 4, exp: 24 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 26,
y: 27
},
{
id: 'jing-south-cavalry-c',
name: '영릉 기병',
faction: 'enemy',
className: '성채 기병',
classKey: 'cavalry',
level: 32,
exp: 54,
hp: 120,
maxHp: 120,
attack: 38,
move: 5,
stats: { might: 132, intelligence: 86, leadership: 106, agility: 124, luck: 79 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 46 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 28 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 35,
y: 23
},
{
id: 'jing-south-guard-a',
name: '형도영 친위',
faction: 'enemy',
className: '영릉 친위',
classKey: 'yellowTurban',
level: 32,
exp: 56,
hp: 122,
maxHp: 122,
attack: 38,
move: 3,
stats: { might: 132, intelligence: 88, leadership: 112, agility: 96, luck: 80 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 52 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 34 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 38,
y: 16
},
{
id: 'jing-south-guard-b',
name: '형도영 친위',
faction: 'enemy',
className: '영릉 친위',
classKey: 'yellowTurban',
level: 32,
exp: 56,
hp: 122,
maxHp: 122,
attack: 38,
move: 3,
stats: { might: 132, intelligence: 88, leadership: 112, agility: 96, luck: 80 },
equipment: {
weapon: { itemId: 'iron-spear', level: 4, exp: 52 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 34 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 39,
y: 19
},
{
id: 'jing-south-strategist-a',
name: '영릉 문객',
faction: 'enemy',
className: '남부 문객',
classKey: 'archer',
level: 31,
exp: 52,
hp: 86,
maxHp: 86,
attack: 34,
move: 3,
stats: { might: 84, intelligence: 106, leadership: 100, agility: 92, luck: 80 },
equipment: {
weapon: { itemId: 'short-bow', level: 4, exp: 44 },
armor: { itemId: 'cloth-armor', level: 4, exp: 28 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 36,
y: 13
},
{
id: 'jing-south-strategist-b',
name: '영릉 문객',
faction: 'enemy',
className: '남부 문객',
classKey: 'archer',
level: 31,
exp: 52,
hp: 86,
maxHp: 86,
attack: 34,
move: 3,
stats: { might: 84, intelligence: 106, leadership: 100, agility: 92, luck: 80 },
equipment: {
weapon: { itemId: 'short-bow', level: 4, exp: 44 },
armor: { itemId: 'cloth-armor', level: 4, exp: 28 },
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
},
x: 40,
y: 14
},
{
id: 'jing-south-leader-xing-daorong',
name: '형도영',
faction: 'enemy',
className: '영릉 맹장',
classKey: 'rebelLeader',
level: 33,
exp: 58,
hp: 164,
maxHp: 164,
attack: 41,
move: 4,
stats: { might: 136, intelligence: 76, leadership: 118, agility: 96, luck: 80 },
equipment: {
weapon: { itemId: 'leader-axe', level: 4, exp: 58 },
armor: { itemId: 'reinforced-lamellar', level: 4, exp: 40 },
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
},
x: 42,
y: 17
}
];
export const firstBattleBonds: BattleBond[] = [
{
id: 'liu-bei__guan-yu',
@@ -8727,6 +9197,33 @@ export const zhugeRecruitBonds: BattleBond[] = [
}
];
export const jingzhouRecruitBonds: BattleBond[] = [
{
id: 'liu-bei__ma-liang',
unitIds: ['liu-bei', 'ma-liang'],
title: '백미의 조언',
level: 36,
exp: 0,
description: '유비의 인의와 마량의 형주 식견이 만나 남부 군현의 민심을 차분히 묶어 냅니다.'
},
{
id: 'zhuge-liang__ma-liang',
unitIds: ['zhuge-liang', 'ma-liang'],
title: '형주 문맥',
level: 34,
exp: 0,
description: '제갈량의 큰 계책과 마량의 현지 정보가 맞물려 형주 남부의 길과 사람을 읽어냅니다.'
},
{
id: 'sun-qian__ma-liang',
unitIds: ['sun-qian', 'ma-liang'],
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);
@@ -8754,6 +9251,7 @@ export const nineteenthBattleBonds: BattleBond[] = [...eighteenthBattleBonds].ma
export const twentiethBattleBonds: BattleBond[] = [...nineteenthBattleBonds].map(cloneBattleBondForScenario);
export const twentyFirstBattleBonds: BattleBond[] = [...twentiethBattleBonds].map(cloneBattleBondForScenario);
export const twentySecondBattleBonds: BattleBond[] = [...twentyFirstBattleBonds].map(cloneBattleBondForScenario);
export const twentyThirdBattleBonds: BattleBond[] = [...twentySecondBattleBonds].map(cloneBattleBondForScenario);
function createEighthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 22 }, (_, y) =>
@@ -9488,6 +9986,69 @@ function createTwentySecondBattleTerrain(): TerrainType[][] {
);
}
function createTwentyThirdBattleTerrain(): TerrainType[][] {
return Array.from({ length: 32 }, (_, y) =>
Array.from({ length: 46 }, (_, x): TerrainType => {
if ((x <= 4 && y >= 24 && y <= 30) || (x >= 5 && x <= 9 && y >= 27 && y <= 31)) {
return 'camp';
}
if ((x >= 38 && x <= 45 && y >= 14 && y <= 22) || (x >= 34 && x <= 38 && y >= 16 && y <= 20)) {
return 'fort';
}
if (
(x >= 12 && x <= 15 && y >= 23 && y <= 25) ||
(x >= 24 && x <= 27 && y >= 18 && y <= 20) ||
(x >= 33 && x <= 35 && y >= 15 && y <= 17)
) {
return 'village';
}
if (
(y === 25 && x >= 3 && x <= 18) ||
(y === 22 && x >= 16 && x <= 29) ||
(y === 18 && x >= 28 && x <= 40) ||
(x === 38 && y >= 14 && y <= 24)
) {
return 'road';
}
if (
(x >= 7 && x <= 18 && y === 29 - Math.floor(x / 2)) ||
(x >= 19 && x <= 36 && y === Math.floor(x / 2) + 8) ||
(x >= 31 && x <= 39 && y === 18)
) {
return 'road';
}
if ((x === 20 || x === 21) && y >= 0 && y <= 31) {
return 'river';
}
if ((x === 29 || x === 30) && y >= 0 && y <= 20) {
return 'river';
}
if ((x === 25 || x === 26) && y >= 24 && y <= 31) {
return 'river';
}
if (
(x >= 4 && x <= 15 && y >= 8 && y <= 19) ||
(x >= 15 && x <= 21 && y >= 25 && y <= 31) ||
(x <= 9 && y <= 8) ||
(x >= 31 && x <= 44 && y <= 10)
) {
return 'forest';
}
if (
(x >= 10 && x <= 19 && y >= 2 && y <= 7) ||
(x >= 30 && x <= 39 && y >= 24 && y <= 31) ||
(x >= 37 && x <= 45 && y >= 4 && y <= 9)
) {
return 'hill';
}
if ((x <= 1 && y <= 15) || (x >= 44 && y <= 12) || (x >= 44 && y >= 24)) {
return 'cliff';
}
return 'plain';
})
);
}
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
return {
...cloneUnitForScenario(unit),