Add Changban refuge sortie chapter
This commit is contained in:
95
src/assets/images/battle/nineteenth-battle-map.svg
Normal file
95
src/assets/images/battle/nineteenth-battle-map.svg
Normal file
@@ -0,0 +1,95 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="3800" height="2800" viewBox="0 0 3800 2800">
|
||||
<defs>
|
||||
<filter id="grain">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.014" numOctaves="5" seed="19"/>
|
||||
<feColorMatrix type="saturate" values="0.46"/>
|
||||
<feBlend mode="multiply" in2="SourceGraphic"/>
|
||||
</filter>
|
||||
<linearGradient id="plain" x1="0" x2="1" y1="0" y2="1">
|
||||
<stop offset="0" stop-color="#b7a163"/>
|
||||
<stop offset="0.52" stop-color="#847748"/>
|
||||
<stop offset="1" stop-color="#5f6944"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="river" x1="0" x2="1">
|
||||
<stop offset="0" stop-color="#17314d"/>
|
||||
<stop offset="0.5" stop-color="#2c738f"/>
|
||||
<stop offset="1" stop-color="#152c45"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="road" x1="0" x2="1">
|
||||
<stop offset="0" stop-color="#d8c17a"/>
|
||||
<stop offset="0.55" stop-color="#a88550"/>
|
||||
<stop offset="1" stop-color="#78603c"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="camp" x1="0" x2="1" y1="0" y2="1">
|
||||
<stop offset="0" stop-color="#6f7254"/>
|
||||
<stop offset="1" stop-color="#3f5360"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="torch" cx="0.5" cy="0.5" r="0.55">
|
||||
<stop offset="0" stop-color="#f1c66b" stop-opacity="0.7"/>
|
||||
<stop offset="0.42" stop-color="#d66f2e" stop-opacity="0.44"/>
|
||||
<stop offset="1" stop-color="#251a12" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect width="3800" height="2800" fill="url(#plain)"/>
|
||||
<g filter="url(#grain)" opacity="0.5">
|
||||
<rect width="3800" height="2800" fill="#8e7f52"/>
|
||||
</g>
|
||||
<path d="M1550 -160 C1470 330 1600 670 1530 1010 C1460 1330 1510 1540 1460 1780" fill="none" stroke="url(#river)" stroke-width="230" opacity="0.95"/>
|
||||
<path d="M2380 650 C2310 1040 2470 1410 2380 1780 C2310 2110 2390 2460 2300 2960" fill="none" stroke="url(#river)" stroke-width="220" opacity="0.94"/>
|
||||
<path d="M280 2220 C720 2200 1080 2210 1400 2190 C1680 2180 1830 1920 2270 1900 C2630 1880 3000 1750 3500 1710" fill="none" stroke="url(#road)" stroke-width="190" stroke-linecap="round" opacity="0.76"/>
|
||||
<path d="M520 2470 C820 2320 1020 2160 1320 2050 C1670 1920 2040 1890 2380 1830 C2700 1780 3020 1680 3330 1440" fill="none" stroke="#b99055" stroke-width="112" stroke-linecap="round" opacity="0.62"/>
|
||||
<path d="M3050 1300 C3150 1500 3150 1900 3060 2140" fill="none" stroke="url(#road)" stroke-width="130" stroke-linecap="round" opacity="0.62"/>
|
||||
<g opacity="0.9">
|
||||
<path d="M520 820 C860 720 1220 860 1460 1110 C1230 1340 810 1290 560 1160 C470 1050 460 930 520 820Z" fill="#2e5639"/>
|
||||
<path d="M1660 2020 C1910 1900 2240 2020 2340 2280 C2140 2530 1760 2570 1520 2380Z" fill="#2f5d39"/>
|
||||
<path d="M60 60 C420 10 780 120 960 370 C680 550 300 530 50 330Z" fill="#315d3e"/>
|
||||
<path d="M2650 90 C3020 20 3510 120 3800 410 L3800 880 C3440 920 3040 770 2700 560Z" fill="#2d5637"/>
|
||||
</g>
|
||||
<g opacity="0.72">
|
||||
<ellipse cx="1180" cy="380" rx="390" ry="190" fill="#5d553b"/>
|
||||
<ellipse cx="2850" cy="2500" rx="520" ry="210" fill="#615b3e"/>
|
||||
<ellipse cx="3270" cy="520" rx="450" ry="190" fill="#60563a"/>
|
||||
</g>
|
||||
<g opacity="0.9">
|
||||
<rect x="40" y="2120" width="360" height="560" rx="26" fill="url(#camp)"/>
|
||||
<rect x="420" y="2320" width="360" height="330" rx="24" fill="url(#camp)" opacity="0.86"/>
|
||||
<path d="M80 2220 L210 2110 L340 2220Z" fill="#c58b3b"/>
|
||||
<path d="M480 2390 L610 2290 L740 2390Z" fill="#c58b3b"/>
|
||||
<rect x="3020" y="1360" width="600" height="720" rx="24" fill="#5a5541"/>
|
||||
<path d="M3080 1410 L3580 1410 L3580 2030 L3080 2030Z" fill="none" stroke="#d7b56b" stroke-width="18" opacity="0.52"/>
|
||||
</g>
|
||||
<g opacity="0.75">
|
||||
<rect x="820" y="2030" width="260" height="210" rx="18" fill="#8b6c3c"/>
|
||||
<path d="M810 2035 L950 1900 L1100 2035Z" fill="#c58a3a"/>
|
||||
<rect x="2020" y="1730" width="270" height="220" rx="18" fill="#806237"/>
|
||||
<path d="M2010 1735 L2150 1600 L2310 1735Z" fill="#c58a3a"/>
|
||||
</g>
|
||||
<g opacity="0.58">
|
||||
<rect x="1450" y="1740" width="270" height="120" rx="18" fill="#73664a"/>
|
||||
<rect x="2260" y="1880" width="260" height="120" rx="18" fill="#73664a"/>
|
||||
<path d="M1450 1790 H1720 M2260 1940 H2520" stroke="#e6d093" stroke-width="18" opacity="0.55"/>
|
||||
</g>
|
||||
<g opacity="0.64">
|
||||
<circle cx="1150" cy="2150" r="120" fill="url(#torch)"/>
|
||||
<circle cx="1820" cy="1900" r="110" fill="url(#torch)"/>
|
||||
<circle cx="2780" cy="1700" r="130" fill="url(#torch)"/>
|
||||
<circle cx="3300" cy="1550" r="105" fill="url(#torch)"/>
|
||||
</g>
|
||||
<g opacity="0.22" fill="#e7d59a">
|
||||
<circle cx="650" cy="2190" r="18"/>
|
||||
<circle cx="720" cy="2220" r="14"/>
|
||||
<circle cx="780" cy="2185" r="16"/>
|
||||
<circle cx="1260" cy="2100" r="16"/>
|
||||
<circle cx="1350" cy="2070" r="14"/>
|
||||
<circle cx="1880" cy="1900" r="15"/>
|
||||
<circle cx="1970" cy="1870" r="13"/>
|
||||
</g>
|
||||
<g opacity="0.2">
|
||||
<path d="M0 0H3800V2800H0Z" fill="none" stroke="#f2d386" stroke-width="28"/>
|
||||
<path d="M150 150H3650V2650H150Z" fill="none" stroke="#111820" stroke-width="7"/>
|
||||
</g>
|
||||
<g opacity="0.14" stroke="#121a18" stroke-width="8">
|
||||
<path d="M0 500H3800M0 1000H3800M0 1500H3800M0 2000H3800M0 2500H3800"/>
|
||||
<path d="M500 0V2800M1000 0V2800M1500 0V2800M2000 0V2800M2500 0V2800M3000 0V2800M3500 0V2800"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
@@ -27,6 +27,10 @@ import {
|
||||
ninthBattleMap,
|
||||
ninthBattleUnits,
|
||||
ninthBattleVictoryPages,
|
||||
nineteenthBattleBonds,
|
||||
nineteenthBattleMap,
|
||||
nineteenthBattleUnits,
|
||||
nineteenthBattleVictoryPages,
|
||||
tenthBattleBonds,
|
||||
tenthBattleMap,
|
||||
tenthBattleUnits,
|
||||
@@ -95,7 +99,8 @@ export type BattleScenarioId =
|
||||
| 'fifteenth-battle-yuan-refuge-road'
|
||||
| 'sixteenth-battle-liu-biao-refuge'
|
||||
| 'seventeenth-battle-wolong-visit-road'
|
||||
| 'eighteenth-battle-bowang-ambush';
|
||||
| 'eighteenth-battle-bowang-ambush'
|
||||
| 'nineteenth-battle-changban-refuge';
|
||||
|
||||
export type BattleObjectiveKind = 'defeat-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
|
||||
|
||||
@@ -1088,6 +1093,69 @@ export const eighteenthBattleScenario: BattleScenarioDefinition = {
|
||||
nextCampScene: 'CampScene'
|
||||
};
|
||||
|
||||
export const nineteenthBattleScenario: BattleScenarioDefinition = {
|
||||
id: 'nineteenth-battle-changban-refuge',
|
||||
title: '장판파 피난로',
|
||||
victoryConditionLabel: '조순 퇴각',
|
||||
defeatConditionLabel: '유비 또는 조운 퇴각',
|
||||
openingObjectiveLines: [
|
||||
'조조군 호표기가 피난 행렬을 따라 장판파로 들이칩니다. 백성을 버리지 않으려면 남쪽 피난로와 다리목을 동시에 지켜야 합니다.',
|
||||
'조운은 넓은 길을 오가며 흩어진 병력을 모을 수 있고, 장비는 다리목을 막아 추격 기병을 늦추기 좋습니다. 제갈량과 손건은 전후 강동 사절 명분을 정리합니다.',
|
||||
'조순을 퇴각시키고 유비와 조운을 지키십시오. 피난민 마을을 확보하면 다음 강동 사절 준비가 안정됩니다.'
|
||||
],
|
||||
map: nineteenthBattleMap,
|
||||
units: nineteenthBattleUnits,
|
||||
bonds: nineteenthBattleBonds,
|
||||
mapTextureKey: 'battle-map-nineteenth',
|
||||
leaderUnitId: 'changban-leader-cao-chun',
|
||||
quickVictoryTurnLimit: 28,
|
||||
baseVictoryGold: 2220,
|
||||
objectives: [
|
||||
{
|
||||
id: 'leader',
|
||||
kind: 'defeat-leader',
|
||||
label: '조순 퇴각',
|
||||
rewardGold: 1440,
|
||||
unitId: 'changban-leader-cao-chun'
|
||||
},
|
||||
{
|
||||
id: 'liu-bei',
|
||||
kind: 'keep-unit-alive',
|
||||
label: '유비 생존',
|
||||
rewardGold: 480,
|
||||
unitId: 'liu-bei'
|
||||
},
|
||||
{
|
||||
id: 'zhao-yun',
|
||||
kind: 'keep-unit-alive',
|
||||
label: '조운 생존',
|
||||
rewardGold: 620,
|
||||
unitId: 'zhao-yun'
|
||||
},
|
||||
{
|
||||
id: 'refugee-village',
|
||||
kind: 'secure-terrain',
|
||||
label: '피난민 마을 확보',
|
||||
rewardGold: 820,
|
||||
terrain: 'village'
|
||||
},
|
||||
{
|
||||
id: 'quick',
|
||||
kind: 'quick-victory',
|
||||
label: '28턴 이내 승리',
|
||||
rewardGold: 620,
|
||||
maxTurn: 28
|
||||
}
|
||||
],
|
||||
defeatConditions: [
|
||||
{ kind: 'unit-defeated', unitId: 'liu-bei' },
|
||||
{ kind: 'unit-defeated', unitId: 'zhao-yun' }
|
||||
],
|
||||
itemRewards: ['콩 7', '상처약 5', '탁주 2', '피난로 지도 +1', '강동 풍문 +1'],
|
||||
victoryPages: nineteenthBattleVictoryPages,
|
||||
nextCampScene: 'CampScene'
|
||||
};
|
||||
|
||||
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
|
||||
|
||||
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
|
||||
@@ -1108,7 +1176,8 @@ export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition>
|
||||
'fifteenth-battle-yuan-refuge-road': fifteenthBattleScenario,
|
||||
'sixteenth-battle-liu-biao-refuge': sixteenthBattleScenario,
|
||||
'seventeenth-battle-wolong-visit-road': seventeenthBattleScenario,
|
||||
'eighteenth-battle-bowang-ambush': eighteenthBattleScenario
|
||||
'eighteenth-battle-bowang-ambush': eighteenthBattleScenario,
|
||||
'nineteenth-battle-changban-refuge': nineteenthBattleScenario
|
||||
};
|
||||
|
||||
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
fourteenthBattleScenario,
|
||||
fourthBattleScenario,
|
||||
ninthBattleScenario,
|
||||
nineteenthBattleScenario,
|
||||
secondBattleScenario,
|
||||
seventhBattleScenario,
|
||||
sixthBattleScenario,
|
||||
@@ -38,6 +39,8 @@ import {
|
||||
fourthBattleVictoryPages,
|
||||
ninthBattleIntroPages,
|
||||
ninthBattleVictoryPages,
|
||||
nineteenthBattleIntroPages,
|
||||
nineteenthBattleVictoryPages,
|
||||
secondBattleIntroPages,
|
||||
secondBattleVictoryPages,
|
||||
seventhBattleIntroPages,
|
||||
@@ -249,13 +252,24 @@ const sortieFlows: Record<string, SortieFlow> = {
|
||||
},
|
||||
[eighteenthBattleScenario.id]: {
|
||||
afterBattleId: eighteenthBattleScenario.id,
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '강동으로 부는 바람',
|
||||
eyebrow: '다음 전장',
|
||||
title: nineteenthBattleScenario.title,
|
||||
description:
|
||||
'박망파에서 조조군 선봉을 늦춘 유비군은 더 큰 남하를 막기 위해 강동과 손잡을 길을 찾아야 합니다. 다음 흐름은 장판파와 강동 사절, 그리고 적벽대전으로 이어집니다.',
|
||||
rewardHint: '다음 장: 장판파와 강동 사절 준비 중',
|
||||
pages: eighteenthBattleVictoryPages,
|
||||
unavailableNotice: '장판파와 강동 사절 장은 다음 작업에서 이어집니다. 군영에서 제갈량의 책략과 장수들의 출전 구성을 정비하십시오.'
|
||||
'박망파에서 조조군 선봉을 늦췄지만 대군의 남하는 계속됩니다. 신야의 백성을 데리고 장판파 피난로를 열어야 강동 사절로 이어질 시간을 벌 수 있습니다.',
|
||||
rewardHint: `예상 보상: ${nineteenthBattleScenario.title} 개방 / 장판파 피난로 확보`,
|
||||
nextBattleId: nineteenthBattleScenario.id,
|
||||
campaignStep: 'nineteenth-battle',
|
||||
pages: [...eighteenthBattleVictoryPages, ...nineteenthBattleIntroPages]
|
||||
},
|
||||
[nineteenthBattleScenario.id]: {
|
||||
afterBattleId: nineteenthBattleScenario.id,
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '강동 사절 준비',
|
||||
description:
|
||||
'장판파에서 피난로를 열어 백성과 군을 다시 모았습니다. 이제 제갈량과 손건은 강동으로 보낼 말과 증거를 정리하고, 손권과 마주할 준비를 해야 합니다.',
|
||||
rewardHint: '다음 장: 강동 사절과 적벽대전 준비 중',
|
||||
pages: nineteenthBattleVictoryPages,
|
||||
unavailableNotice: '강동 사절과 적벽대전 장은 다음 작업에서 이어집니다. 군영에서 출전 후보, 공명, 보급을 정비하십시오.'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1197,6 +1197,69 @@ export const eighteenthBattleVictoryPages: StoryPage[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const nineteenthBattleIntroPages: StoryPage[] = [
|
||||
{
|
||||
id: 'nineteenth-cao-army-south',
|
||||
bgm: 'story-dark',
|
||||
chapter: '조조의 남하',
|
||||
background: 'story-militia',
|
||||
speaker: '손건',
|
||||
text: '박망파에서 시간을 벌었지만 조조의 대군은 멈추지 않았습니다. 신야의 백성들이 남쪽으로 몰리고, 장판파 길목에는 추격 기병이 먼저 닿고 있습니다.'
|
||||
},
|
||||
{
|
||||
id: 'nineteenth-zhao-yun-rescue',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '백마의 구원',
|
||||
background: 'story-three-heroes',
|
||||
speaker: '조운',
|
||||
text: '주공, 피난 행렬이 흩어지면 백성도 군도 모두 잃습니다. 제가 앞뒤를 오가며 길을 묶겠습니다. 다리와 마을을 먼저 지켜 주십시오.'
|
||||
},
|
||||
{
|
||||
id: 'nineteenth-zhang-fei-bridge',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '장판교의 호령',
|
||||
background: 'story-sortie',
|
||||
speaker: '장비',
|
||||
portrait: 'zhangFei',
|
||||
text: '형님은 백성을 이끌고 남쪽 길을 보시오. 뒤쫓는 놈들은 제가 다리목에서 한 번 꺾어 놓겠습니다. 다만 누가 옆을 받쳐 줄지는 잘 골라야겠소!'
|
||||
},
|
||||
{
|
||||
id: 'nineteenth-changban-sortie',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '장판파 피난로',
|
||||
background: 'story-liu-bei',
|
||||
speaker: '유비',
|
||||
portrait: 'liuBei',
|
||||
text: '오늘의 싸움은 이기는 것만으로 끝나지 않소. 백성이 지나갈 길을 열고, 조운과 익덕이 무너지지 않게 서로 받쳐야 하오. 함께할 무장을 신중히 정합시다.'
|
||||
}
|
||||
];
|
||||
|
||||
export const nineteenthBattleVictoryPages: StoryPage[] = [
|
||||
{
|
||||
id: 'nineteenth-victory-refuge-road',
|
||||
bgm: 'militia-theme',
|
||||
chapter: '피난로가 열리다',
|
||||
background: 'story-militia',
|
||||
text: '장판파의 먼지 속에서 유비군은 피난 행렬을 가까스로 남쪽 길로 흘려보냈습니다. 조운의 창과 장비의 호령이 무너질 뻔한 길목을 붙들었습니다.'
|
||||
},
|
||||
{
|
||||
id: 'nineteenth-zhao-yun-returns',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '흩어진 깃발을 모아',
|
||||
background: 'story-three-heroes',
|
||||
speaker: '조운',
|
||||
text: '흩어진 병사와 백성을 모두 되찾지는 못했습니다. 그러나 주공의 깃발이 뒤돌아보았기에 사람들은 다시 모일 곳을 알게 되었습니다.'
|
||||
},
|
||||
{
|
||||
id: 'nineteenth-jiangdong-envoy',
|
||||
bgm: 'story-dark',
|
||||
chapter: '강동으로 보낼 사절',
|
||||
background: 'story-liu-bei',
|
||||
speaker: '제갈량',
|
||||
text: '조조의 남하는 이제 강동도 외면할 수 없습니다. 장판파에서 지켜낸 백성의 길과 조조군의 속도를 함께 전하면, 손권과 마주 앉을 명분이 생깁니다.'
|
||||
}
|
||||
];
|
||||
|
||||
export const firstBattleMap: BattleMap = {
|
||||
width: 20,
|
||||
height: 18,
|
||||
@@ -1450,6 +1513,12 @@ export const eighteenthBattleMap: BattleMap = {
|
||||
terrain: createEighteenthBattleTerrain()
|
||||
};
|
||||
|
||||
export const nineteenthBattleMap: BattleMap = {
|
||||
width: 38,
|
||||
height: 28,
|
||||
terrain: createNineteenthBattleTerrain()
|
||||
};
|
||||
|
||||
export const firstBattleUnits: UnitData[] = [
|
||||
{
|
||||
id: 'liu-bei',
|
||||
@@ -6792,6 +6861,384 @@ export const eighteenthBattleUnits: UnitData[] = [
|
||||
}
|
||||
];
|
||||
|
||||
const nineteenthBattleAllyPositions: Record<string, { x: number; y: number }> = {
|
||||
'liu-bei': { x: 4, y: 22 },
|
||||
'guan-yu': { x: 5, y: 20 },
|
||||
'zhang-fei': { x: 6, y: 22 },
|
||||
'jian-yong': { x: 3, y: 23 },
|
||||
'mi-zhu': { x: 4, y: 24 },
|
||||
'sun-qian': { x: 6, y: 24 },
|
||||
'zhao-yun': { x: 8, y: 20 },
|
||||
'zhuge-liang': { x: 5, y: 23 }
|
||||
};
|
||||
|
||||
export const nineteenthBattleUnits: UnitData[] = [
|
||||
...[
|
||||
...firstBattleUnits.filter((unit) => unit.faction === 'ally'),
|
||||
...xuzhouRecruitUnits,
|
||||
...caoBreakRecruitUnits,
|
||||
...liuBiaoRecruitUnits,
|
||||
...zhugeRecruitUnits
|
||||
].map((unit) => placeScenarioUnit(unit, nineteenthBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
|
||||
{
|
||||
id: 'changban-scout-a',
|
||||
name: '조조군 척후',
|
||||
faction: 'enemy',
|
||||
className: '추격 척후',
|
||||
classKey: 'bandit',
|
||||
level: 22,
|
||||
exp: 30,
|
||||
hp: 66,
|
||||
maxHp: 66,
|
||||
attack: 25,
|
||||
move: 4,
|
||||
stats: { might: 98, intelligence: 72, leadership: 78, agility: 98, luck: 68 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 3, exp: 22 },
|
||||
armor: { itemId: 'rebel-vest', level: 2, exp: 70 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 13,
|
||||
y: 21
|
||||
},
|
||||
{
|
||||
id: 'changban-scout-b',
|
||||
name: '조조군 척후',
|
||||
faction: 'enemy',
|
||||
className: '측면 척후',
|
||||
classKey: 'bandit',
|
||||
level: 22,
|
||||
exp: 30,
|
||||
hp: 66,
|
||||
maxHp: 66,
|
||||
attack: 25,
|
||||
move: 4,
|
||||
stats: { might: 98, intelligence: 72, leadership: 78, agility: 98, luck: 68 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 3, exp: 22 },
|
||||
armor: { itemId: 'rebel-vest', level: 2, exp: 70 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 12,
|
||||
y: 24
|
||||
},
|
||||
{
|
||||
id: 'changban-cavalry-a',
|
||||
name: '호표 추격기',
|
||||
faction: 'enemy',
|
||||
className: '조조 경기병',
|
||||
classKey: 'cavalry',
|
||||
level: 23,
|
||||
exp: 32,
|
||||
hp: 88,
|
||||
maxHp: 88,
|
||||
attack: 30,
|
||||
move: 5,
|
||||
stats: { might: 112, intelligence: 72, leadership: 90, agility: 106, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 28 },
|
||||
armor: { itemId: 'lamellar-armor', level: 3, exp: 4 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 16,
|
||||
y: 18
|
||||
},
|
||||
{
|
||||
id: 'changban-cavalry-b',
|
||||
name: '호표 추격기',
|
||||
faction: 'enemy',
|
||||
className: '조조 경기병',
|
||||
classKey: 'cavalry',
|
||||
level: 23,
|
||||
exp: 32,
|
||||
hp: 88,
|
||||
maxHp: 88,
|
||||
attack: 30,
|
||||
move: 5,
|
||||
stats: { might: 112, intelligence: 72, leadership: 90, agility: 106, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 28 },
|
||||
armor: { itemId: 'lamellar-armor', level: 3, exp: 4 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 17,
|
||||
y: 22
|
||||
},
|
||||
{
|
||||
id: 'changban-cavalry-c',
|
||||
name: '조조군 선봉기',
|
||||
faction: 'enemy',
|
||||
className: '선봉 기병',
|
||||
classKey: 'cavalry',
|
||||
level: 24,
|
||||
exp: 34,
|
||||
hp: 92,
|
||||
maxHp: 92,
|
||||
attack: 31,
|
||||
move: 5,
|
||||
stats: { might: 114, intelligence: 74, leadership: 92, agility: 108, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 34 },
|
||||
armor: { itemId: 'lamellar-armor', level: 3, exp: 10 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 22,
|
||||
y: 17
|
||||
},
|
||||
{
|
||||
id: 'changban-cavalry-d',
|
||||
name: '조조군 선봉기',
|
||||
faction: 'enemy',
|
||||
className: '선봉 기병',
|
||||
classKey: 'cavalry',
|
||||
level: 24,
|
||||
exp: 34,
|
||||
hp: 92,
|
||||
maxHp: 92,
|
||||
attack: 31,
|
||||
move: 5,
|
||||
stats: { might: 114, intelligence: 74, leadership: 92, agility: 108, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 34 },
|
||||
armor: { itemId: 'lamellar-armor', level: 3, exp: 10 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 25,
|
||||
y: 21
|
||||
},
|
||||
{
|
||||
id: 'changban-infantry-a',
|
||||
name: '조조 보병',
|
||||
faction: 'enemy',
|
||||
className: '추격 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 22,
|
||||
exp: 30,
|
||||
hp: 82,
|
||||
maxHp: 82,
|
||||
attack: 27,
|
||||
move: 3,
|
||||
stats: { might: 106, intelligence: 74, leadership: 92, agility: 78, luck: 68 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 26 },
|
||||
armor: { itemId: 'lamellar-armor', level: 3, exp: 2 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 18,
|
||||
y: 16
|
||||
},
|
||||
{
|
||||
id: 'changban-infantry-b',
|
||||
name: '조조 보병',
|
||||
faction: 'enemy',
|
||||
className: '추격 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 22,
|
||||
exp: 30,
|
||||
hp: 82,
|
||||
maxHp: 82,
|
||||
attack: 27,
|
||||
move: 3,
|
||||
stats: { might: 106, intelligence: 74, leadership: 92, agility: 78, luck: 68 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 26 },
|
||||
armor: { itemId: 'lamellar-armor', level: 3, exp: 2 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 20,
|
||||
y: 20
|
||||
},
|
||||
{
|
||||
id: 'changban-infantry-c',
|
||||
name: '장판 보병',
|
||||
faction: 'enemy',
|
||||
className: '다리목 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 23,
|
||||
exp: 32,
|
||||
hp: 86,
|
||||
maxHp: 86,
|
||||
attack: 28,
|
||||
move: 3,
|
||||
stats: { might: 108, intelligence: 76, leadership: 94, agility: 80, luck: 69 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 30 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 3, exp: 6 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 26,
|
||||
y: 16
|
||||
},
|
||||
{
|
||||
id: 'changban-infantry-d',
|
||||
name: '장판 보병',
|
||||
faction: 'enemy',
|
||||
className: '다리목 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 23,
|
||||
exp: 32,
|
||||
hp: 86,
|
||||
maxHp: 86,
|
||||
attack: 28,
|
||||
move: 3,
|
||||
stats: { might: 108, intelligence: 76, leadership: 94, agility: 80, luck: 69 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 30 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 3, exp: 6 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 28,
|
||||
y: 20
|
||||
},
|
||||
{
|
||||
id: 'changban-archer-a',
|
||||
name: '조조 궁병',
|
||||
faction: 'enemy',
|
||||
className: '언덕 궁병',
|
||||
classKey: 'archer',
|
||||
level: 22,
|
||||
exp: 30,
|
||||
hp: 64,
|
||||
maxHp: 64,
|
||||
attack: 27,
|
||||
move: 3,
|
||||
stats: { might: 94, intelligence: 86, leadership: 84, agility: 92, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 3, exp: 24 },
|
||||
armor: { itemId: 'cloth-armor', level: 3, exp: 0 },
|
||||
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
|
||||
},
|
||||
x: 21,
|
||||
y: 14
|
||||
},
|
||||
{
|
||||
id: 'changban-archer-b',
|
||||
name: '조조 궁병',
|
||||
faction: 'enemy',
|
||||
className: '강변 궁병',
|
||||
classKey: 'archer',
|
||||
level: 22,
|
||||
exp: 30,
|
||||
hp: 64,
|
||||
maxHp: 64,
|
||||
attack: 27,
|
||||
move: 3,
|
||||
stats: { might: 94, intelligence: 86, leadership: 84, agility: 92, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 3, exp: 24 },
|
||||
armor: { itemId: 'cloth-armor', level: 3, exp: 0 },
|
||||
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
|
||||
},
|
||||
x: 24,
|
||||
y: 23
|
||||
},
|
||||
{
|
||||
id: 'changban-archer-c',
|
||||
name: '조조 궁병',
|
||||
faction: 'enemy',
|
||||
className: '후방 궁병',
|
||||
classKey: 'archer',
|
||||
level: 23,
|
||||
exp: 32,
|
||||
hp: 66,
|
||||
maxHp: 66,
|
||||
attack: 28,
|
||||
move: 3,
|
||||
stats: { might: 96, intelligence: 88, leadership: 86, agility: 94, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 3, exp: 30 },
|
||||
armor: { itemId: 'cloth-armor', level: 3, exp: 4 },
|
||||
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
|
||||
},
|
||||
x: 31,
|
||||
y: 18
|
||||
},
|
||||
{
|
||||
id: 'changban-guard-a',
|
||||
name: '조조 친위',
|
||||
faction: 'enemy',
|
||||
className: '호표 친위',
|
||||
classKey: 'yellowTurban',
|
||||
level: 24,
|
||||
exp: 34,
|
||||
hp: 94,
|
||||
maxHp: 94,
|
||||
attack: 30,
|
||||
move: 3,
|
||||
stats: { might: 114, intelligence: 78, leadership: 102, agility: 84, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 38 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 3, exp: 14 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 33,
|
||||
y: 16
|
||||
},
|
||||
{
|
||||
id: 'changban-guard-b',
|
||||
name: '조조 친위',
|
||||
faction: 'enemy',
|
||||
className: '호표 친위',
|
||||
classKey: 'yellowTurban',
|
||||
level: 24,
|
||||
exp: 34,
|
||||
hp: 94,
|
||||
maxHp: 94,
|
||||
attack: 30,
|
||||
move: 3,
|
||||
stats: { might: 114, intelligence: 78, leadership: 102, agility: 84, luck: 70 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 3, exp: 38 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 3, exp: 14 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 33,
|
||||
y: 20
|
||||
},
|
||||
{
|
||||
id: 'changban-strategist-a',
|
||||
name: '조조군 군리',
|
||||
faction: 'enemy',
|
||||
className: '군리',
|
||||
classKey: 'archer',
|
||||
level: 23,
|
||||
exp: 32,
|
||||
hp: 68,
|
||||
maxHp: 68,
|
||||
attack: 27,
|
||||
move: 3,
|
||||
stats: { might: 76, intelligence: 96, leadership: 88, agility: 84, luck: 72 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 3, exp: 34 },
|
||||
armor: { itemId: 'cloth-armor', level: 3, exp: 8 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 31,
|
||||
y: 14
|
||||
},
|
||||
{
|
||||
id: 'changban-leader-cao-chun',
|
||||
name: '조순',
|
||||
faction: 'enemy',
|
||||
className: '호표기장',
|
||||
classKey: 'rebelLeader',
|
||||
level: 25,
|
||||
exp: 38,
|
||||
hp: 126,
|
||||
maxHp: 126,
|
||||
attack: 33,
|
||||
move: 5,
|
||||
stats: { might: 118, intelligence: 82, leadership: 110, agility: 96, luck: 74 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'leader-axe', level: 3, exp: 52 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 3, exp: 22 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 35,
|
||||
y: 18
|
||||
}
|
||||
];
|
||||
|
||||
export const firstBattleBonds: BattleBond[] = [
|
||||
{
|
||||
id: 'liu-bei__guan-yu',
|
||||
@@ -6942,6 +7389,7 @@ export const seventeenthBattleBonds: BattleBond[] = sixteenthBattleBonds.map(clo
|
||||
export const eighteenthBattleBonds: BattleBond[] = [...sixteenthBattleBonds, ...zhugeRecruitBonds].map(
|
||||
cloneBattleBondForScenario
|
||||
);
|
||||
export const nineteenthBattleBonds: BattleBond[] = [...eighteenthBattleBonds].map(cloneBattleBondForScenario);
|
||||
|
||||
function createEighthBattleTerrain(): TerrainType[][] {
|
||||
return Array.from({ length: 22 }, (_, y) =>
|
||||
@@ -7450,6 +7898,62 @@ function createEighteenthBattleTerrain(): TerrainType[][] {
|
||||
);
|
||||
}
|
||||
|
||||
function createNineteenthBattleTerrain(): TerrainType[][] {
|
||||
return Array.from({ length: 28 }, (_, y) =>
|
||||
Array.from({ length: 38 }, (_, x): TerrainType => {
|
||||
if ((x <= 3 && y >= 21 && y <= 26) || (x >= 4 && x <= 7 && y >= 23 && y <= 26)) {
|
||||
return 'camp';
|
||||
}
|
||||
if ((x >= 29 && x <= 36 && y >= 15 && y <= 22) || (x >= 32 && x <= 37 && y >= 12 && y <= 14)) {
|
||||
return 'fort';
|
||||
}
|
||||
if ((x >= 8 && x <= 10 && y >= 20 && y <= 22) || (x >= 20 && x <= 22 && y >= 17 && y <= 19)) {
|
||||
return 'village';
|
||||
}
|
||||
if ((x === 15 || x === 16) && y >= 0 && y <= 17) {
|
||||
return 'river';
|
||||
}
|
||||
if ((x === 23 || x === 24) && y >= 7 && y <= 27) {
|
||||
return 'river';
|
||||
}
|
||||
if (
|
||||
(y === 22 && x >= 3 && x <= 14) ||
|
||||
(y === 19 && x >= 13 && x <= 23) ||
|
||||
(y === 17 && x >= 23 && x <= 35) ||
|
||||
(x === 31 && y >= 13 && y <= 21)
|
||||
) {
|
||||
return 'road';
|
||||
}
|
||||
if (
|
||||
(x >= 4 && x <= 14 && y === 25 - Math.floor(x / 2)) ||
|
||||
(x >= 16 && x <= 30 && y === Math.floor(x / 2) + 8) ||
|
||||
(x >= 7 && x <= 13 && y === 22)
|
||||
) {
|
||||
return 'road';
|
||||
}
|
||||
if (
|
||||
(x >= 5 && x <= 14 && y >= 9 && y <= 18) ||
|
||||
(x >= 16 && x <= 22 && y >= 20 && y <= 27) ||
|
||||
(x <= 9 && y <= 8) ||
|
||||
(x >= 26 && x <= 35 && y <= 9)
|
||||
) {
|
||||
return 'forest';
|
||||
}
|
||||
if (
|
||||
(x >= 9 && x <= 14 && y >= 2 && y <= 6) ||
|
||||
(x >= 25 && x <= 31 && y >= 22 && y <= 27) ||
|
||||
(x >= 29 && x <= 37 && y >= 3 && y <= 7)
|
||||
) {
|
||||
return 'hill';
|
||||
}
|
||||
if ((x <= 1 && y <= 13) || (x >= 36 && y <= 11) || (x >= 36 && y >= 23)) {
|
||||
return 'cliff';
|
||||
}
|
||||
return 'plain';
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
|
||||
return {
|
||||
...cloneUnitForScenario(unit),
|
||||
|
||||
@@ -171,7 +171,24 @@ const unitTexture: Record<string, string> = {
|
||||
'bowang-guard-a': 'unit-rebel',
|
||||
'bowang-guard-b': 'unit-rebel',
|
||||
'bowang-strategist-a': 'unit-rebel-archer',
|
||||
'bowang-leader-xiahou-dun': 'unit-rebel-leader'
|
||||
'bowang-leader-xiahou-dun': 'unit-rebel-leader',
|
||||
'changban-scout-a': 'unit-rebel',
|
||||
'changban-scout-b': 'unit-rebel',
|
||||
'changban-cavalry-a': 'unit-rebel-cavalry',
|
||||
'changban-cavalry-b': 'unit-rebel-cavalry',
|
||||
'changban-cavalry-c': 'unit-rebel-cavalry',
|
||||
'changban-cavalry-d': 'unit-rebel-cavalry',
|
||||
'changban-infantry-a': 'unit-rebel',
|
||||
'changban-infantry-b': 'unit-rebel',
|
||||
'changban-infantry-c': 'unit-rebel',
|
||||
'changban-infantry-d': 'unit-rebel',
|
||||
'changban-archer-a': 'unit-rebel-archer',
|
||||
'changban-archer-b': 'unit-rebel-archer',
|
||||
'changban-archer-c': 'unit-rebel-archer',
|
||||
'changban-guard-a': 'unit-rebel',
|
||||
'changban-guard-b': 'unit-rebel',
|
||||
'changban-strategist-a': 'unit-rebel-archer',
|
||||
'changban-leader-cao-chun': 'unit-rebel-leader'
|
||||
};
|
||||
|
||||
const unitTextureByClass: Partial<Record<UnitClassKey, string>> = {
|
||||
@@ -798,7 +815,24 @@ const enemyAiByUnitId: Record<string, EnemyAiBehavior> = {
|
||||
'bowang-guard-a': 'guard',
|
||||
'bowang-guard-b': 'guard',
|
||||
'bowang-strategist-a': 'hold',
|
||||
'bowang-leader-xiahou-dun': 'guard'
|
||||
'bowang-leader-xiahou-dun': 'guard',
|
||||
'changban-scout-a': 'aggressive',
|
||||
'changban-scout-b': 'aggressive',
|
||||
'changban-cavalry-a': 'aggressive',
|
||||
'changban-cavalry-b': 'aggressive',
|
||||
'changban-cavalry-c': 'aggressive',
|
||||
'changban-cavalry-d': 'aggressive',
|
||||
'changban-infantry-a': 'guard',
|
||||
'changban-infantry-b': 'guard',
|
||||
'changban-infantry-c': 'guard',
|
||||
'changban-infantry-d': 'guard',
|
||||
'changban-archer-a': 'hold',
|
||||
'changban-archer-b': 'hold',
|
||||
'changban-archer-c': 'hold',
|
||||
'changban-guard-a': 'guard',
|
||||
'changban-guard-b': 'guard',
|
||||
'changban-strategist-a': 'hold',
|
||||
'changban-leader-cao-chun': 'guard'
|
||||
};
|
||||
|
||||
const defaultEnemyAiByClass: Partial<Record<UnitClassKey, EnemyAiBehavior>> = {
|
||||
|
||||
@@ -8,6 +8,7 @@ import firstBattleMapUrl from '../../assets/images/battle/first-battle-map.png';
|
||||
import fourteenthBattleMapUrl from '../../assets/images/battle/fourteenth-battle-map.svg';
|
||||
import fourthBattleMapUrl from '../../assets/images/battle/fourth-battle-map.svg';
|
||||
import ninthBattleMapUrl from '../../assets/images/battle/ninth-battle-map.svg';
|
||||
import nineteenthBattleMapUrl from '../../assets/images/battle/nineteenth-battle-map.svg';
|
||||
import secondBattleMapUrl from '../../assets/images/battle/second-battle-map.svg';
|
||||
import seventhBattleMapUrl from '../../assets/images/battle/seventh-battle-map.svg';
|
||||
import sixthBattleMapUrl from '../../assets/images/battle/sixth-battle-map.svg';
|
||||
@@ -94,6 +95,7 @@ export class BootScene extends Phaser.Scene {
|
||||
this.load.image('battle-map-sixteenth', sixteenthBattleMapUrl);
|
||||
this.load.image('battle-map-seventeenth', seventeenthBattleMapUrl);
|
||||
this.load.image('battle-map-eighteenth', eighteenthBattleMapUrl);
|
||||
this.load.image('battle-map-nineteenth', nineteenthBattleMapUrl);
|
||||
this.load.image('portrait-liu-bei', liuBeiPortraitUrl);
|
||||
this.load.image('portrait-guan-yu', guanYuPortraitUrl);
|
||||
this.load.image('portrait-zhang-fei', zhangFeiPortraitUrl);
|
||||
|
||||
@@ -281,7 +281,7 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
|
||||
title: '적벽대전',
|
||||
period: '강동의 바람',
|
||||
description: '제갈량의 계책과 강동의 힘이 맞물려 조조의 대군을 막아서는 큰 전환 장입니다.',
|
||||
battleIds: ['eighteenth-battle-bowang-ambush'],
|
||||
battleIds: ['eighteenth-battle-bowang-ambush', 'nineteenth-battle-changban-refuge'],
|
||||
nextHints: ['강동 사절', '화공 준비', '조조 남하']
|
||||
},
|
||||
{
|
||||
@@ -320,7 +320,8 @@ const campBattleIds = {
|
||||
fifteenth: 'fifteenth-battle-yuan-refuge-road',
|
||||
sixteenth: 'sixteenth-battle-liu-biao-refuge',
|
||||
seventeenth: 'seventeenth-battle-wolong-visit-road',
|
||||
eighteenth: 'eighteenth-battle-bowang-ambush'
|
||||
eighteenth: 'eighteenth-battle-bowang-ambush',
|
||||
nineteenth: 'nineteenth-battle-changban-refuge'
|
||||
} as const;
|
||||
|
||||
const requiredSortieUnitIds = new Set(['liu-bei']);
|
||||
@@ -511,6 +512,18 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
|
||||
{ unitId: 'sun-qian', reason: '강동 사절로 이어질 명분과 전후 보고를 정리합니다.' }
|
||||
],
|
||||
note: '제갈량의 첫 실전 계책입니다. 책략 담당을 포함해 전열, 기동, 보급 중 무엇을 남길지 결정해야 합니다.'
|
||||
},
|
||||
'nineteenth-battle-changban-refuge': {
|
||||
maxUnits: 6,
|
||||
recommended: [
|
||||
{ unitId: 'liu-bei', reason: '피난 행렬의 중심이며 패배 조건입니다.' },
|
||||
{ unitId: 'zhao-yun', reason: '피난로를 오가며 흩어진 병력과 백성을 붙잡는 핵심 기동 장수입니다.' },
|
||||
{ unitId: 'zhang-fei', reason: '장판교와 좁은 길목에서 추격 기병을 늦추는 역할입니다.' },
|
||||
{ unitId: 'zhuge-liang', reason: '피난로 판단과 강동 사절 명분을 전투 뒤로 연결합니다.' },
|
||||
{ unitId: 'guan-yu', reason: '다리목 전열과 친위 보병을 받아낼 안정적인 전열입니다.' },
|
||||
{ unitId: 'sun-qian', reason: '강동에 보낼 기록과 외교 명분을 정리합니다.' }
|
||||
],
|
||||
note: '장판파는 출전 제한보다 역할이 많은 전장입니다. 조운과 장비를 중심으로 기동, 전열, 책략, 보급 중 무엇을 우선할지 직접 선택하십시오.'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2026,6 +2039,87 @@ const campDialogues: CampDialogue[] = [
|
||||
rewardExp: 9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'liu-zhao-after-changban-refuge',
|
||||
title: '백마가 지킨 길',
|
||||
availableAfterBattleIds: [campBattleIds.nineteenth],
|
||||
unitIds: ['liu-bei', 'zhao-yun'],
|
||||
bondId: 'liu-bei__zhao-yun',
|
||||
rewardExp: 30,
|
||||
lines: [
|
||||
'유비: 자룡, 장판파의 먼지 속에서도 그대의 창은 백성을 향해 길을 열었소.',
|
||||
'조운: 주공께서 백성을 버리지 않으셨기에 저도 물러서지 않을 수 있었습니다.',
|
||||
'유비: 오늘의 공은 전공보다 무겁소. 다음 길에서도 그 마음을 함께 지켜 주시오.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'entrust-refugee-guard',
|
||||
label: '피난 행렬 호위를 맡긴다',
|
||||
response: '조운은 말없이 창을 세웠고, 유비군의 피난길은 더 단단한 호위를 얻었다.',
|
||||
rewardExp: 12
|
||||
},
|
||||
{
|
||||
id: 'praise-white-horse-loyalty',
|
||||
label: '백마의 의리를 칭찬한다',
|
||||
response: '주공의 말에 조운은 깊이 고개를 숙였다. 흩어진 군영 안에서도 두 사람의 신뢰가 또렷해졌다.',
|
||||
rewardExp: 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'zhang-zhuge-after-changban-refuge',
|
||||
title: '다리목의 호령',
|
||||
availableAfterBattleIds: [campBattleIds.nineteenth],
|
||||
unitIds: ['zhang-fei', 'zhuge-liang'],
|
||||
bondId: 'zhang-fei__zhuge-liang',
|
||||
rewardExp: 22,
|
||||
lines: [
|
||||
'장비: 군사, 다리목에서 한 번 호통치니 놈들이 눈치를 보더군. 이번엔 계책이 아니라 목청이 이긴 것 아니오?',
|
||||
'제갈량: 익덕 장군의 호령이 먹힌 것은 설 곳을 정확히 골랐기 때문입니다. 그 자리까지 가는 길도 계책의 일부입니다.',
|
||||
'장비: 하하, 그렇다면 다음에도 어디서 소리치면 되는지만 알려 주시오. 나머지는 내 창이 알아서 하겠소.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'fix-bridge-ambush-signals',
|
||||
label: '다리목 신호를 정한다',
|
||||
response: '제갈량은 장비가 나서야 할 순간을 짧은 깃발 신호로 정했고, 장비는 복잡한 설명보다 마음에 든다고 웃었다.',
|
||||
rewardExp: 9
|
||||
},
|
||||
{
|
||||
id: 'let-roar-lead',
|
||||
label: '호령을 먼저 세운다',
|
||||
response: '장비의 호령이 적의 발을 묶고, 제갈량의 손짓이 그 뒤를 받치는 새 호흡이 생겼다.',
|
||||
rewardExp: 8
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'liu-zhuge-after-changban-refuge',
|
||||
title: '피난길과 강동',
|
||||
availableAfterBattleIds: [campBattleIds.nineteenth],
|
||||
unitIds: ['liu-bei', 'zhuge-liang'],
|
||||
bondId: 'liu-bei__zhuge-liang',
|
||||
rewardExp: 28,
|
||||
lines: [
|
||||
'유비: 오늘 지킨 것은 길 하나였지만, 그 길 위의 사람들은 천하보다 가벼울 수 없었소.',
|
||||
'제갈량: 바로 그 점이 강동에 전할 말입니다. 조조의 힘만이 아니라 주공이 무엇을 지키려 하는지를 보여야 합니다.',
|
||||
'유비: 그렇다면 손권에게 갈 말도 이 피난길에서 시작해야겠구려.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'write-refugee-road-record',
|
||||
label: '피난로 기록을 남긴다',
|
||||
response: '제갈량은 장판파의 피난로와 조조군의 추격 속도를 함께 적어 강동 사절 문서의 근거로 삼았다.',
|
||||
rewardExp: 11
|
||||
},
|
||||
{
|
||||
id: 'align-people-and-strategy',
|
||||
label: '백성과 대계를 함께 본다',
|
||||
response: '유비와 제갈량은 백성을 지키는 마음과 천하를 보는 계책이 서로 멀지 않음을 확인했다.',
|
||||
rewardExp: 10
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -2235,6 +2329,66 @@ const campVisits: CampVisitDefinition[] = [
|
||||
itemRewards: ['탁주 1']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'changban-refugee-camp',
|
||||
title: '장판파 피난민 수습',
|
||||
location: '남쪽 피난 진영',
|
||||
availableAfterBattleIds: [campBattleIds.nineteenth],
|
||||
bondId: 'liu-bei__zhao-yun',
|
||||
description: '장판파를 벗어난 피난민을 돌보며 흩어진 병사와 민심을 다시 모읍니다.',
|
||||
lines: [
|
||||
'조운: 피난민 중에는 가족을 잃고 주저앉은 사람도 많습니다. 군이 먼저 손을 내밀어야 길이 이어집니다.',
|
||||
'유비: 우리가 지킨 길이 사람을 버리는 길이 되어서는 안 되오. 군량을 나누되, 다음 행군도 버틸 수 있게 살피시오.',
|
||||
'남쪽 진영에는 먼지와 상처가 가득하지만, 유비군의 깃발 아래 다시 줄이 만들어집니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'share-field-medicine',
|
||||
label: '상처 입은 피난민을 돌본다',
|
||||
response: '조운은 약을 나누며 질서를 세웠고, 피난민들은 유비군이 자신들을 버리지 않았음을 기억했다.',
|
||||
bondExp: 22,
|
||||
itemRewards: ['민심 기록 1']
|
||||
},
|
||||
{
|
||||
id: 'gather-scattered-soldiers',
|
||||
label: '흩어진 병사를 모은다',
|
||||
response: '장판파에서 흩어진 병사들이 하나둘 돌아왔고, 군영은 다음 이동을 버틸 힘을 되찾았다.',
|
||||
bondExp: 18,
|
||||
gold: 140,
|
||||
itemRewards: ['콩 2']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'jiangdong-envoy-after-changban',
|
||||
title: '강동 사절 문서',
|
||||
location: '피난 진영 막사',
|
||||
availableAfterBattleIds: [campBattleIds.nineteenth],
|
||||
bondId: 'sun-qian__zhuge-liang',
|
||||
description: '제갈량과 손건이 장판파 전황을 강동에 보낼 문서로 정리합니다.',
|
||||
lines: [
|
||||
'손건: 장판파의 일은 처참하지만, 강동이 조조의 남하를 실감할 증거이기도 합니다.',
|
||||
'제갈량: 두려움만 적으면 사람은 굳고, 계산만 적으면 마음이 움직이지 않습니다. 주공이 지킨 길을 함께 써야 합니다.',
|
||||
'작은 막사 안에서 피난로 지도와 조조군의 진격 보고가 하나의 문서로 묶입니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'write-sun-quan-brief',
|
||||
label: '손권에게 보낼 요지를 쓴다',
|
||||
response: '손건은 제갈량의 형세 판단을 짧은 문장으로 정리했고, 강동 사절의 첫 말이 뚜렷해졌다.',
|
||||
bondExp: 20,
|
||||
itemRewards: ['강동 풍문 1']
|
||||
},
|
||||
{
|
||||
id: 'prepare-envoy-supplies',
|
||||
label: '사절 보급을 챙긴다',
|
||||
response: '강동까지 갈 사절단의 노자와 약품을 따로 묶어 두었다. 긴 길을 위한 준비가 조금 더 단단해졌다.',
|
||||
bondExp: 16,
|
||||
gold: 180,
|
||||
itemRewards: ['상처약 1', '탁주 1']
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -2320,7 +2474,7 @@ export class CampScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
if (battleId === campBattleIds.seventeenth || battleId === campBattleIds.eighteenth) {
|
||||
if (battleId === campBattleIds.seventeenth || battleId === campBattleIds.eighteenth || battleId === campBattleIds.nineteenth) {
|
||||
this.campaign = ensureCampaignRosterUnits(
|
||||
[...xuzhouRecruitUnits, ...caoBreakRecruitUnits, ...liuBiaoRecruitUnits, ...zhugeRecruitUnits],
|
||||
[...xuzhouRecruitBonds, ...caoBreakRecruitBonds, ...liuBiaoRecruitBonds, ...zhugeRecruitBonds]
|
||||
@@ -2377,6 +2531,9 @@ export class CampScene extends Phaser.Scene {
|
||||
|
||||
private currentCampTitle() {
|
||||
const battleId = this.currentCampBattleId();
|
||||
if (battleId === campBattleIds.nineteenth) {
|
||||
return '장판파 돌파 후 군영';
|
||||
}
|
||||
if (battleId === campBattleIds.eighteenth) {
|
||||
return '박망파 승전 후 군영';
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
fourteenthBattleScenario,
|
||||
fourthBattleScenario,
|
||||
ninthBattleScenario,
|
||||
nineteenthBattleScenario,
|
||||
secondBattleScenario,
|
||||
seventhBattleScenario,
|
||||
sixthBattleScenario,
|
||||
@@ -335,7 +336,8 @@ export class TitleScene extends Phaser.Scene {
|
||||
campaign.step === 'fifteenth-camp' ||
|
||||
campaign.step === 'sixteenth-camp' ||
|
||||
campaign.step === 'seventeenth-camp' ||
|
||||
campaign.step === 'eighteenth-camp'
|
||||
campaign.step === 'eighteenth-camp' ||
|
||||
campaign.step === 'nineteenth-camp'
|
||||
) {
|
||||
this.scene.start('CampScene');
|
||||
return;
|
||||
@@ -431,6 +433,11 @@ export class TitleScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
if (campaign.step === 'nineteenth-battle') {
|
||||
this.scene.start('BattleScene', { battleId: nineteenthBattleScenario.id });
|
||||
return;
|
||||
}
|
||||
|
||||
if (campaign.step === 'first-victory-story') {
|
||||
this.scene.start('StoryScene', { pages: firstBattleVictoryPages, nextScene: 'TitleScene' });
|
||||
return;
|
||||
|
||||
@@ -77,7 +77,9 @@ export type CampaignStep =
|
||||
| 'seventeenth-battle'
|
||||
| 'seventeenth-camp'
|
||||
| 'eighteenth-battle'
|
||||
| 'eighteenth-camp';
|
||||
| 'eighteenth-camp'
|
||||
| 'nineteenth-battle'
|
||||
| 'nineteenth-camp';
|
||||
|
||||
export type CampaignUnitProgressSnapshot = {
|
||||
unitId: string;
|
||||
@@ -157,7 +159,8 @@ const campaignBattleSteps: Record<string, { victory: CampaignStep; retry: Campai
|
||||
'fifteenth-battle-yuan-refuge-road': { victory: 'fifteenth-camp', retry: 'fifteenth-battle' },
|
||||
'sixteenth-battle-liu-biao-refuge': { victory: 'sixteenth-camp', retry: 'sixteenth-battle' },
|
||||
'seventeenth-battle-wolong-visit-road': { victory: 'seventeenth-camp', retry: 'seventeenth-battle' },
|
||||
'eighteenth-battle-bowang-ambush': { victory: 'eighteenth-camp', retry: 'eighteenth-battle' }
|
||||
'eighteenth-battle-bowang-ambush': { victory: 'eighteenth-camp', retry: 'eighteenth-battle' },
|
||||
'nineteenth-battle-changban-refuge': { victory: 'nineteenth-camp', retry: 'nineteenth-battle' }
|
||||
};
|
||||
|
||||
export type CampaignSaveSlotSummary = {
|
||||
|
||||
Reference in New Issue
Block a user