Add Wolong recruitment chapter
This commit is contained in:
@@ -76,6 +76,15 @@ export const itemCatalog: Record<string, ItemDefinition> = {
|
||||
attackBonus: 6,
|
||||
effects: ['단독으로 돌파할 때 피해 보너스']
|
||||
},
|
||||
'white-feather-fan': {
|
||||
id: 'white-feather-fan',
|
||||
name: '백우선',
|
||||
slot: 'weapon',
|
||||
rank: 'treasure',
|
||||
description: '제갈량이 책략을 펼칠 때 드는 흰 깃털 부채. 전장의 바람과 마음을 읽는다.',
|
||||
strategyBonus: 5,
|
||||
effects: ['책략 피해와 공명 지원 경험치 보정']
|
||||
},
|
||||
'yellow-turban-saber': {
|
||||
id: 'yellow-turban-saber',
|
||||
name: '황건도',
|
||||
|
||||
@@ -60,6 +60,10 @@ import {
|
||||
sixteenthBattleMap,
|
||||
sixteenthBattleUnits,
|
||||
sixteenthBattleVictoryPages,
|
||||
seventeenthBattleBonds,
|
||||
seventeenthBattleMap,
|
||||
seventeenthBattleUnits,
|
||||
seventeenthBattleVictoryPages,
|
||||
thirdBattleMap,
|
||||
thirdBattleUnits,
|
||||
thirdBattleVictoryPages,
|
||||
@@ -85,7 +89,8 @@ export type BattleScenarioId =
|
||||
| 'thirteenth-battle-xiapi-final'
|
||||
| 'fourteenth-battle-cao-break'
|
||||
| 'fifteenth-battle-yuan-refuge-road'
|
||||
| 'sixteenth-battle-liu-biao-refuge';
|
||||
| 'sixteenth-battle-liu-biao-refuge'
|
||||
| 'seventeenth-battle-wolong-visit-road';
|
||||
|
||||
export type BattleObjectiveKind = 'defeat-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
|
||||
|
||||
@@ -972,6 +977,59 @@ export const sixteenthBattleScenario: BattleScenarioDefinition = {
|
||||
nextCampScene: 'CampScene'
|
||||
};
|
||||
|
||||
export const seventeenthBattleScenario: BattleScenarioDefinition = {
|
||||
id: 'seventeenth-battle-wolong-visit-road',
|
||||
title: '융중 방문로',
|
||||
victoryConditionLabel: '채순 격파',
|
||||
defeatConditionLabel: '유비 퇴각',
|
||||
openingObjectiveLines: [
|
||||
'형주에서 모은 와룡의 단서를 따라 유비군은 융중으로 향합니다. 그러나 산길에는 채씨 가병이 먼저 길목을 잡고 있습니다.',
|
||||
'숲과 언덕, 좁은 물길이 많은 전장입니다. 조운의 기동력과 책사들의 후원을 살려 산길의 궁병과 감시병을 끊어 내십시오.',
|
||||
'채순을 격파하고 융중 초가로 향하는 길을 확보하십시오. 26턴 안에 승리하면 제갈량 영입의 명분과 보급을 더 단단히 챙길 수 있습니다.'
|
||||
],
|
||||
map: seventeenthBattleMap,
|
||||
units: seventeenthBattleUnits,
|
||||
bonds: seventeenthBattleBonds,
|
||||
mapTextureKey: 'battle-map-seventeenth',
|
||||
leaderUnitId: 'wolong-road-leader-cai-xun',
|
||||
quickVictoryTurnLimit: 26,
|
||||
baseVictoryGold: 1960,
|
||||
objectives: [
|
||||
{
|
||||
id: 'leader',
|
||||
kind: 'defeat-leader',
|
||||
label: '채순 격파',
|
||||
rewardGold: 1260,
|
||||
unitId: 'wolong-road-leader-cai-xun'
|
||||
},
|
||||
{
|
||||
id: 'liu-bei',
|
||||
kind: 'keep-unit-alive',
|
||||
label: '유비 생존',
|
||||
rewardGold: 440,
|
||||
unitId: 'liu-bei'
|
||||
},
|
||||
{
|
||||
id: 'longzhong-cottage',
|
||||
kind: 'secure-terrain',
|
||||
label: '융중 초가 길 확보',
|
||||
rewardGold: 720,
|
||||
terrain: 'village'
|
||||
},
|
||||
{
|
||||
id: 'quick',
|
||||
kind: 'quick-victory',
|
||||
label: '26턴 이내 승리',
|
||||
rewardGold: 560,
|
||||
maxTurn: 26
|
||||
}
|
||||
],
|
||||
defeatConditions: [{ kind: 'unit-defeated', unitId: 'liu-bei' }],
|
||||
itemRewards: ['콩 6', '상처약 4', '탁주 2', '와룡의 서찰 +1'],
|
||||
victoryPages: seventeenthBattleVictoryPages,
|
||||
nextCampScene: 'CampScene'
|
||||
};
|
||||
|
||||
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
|
||||
|
||||
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
|
||||
@@ -990,7 +1048,8 @@ export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition>
|
||||
'thirteenth-battle-xiapi-final': thirteenthBattleScenario,
|
||||
'fourteenth-battle-cao-break': fourteenthBattleScenario,
|
||||
'fifteenth-battle-yuan-refuge-road': fifteenthBattleScenario,
|
||||
'sixteenth-battle-liu-biao-refuge': sixteenthBattleScenario
|
||||
'sixteenth-battle-liu-biao-refuge': sixteenthBattleScenario,
|
||||
'seventeenth-battle-wolong-visit-road': seventeenthBattleScenario
|
||||
};
|
||||
|
||||
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
seventhBattleScenario,
|
||||
sixthBattleScenario,
|
||||
sixteenthBattleScenario,
|
||||
seventeenthBattleScenario,
|
||||
tenthBattleScenario,
|
||||
thirteenthBattleScenario,
|
||||
twelfthBattleScenario,
|
||||
@@ -42,6 +43,8 @@ import {
|
||||
sixthBattleVictoryPages,
|
||||
sixteenthBattleIntroPages,
|
||||
sixteenthBattleVictoryPages,
|
||||
seventeenthBattleIntroPages,
|
||||
seventeenthBattleVictoryPages,
|
||||
tenthBattleIntroPages,
|
||||
tenthBattleVictoryPages,
|
||||
thirteenthBattleIntroPages,
|
||||
@@ -221,13 +224,24 @@ const sortieFlows: Record<string, SortieFlow> = {
|
||||
},
|
||||
[sixteenthBattleScenario.id]: {
|
||||
afterBattleId: sixteenthBattleScenario.id,
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '제갈량을 향한 길',
|
||||
eyebrow: '다음 전장',
|
||||
title: seventeenthBattleScenario.title,
|
||||
description:
|
||||
'유표에게 의탁한 유비군은 형주에서 숨을 돌리지만, 손님으로 머무는 것만으로 천하의 길을 열 수는 없습니다. 다음 흐름은 와룡의 이름을 찾아가는 제갈량 영입 장으로 이어집니다.',
|
||||
rewardHint: '다음 장: 제갈량 영입 준비 중',
|
||||
pages: sixteenthBattleVictoryPages,
|
||||
unavailableNotice: '제갈량 영입 장은 다음 작업에서 이어집니다. 군영에서 새로 합류한 조운과 공명도를 다지고 출전 구성을 정비하십시오.'
|
||||
'유표에게 의탁한 유비군은 형주에서 숨을 돌리지만, 손님으로 머무는 것만으로 천하의 길을 열 수는 없습니다. 형주에서 모은 와룡의 단서를 따라 융중으로 향해야 합니다.',
|
||||
rewardHint: `예상 보상: ${seventeenthBattleScenario.title} 개방 / 제갈량 영입`,
|
||||
nextBattleId: seventeenthBattleScenario.id,
|
||||
campaignStep: 'seventeenth-battle',
|
||||
pages: [...sixteenthBattleVictoryPages, ...seventeenthBattleIntroPages]
|
||||
},
|
||||
[seventeenthBattleScenario.id]: {
|
||||
afterBattleId: seventeenthBattleScenario.id,
|
||||
eyebrow: '다음 장 준비',
|
||||
title: '적벽으로 향하는 바람',
|
||||
description:
|
||||
'제갈량이 합류하며 유비군은 비로소 천하의 큰 판을 바라보게 됩니다. 다음 흐름은 형주의 불안과 강동의 바람이 맞물리는 적벽대전 준비로 이어집니다.',
|
||||
rewardHint: '다음 장: 적벽대전 준비 중',
|
||||
pages: seventeenthBattleVictoryPages,
|
||||
unavailableNotice: '적벽대전 장은 다음 작업에서 이어집니다. 군영에서 제갈량과의 공명도를 다지고 출전 구성을 정비하십시오.'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1069,6 +1069,70 @@ export const sixteenthBattleVictoryPages: StoryPage[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const seventeenthBattleIntroPages: StoryPage[] = [
|
||||
{
|
||||
id: 'seventeenth-wolong-clue-gathered',
|
||||
bgm: 'story-dark',
|
||||
chapter: '와룡의 단서',
|
||||
background: 'story-militia',
|
||||
speaker: '손건',
|
||||
text: '형주 선비들의 말이 하나로 모입니다. 융중의 초가에 머무는 제갈공명, 사람들은 그를 와룡이라 부릅니다. 주공께서 직접 찾아가 예를 다한다면 길이 열릴지도 모릅니다.'
|
||||
},
|
||||
{
|
||||
id: 'seventeenth-liu-bei-third-visit',
|
||||
bgm: 'militia-theme',
|
||||
chapter: '삼고초려',
|
||||
background: 'story-liu-bei',
|
||||
speaker: '유비',
|
||||
portrait: 'liuBei',
|
||||
text: '한 번 찾아가 만나지 못했다 하여 뜻이 얕아지는 것은 아니오. 천하를 구할 계책을 구하려면, 내가 먼저 몸을 낮추어 그 문 앞에 서야 하오.'
|
||||
},
|
||||
{
|
||||
id: 'seventeenth-road-to-longzhong',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '융중 방문로',
|
||||
background: 'story-three-heroes',
|
||||
speaker: '조운',
|
||||
text: '융중으로 향하는 산길에 수상한 가병들이 숨어 있습니다. 주공의 방문이 형주 안의 권신들에게 알려진 듯합니다. 길을 먼저 정리하겠습니다.'
|
||||
},
|
||||
{
|
||||
id: 'seventeenth-longzhong-sortie',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '와룡을 찾아',
|
||||
background: 'story-sortie',
|
||||
speaker: '장비',
|
||||
portrait: 'zhangFei',
|
||||
text: '군사 하나 만나러 가는데 길목마다 잔챙이들이 성가시게 하는군요. 그래도 형님 뜻이라면 길부터 시원하게 열어 보겠습니다.'
|
||||
}
|
||||
];
|
||||
|
||||
export const seventeenthBattleVictoryPages: StoryPage[] = [
|
||||
{
|
||||
id: 'seventeenth-victory-longzhong-road',
|
||||
bgm: 'militia-theme',
|
||||
chapter: '열린 초가 길',
|
||||
background: 'story-sortie',
|
||||
text: '융중으로 향하는 길목의 가병들이 흩어지고, 산길은 조용해졌다. 유비는 갑옷의 먼지를 털지도 않은 채 제갈량의 초가 앞에 다시 섰다.'
|
||||
},
|
||||
{
|
||||
id: 'seventeenth-zhuge-liang-counsel',
|
||||
bgm: 'story-dark',
|
||||
chapter: '천하삼분의 말',
|
||||
background: 'story-liu-bei',
|
||||
speaker: '제갈량',
|
||||
text: '한실을 일으키려면 먼저 형주와 익주를 얻어 근본을 세우고, 때를 기다려 북벌의 길을 여십시오. 주공의 뜻이 백성에게 닿는다면, 저는 그 길에 지혜를 보태겠습니다.'
|
||||
},
|
||||
{
|
||||
id: 'seventeenth-zhuge-liang-joins',
|
||||
bgm: 'battle-prep',
|
||||
chapter: '와룡 출려',
|
||||
background: 'story-three-heroes',
|
||||
speaker: '유비',
|
||||
portrait: 'liuBei',
|
||||
text: '공명 선생이 함께한다면 우리 군은 비로소 길을 보는 눈을 얻은 것이오. 이제 형주의 머무름은 다음 큰 전장을 준비하는 시간이 될 것이오.'
|
||||
}
|
||||
];
|
||||
|
||||
export const firstBattleMap: BattleMap = {
|
||||
width: 20,
|
||||
height: 18,
|
||||
@@ -1310,6 +1374,12 @@ export const sixteenthBattleMap: BattleMap = {
|
||||
terrain: createSixteenthBattleTerrain()
|
||||
};
|
||||
|
||||
export const seventeenthBattleMap: BattleMap = {
|
||||
width: 34,
|
||||
height: 26,
|
||||
terrain: createSeventeenthBattleTerrain()
|
||||
};
|
||||
|
||||
export const firstBattleUnits: UnitData[] = [
|
||||
{
|
||||
id: 'liu-bei',
|
||||
@@ -3242,6 +3312,30 @@ export const liuBiaoRecruitUnits: UnitData[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const zhugeRecruitUnits: UnitData[] = [
|
||||
{
|
||||
id: 'zhuge-liang',
|
||||
name: '제갈량',
|
||||
faction: 'ally',
|
||||
className: '군사',
|
||||
classKey: 'strategist',
|
||||
level: 8,
|
||||
exp: 0,
|
||||
hp: 28,
|
||||
maxHp: 28,
|
||||
attack: 8,
|
||||
move: 4,
|
||||
stats: { might: 34, intelligence: 100, leadership: 88, agility: 74, luck: 86 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'white-feather-fan', level: 1, exp: 0 },
|
||||
armor: { itemId: 'oath-robe', level: 1, exp: 0 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 7,
|
||||
y: 20
|
||||
}
|
||||
];
|
||||
|
||||
const eighthBattleAllyPositions: Record<string, { x: number; y: number }> = {
|
||||
'liu-bei': { x: 2, y: 17 },
|
||||
'guan-yu': { x: 3, y: 17 },
|
||||
@@ -5937,6 +6031,340 @@ export const sixteenthBattleUnits: UnitData[] = [
|
||||
}
|
||||
];
|
||||
|
||||
const seventeenthBattleAllyPositions: Record<string, { x: number; y: number }> = {
|
||||
'liu-bei': { x: 3, y: 21 },
|
||||
'guan-yu': { x: 4, y: 20 },
|
||||
'zhang-fei': { x: 4, y: 22 },
|
||||
'jian-yong': { x: 5, y: 21 },
|
||||
'mi-zhu': { x: 3, y: 23 },
|
||||
'sun-qian': { x: 5, y: 23 },
|
||||
'zhao-yun': { x: 6, y: 22 }
|
||||
};
|
||||
|
||||
export const seventeenthBattleUnits: UnitData[] = [
|
||||
...[
|
||||
...firstBattleUnits.filter((unit) => unit.faction === 'ally'),
|
||||
...xuzhouRecruitUnits,
|
||||
...caoBreakRecruitUnits,
|
||||
...liuBiaoRecruitUnits
|
||||
].map((unit) => placeScenarioUnit(unit, seventeenthBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
|
||||
{
|
||||
id: 'wolong-road-scout-a',
|
||||
name: '산길 척후',
|
||||
faction: 'enemy',
|
||||
className: '형주 척후',
|
||||
classKey: 'bandit',
|
||||
level: 18,
|
||||
exp: 16,
|
||||
hp: 58,
|
||||
maxHp: 58,
|
||||
attack: 22,
|
||||
move: 4,
|
||||
stats: { might: 94, intelligence: 66, leadership: 72, agility: 92, luck: 64 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 82 },
|
||||
armor: { itemId: 'rebel-vest', level: 2, exp: 38 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 10,
|
||||
y: 20
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-scout-b',
|
||||
name: '산길 척후',
|
||||
faction: 'enemy',
|
||||
className: '형주 척후',
|
||||
classKey: 'bandit',
|
||||
level: 18,
|
||||
exp: 16,
|
||||
hp: 58,
|
||||
maxHp: 58,
|
||||
attack: 22,
|
||||
move: 4,
|
||||
stats: { might: 94, intelligence: 66, leadership: 72, agility: 92, luck: 64 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'yellow-turban-saber', level: 2, exp: 82 },
|
||||
armor: { itemId: 'rebel-vest', level: 2, exp: 38 },
|
||||
accessory: { itemId: 'grain-pouch', level: 1, exp: 0 }
|
||||
},
|
||||
x: 12,
|
||||
y: 23
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-infantry-a',
|
||||
name: '형주 가병',
|
||||
faction: 'enemy',
|
||||
className: '산길 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 18,
|
||||
exp: 18,
|
||||
hp: 70,
|
||||
maxHp: 70,
|
||||
attack: 24,
|
||||
move: 3,
|
||||
stats: { might: 100, intelligence: 68, leadership: 86, agility: 74, luck: 64 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 86 },
|
||||
armor: { itemId: 'lamellar-armor', level: 2, exp: 42 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 15,
|
||||
y: 18
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-infantry-b',
|
||||
name: '형주 가병',
|
||||
faction: 'enemy',
|
||||
className: '산길 보병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 18,
|
||||
exp: 18,
|
||||
hp: 70,
|
||||
maxHp: 70,
|
||||
attack: 24,
|
||||
move: 3,
|
||||
stats: { might: 100, intelligence: 68, leadership: 86, agility: 74, luck: 64 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 86 },
|
||||
armor: { itemId: 'lamellar-armor', level: 2, exp: 42 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 17,
|
||||
y: 20
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-infantry-c',
|
||||
name: '형주 가병',
|
||||
faction: 'enemy',
|
||||
className: '초가 수비병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 19,
|
||||
exp: 20,
|
||||
hp: 74,
|
||||
maxHp: 74,
|
||||
attack: 25,
|
||||
move: 3,
|
||||
stats: { might: 102, intelligence: 70, leadership: 88, agility: 74, luck: 65 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 90 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 2, exp: 46 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 26,
|
||||
y: 11
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-infantry-d',
|
||||
name: '형주 가병',
|
||||
faction: 'enemy',
|
||||
className: '초가 수비병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 19,
|
||||
exp: 20,
|
||||
hp: 74,
|
||||
maxHp: 74,
|
||||
attack: 25,
|
||||
move: 3,
|
||||
stats: { might: 102, intelligence: 70, leadership: 88, agility: 74, luck: 65 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 90 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 2, exp: 46 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 27,
|
||||
y: 15
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-archer-a',
|
||||
name: '형주 궁병',
|
||||
faction: 'enemy',
|
||||
className: '숲길 궁병',
|
||||
classKey: 'archer',
|
||||
level: 18,
|
||||
exp: 18,
|
||||
hp: 56,
|
||||
maxHp: 56,
|
||||
attack: 23,
|
||||
move: 3,
|
||||
stats: { might: 88, intelligence: 80, leadership: 78, agility: 88, luck: 65 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 2, exp: 84 },
|
||||
armor: { itemId: 'cloth-armor', level: 2, exp: 40 },
|
||||
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
|
||||
},
|
||||
x: 16,
|
||||
y: 14
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-archer-b',
|
||||
name: '형주 궁병',
|
||||
faction: 'enemy',
|
||||
className: '숲길 궁병',
|
||||
classKey: 'archer',
|
||||
level: 18,
|
||||
exp: 18,
|
||||
hp: 56,
|
||||
maxHp: 56,
|
||||
attack: 23,
|
||||
move: 3,
|
||||
stats: { might: 88, intelligence: 80, leadership: 78, agility: 88, luck: 65 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 2, exp: 84 },
|
||||
armor: { itemId: 'cloth-armor', level: 2, exp: 40 },
|
||||
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
|
||||
},
|
||||
x: 22,
|
||||
y: 10
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-archer-c',
|
||||
name: '형주 궁병',
|
||||
faction: 'enemy',
|
||||
className: '초가 궁병',
|
||||
classKey: 'archer',
|
||||
level: 19,
|
||||
exp: 20,
|
||||
hp: 58,
|
||||
maxHp: 58,
|
||||
attack: 24,
|
||||
move: 3,
|
||||
stats: { might: 90, intelligence: 82, leadership: 80, agility: 88, luck: 66 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 2, exp: 88 },
|
||||
armor: { itemId: 'cloth-armor', level: 2, exp: 42 },
|
||||
accessory: { itemId: 'wind-quiver', level: 1, exp: 0 }
|
||||
},
|
||||
x: 29,
|
||||
y: 13
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-cavalry-a',
|
||||
name: '형주 기병',
|
||||
faction: 'enemy',
|
||||
className: '산길 기병',
|
||||
classKey: 'cavalry',
|
||||
level: 19,
|
||||
exp: 20,
|
||||
hp: 76,
|
||||
maxHp: 76,
|
||||
attack: 26,
|
||||
move: 5,
|
||||
stats: { might: 104, intelligence: 64, leadership: 82, agility: 96, luck: 66 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 90 },
|
||||
armor: { itemId: 'lamellar-armor', level: 2, exp: 44 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 13,
|
||||
y: 19
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-cavalry-b',
|
||||
name: '형주 기병',
|
||||
faction: 'enemy',
|
||||
className: '산길 기병',
|
||||
classKey: 'cavalry',
|
||||
level: 19,
|
||||
exp: 20,
|
||||
hp: 76,
|
||||
maxHp: 76,
|
||||
attack: 26,
|
||||
move: 5,
|
||||
stats: { might: 104, intelligence: 64, leadership: 82, agility: 96, luck: 66 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 90 },
|
||||
armor: { itemId: 'lamellar-armor', level: 2, exp: 44 },
|
||||
accessory: { itemId: 'bravery-token', level: 1, exp: 0 }
|
||||
},
|
||||
x: 20,
|
||||
y: 18
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-guard-a',
|
||||
name: '채씨 가병',
|
||||
faction: 'enemy',
|
||||
className: '초가 감시병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 19,
|
||||
exp: 22,
|
||||
hp: 78,
|
||||
maxHp: 78,
|
||||
attack: 25,
|
||||
move: 3,
|
||||
stats: { might: 102, intelligence: 74, leadership: 90, agility: 75, luck: 65 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 92 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 2, exp: 48 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 30,
|
||||
y: 14
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-guard-b',
|
||||
name: '채씨 가병',
|
||||
faction: 'enemy',
|
||||
className: '초가 감시병',
|
||||
classKey: 'yellowTurban',
|
||||
level: 19,
|
||||
exp: 22,
|
||||
hp: 78,
|
||||
maxHp: 78,
|
||||
attack: 25,
|
||||
move: 3,
|
||||
stats: { might: 102, intelligence: 74, leadership: 90, agility: 75, luck: 65 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'iron-spear', level: 2, exp: 92 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 2, exp: 48 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 31,
|
||||
y: 12
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-strategist-a',
|
||||
name: '형주 문객',
|
||||
faction: 'enemy',
|
||||
className: '채씨 문객',
|
||||
classKey: 'archer',
|
||||
level: 19,
|
||||
exp: 22,
|
||||
hp: 60,
|
||||
maxHp: 60,
|
||||
attack: 24,
|
||||
move: 3,
|
||||
stats: { might: 74, intelligence: 92, leadership: 82, agility: 80, luck: 68 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'short-bow', level: 2, exp: 90 },
|
||||
armor: { itemId: 'cloth-armor', level: 2, exp: 44 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 28,
|
||||
y: 12
|
||||
},
|
||||
{
|
||||
id: 'wolong-road-leader-cai-xun',
|
||||
name: '채순',
|
||||
faction: 'enemy',
|
||||
className: '채씨 가병장',
|
||||
classKey: 'rebelLeader',
|
||||
level: 20,
|
||||
exp: 24,
|
||||
hp: 104,
|
||||
maxHp: 104,
|
||||
attack: 28,
|
||||
move: 4,
|
||||
stats: { might: 108, intelligence: 76, leadership: 98, agility: 82, luck: 66 },
|
||||
equipment: {
|
||||
weapon: { itemId: 'leader-axe', level: 3, exp: 32 },
|
||||
armor: { itemId: 'reinforced-lamellar', level: 2, exp: 52 },
|
||||
accessory: { itemId: 'war-manual', level: 1, exp: 0 }
|
||||
},
|
||||
x: 31,
|
||||
y: 14
|
||||
}
|
||||
];
|
||||
|
||||
export const firstBattleBonds: BattleBond[] = [
|
||||
{
|
||||
id: 'liu-bei__guan-yu',
|
||||
@@ -6021,6 +6449,33 @@ export const liuBiaoRecruitBonds: BattleBond[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export const zhugeRecruitBonds: BattleBond[] = [
|
||||
{
|
||||
id: 'liu-bei__zhuge-liang',
|
||||
unitIds: ['liu-bei', 'zhuge-liang'],
|
||||
title: '군신의 만남',
|
||||
level: 58,
|
||||
exp: 0,
|
||||
description: '유비의 뜻과 제갈량의 계책이 만나 천하를 향한 큰 그림을 열기 시작합니다.'
|
||||
},
|
||||
{
|
||||
id: 'zhao-yun__zhuge-liang',
|
||||
unitIds: ['zhao-yun', 'zhuge-liang'],
|
||||
title: '창과 책략',
|
||||
level: 36,
|
||||
exp: 0,
|
||||
description: '조운의 기동력과 제갈량의 판단은 빠른 구원과 정확한 돌파를 함께 만듭니다.'
|
||||
},
|
||||
{
|
||||
id: 'guan-yu__zhuge-liang',
|
||||
unitIds: ['guan-yu', 'zhuge-liang'],
|
||||
title: '의와 계책',
|
||||
level: 34,
|
||||
exp: 0,
|
||||
description: '관우의 의로운 전열과 제갈량의 큰 계책이 서로를 인정하며 군의 중심을 단단히 세웁니다.'
|
||||
}
|
||||
];
|
||||
|
||||
export const secondBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||
export const thirdBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||
export const fourthBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||
@@ -6040,6 +6495,7 @@ export const fifteenthBattleBonds: BattleBond[] = fourteenthBattleBonds.map(clon
|
||||
export const sixteenthBattleBonds: BattleBond[] = [...fifteenthBattleBonds, ...liuBiaoRecruitBonds].map(
|
||||
cloneBattleBondForScenario
|
||||
);
|
||||
export const seventeenthBattleBonds: BattleBond[] = sixteenthBattleBonds.map(cloneBattleBondForScenario);
|
||||
|
||||
function createEighthBattleTerrain(): TerrainType[][] {
|
||||
return Array.from({ length: 22 }, (_, y) =>
|
||||
@@ -6448,6 +6904,55 @@ function createSixteenthBattleTerrain(): TerrainType[][] {
|
||||
);
|
||||
}
|
||||
|
||||
function createSeventeenthBattleTerrain(): TerrainType[][] {
|
||||
return Array.from({ length: 26 }, (_, y) =>
|
||||
Array.from({ length: 34 }, (_, x): TerrainType => {
|
||||
if ((x <= 2 && y >= 20 && y <= 24) || (x === 3 && y >= 22 && y <= 24)) {
|
||||
return 'camp';
|
||||
}
|
||||
if ((x >= 29 && x <= 33 && y >= 10 && y <= 15) || (x >= 27 && x <= 30 && y >= 8 && y <= 10)) {
|
||||
return 'fort';
|
||||
}
|
||||
if ((x >= 24 && x <= 26 && y >= 11 && y <= 13) || (x >= 12 && x <= 14 && y >= 18 && y <= 20)) {
|
||||
return 'village';
|
||||
}
|
||||
if ((x === 18 || x === 19) && y >= 4 && y <= 23) {
|
||||
return 'river';
|
||||
}
|
||||
if (
|
||||
(y === 21 && x >= 2 && x <= 15) ||
|
||||
(y === 18 && x >= 13 && x <= 24) ||
|
||||
(y === 13 && x >= 22 && x <= 32) ||
|
||||
(x === 29 && y >= 10 && y <= 18)
|
||||
) {
|
||||
return 'road';
|
||||
}
|
||||
if ((x >= 5 && x <= 15 && y === 25 - x) || (x >= 15 && x <= 29 && y === x - 11)) {
|
||||
return 'road';
|
||||
}
|
||||
if (
|
||||
(x <= 10 && y <= 9) ||
|
||||
(x >= 4 && x <= 15 && y >= 10 && y <= 17) ||
|
||||
(x >= 20 && x <= 28 && y >= 16 && y <= 24) ||
|
||||
(x >= 25 && y <= 7)
|
||||
) {
|
||||
return 'forest';
|
||||
}
|
||||
if (
|
||||
(x >= 8 && x <= 15 && y >= 2 && y <= 7) ||
|
||||
(x >= 15 && x <= 23 && y >= 20 && y <= 25) ||
|
||||
(x >= 27 && x <= 33 && y >= 1 && y <= 6)
|
||||
) {
|
||||
return 'hill';
|
||||
}
|
||||
if ((x >= 32 && y <= 9) || (x >= 32 && y >= 17) || (x <= 1 && y <= 6)) {
|
||||
return 'cliff';
|
||||
}
|
||||
return 'plain';
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
|
||||
return {
|
||||
...cloneUnitForScenario(unit),
|
||||
|
||||
@@ -28,6 +28,7 @@ const unitTexture: Record<string, string> = {
|
||||
'guan-yu': 'unit-guan-yu',
|
||||
'zhang-fei': 'unit-zhang-fei',
|
||||
'zhao-yun': 'unit-rebel-cavalry',
|
||||
'zhuge-liang': 'unit-liu-bei',
|
||||
'rebel-a': 'unit-rebel',
|
||||
'rebel-b': 'unit-rebel',
|
||||
'rebel-c': 'unit-rebel-archer',
|
||||
@@ -139,7 +140,22 @@ const unitTexture: Record<string, string> = {
|
||||
'liu-biao-road-guard-a': 'unit-rebel',
|
||||
'liu-biao-road-guard-b': 'unit-rebel',
|
||||
'liu-biao-road-strategist-a': 'unit-rebel-archer',
|
||||
'liu-biao-road-leader-cao-ren': 'unit-rebel-leader'
|
||||
'liu-biao-road-leader-cao-ren': 'unit-rebel-leader',
|
||||
'wolong-road-scout-a': 'unit-rebel',
|
||||
'wolong-road-scout-b': 'unit-rebel',
|
||||
'wolong-road-infantry-a': 'unit-rebel',
|
||||
'wolong-road-infantry-b': 'unit-rebel',
|
||||
'wolong-road-infantry-c': 'unit-rebel',
|
||||
'wolong-road-infantry-d': 'unit-rebel',
|
||||
'wolong-road-archer-a': 'unit-rebel-archer',
|
||||
'wolong-road-archer-b': 'unit-rebel-archer',
|
||||
'wolong-road-archer-c': 'unit-rebel-archer',
|
||||
'wolong-road-cavalry-a': 'unit-rebel-cavalry',
|
||||
'wolong-road-cavalry-b': 'unit-rebel-cavalry',
|
||||
'wolong-road-guard-a': 'unit-rebel',
|
||||
'wolong-road-guard-b': 'unit-rebel',
|
||||
'wolong-road-strategist-a': 'unit-rebel-archer',
|
||||
'wolong-road-leader-cai-xun': 'unit-rebel-leader'
|
||||
};
|
||||
|
||||
const unitTextureByClass: Partial<Record<UnitClassKey, string>> = {
|
||||
@@ -553,7 +569,9 @@ const unitStrategyIds: Record<string, string[]> = {
|
||||
'guan-yu': ['fireTactic'],
|
||||
'zhang-fei': ['roar'],
|
||||
'jian-yong': ['aid', 'encourage', 'fireTactic'],
|
||||
'mi-zhu': ['aid', 'encourage']
|
||||
'mi-zhu': ['aid', 'encourage'],
|
||||
'sun-qian': ['aid', 'encourage', 'fireTactic'],
|
||||
'zhuge-liang': ['aid', 'encourage', 'fireTactic']
|
||||
};
|
||||
|
||||
const initialItemStocks: Record<string, Record<string, number>> = {
|
||||
@@ -563,7 +581,8 @@ const initialItemStocks: Record<string, Record<string, number>> = {
|
||||
'jian-yong': { bean: 1 },
|
||||
'mi-zhu': { bean: 2, salve: 1 },
|
||||
'sun-qian': { bean: 1, salve: 1 },
|
||||
'zhao-yun': { bean: 1, wine: 1 }
|
||||
'zhao-yun': { bean: 1, wine: 1 },
|
||||
'zhuge-liang': { bean: 1, wine: 1 }
|
||||
};
|
||||
|
||||
const attackRangeByClass: Partial<Record<UnitClassKey, number>> = {
|
||||
@@ -727,7 +746,22 @@ const enemyAiByUnitId: Record<string, EnemyAiBehavior> = {
|
||||
'liu-biao-road-guard-a': 'guard',
|
||||
'liu-biao-road-guard-b': 'guard',
|
||||
'liu-biao-road-strategist-a': 'hold',
|
||||
'liu-biao-road-leader-cao-ren': 'guard'
|
||||
'liu-biao-road-leader-cao-ren': 'guard',
|
||||
'wolong-road-scout-a': 'aggressive',
|
||||
'wolong-road-scout-b': 'aggressive',
|
||||
'wolong-road-infantry-a': 'guard',
|
||||
'wolong-road-infantry-b': 'guard',
|
||||
'wolong-road-infantry-c': 'guard',
|
||||
'wolong-road-infantry-d': 'guard',
|
||||
'wolong-road-archer-a': 'hold',
|
||||
'wolong-road-archer-b': 'hold',
|
||||
'wolong-road-archer-c': 'hold',
|
||||
'wolong-road-cavalry-a': 'aggressive',
|
||||
'wolong-road-cavalry-b': 'aggressive',
|
||||
'wolong-road-guard-a': 'guard',
|
||||
'wolong-road-guard-b': 'guard',
|
||||
'wolong-road-strategist-a': 'hold',
|
||||
'wolong-road-leader-cai-xun': 'guard'
|
||||
};
|
||||
|
||||
const defaultEnemyAiByClass: Partial<Record<UnitClassKey, EnemyAiBehavior>> = {
|
||||
|
||||
@@ -11,6 +11,7 @@ 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';
|
||||
import sixteenthBattleMapUrl from '../../assets/images/battle/sixteenth-battle-map.svg';
|
||||
import seventeenthBattleMapUrl from '../../assets/images/battle/seventeenth-battle-map.svg';
|
||||
import tenthBattleMapUrl from '../../assets/images/battle/tenth-battle-map.svg';
|
||||
import thirteenthBattleMapUrl from '../../assets/images/battle/thirteenth-battle-map.svg';
|
||||
import thirdBattleMapUrl from '../../assets/images/battle/third-battle-map.svg';
|
||||
@@ -90,6 +91,7 @@ export class BootScene extends Phaser.Scene {
|
||||
this.load.image('battle-map-fourteenth', fourteenthBattleMapUrl);
|
||||
this.load.image('battle-map-fifteenth', fifteenthBattleMapUrl);
|
||||
this.load.image('battle-map-sixteenth', sixteenthBattleMapUrl);
|
||||
this.load.image('battle-map-seventeenth', seventeenthBattleMapUrl);
|
||||
this.load.image('portrait-liu-bei', liuBeiPortraitUrl);
|
||||
this.load.image('portrait-guan-yu', guanYuPortraitUrl);
|
||||
this.load.image('portrait-zhang-fei', zhangFeiPortraitUrl);
|
||||
@@ -132,6 +134,7 @@ export class BootScene extends Phaser.Scene {
|
||||
this.createItemIcon('item-green-dragon-glaive', (graphics) => this.drawPolearmIcon(graphics, 0x5fbf8f, 0xd8b15f));
|
||||
this.createItemIcon('item-serpent-spear', (graphics) => this.drawSpearIcon(graphics, 0xe0e8ef, 0xb86b55));
|
||||
this.createItemIcon('item-sky-piercer-halberd', (graphics) => this.drawPolearmIcon(graphics, 0xd8dfe6, 0xd95f4f));
|
||||
this.createItemIcon('item-white-feather-fan', (graphics) => this.drawFanIcon(graphics, 0xf3f0df, 0x6e8eb8));
|
||||
this.createItemIcon('item-yellow-turban-saber', (graphics) => this.drawSaberIcon(graphics, 0xd8b15f, 0x9c6b2f));
|
||||
this.createItemIcon('item-short-bow', (graphics) => this.drawBowIcon(graphics, 0xc58a4c, 0xe8dfca));
|
||||
this.createItemIcon('item-leader-axe', (graphics) => this.drawAxeIcon(graphics, 0xd8dfe6, 0x8d5a3a));
|
||||
@@ -258,6 +261,30 @@ export class BootScene extends Phaser.Scene {
|
||||
graphics.fillTriangle(16, 5, 9, 9, 15, 14);
|
||||
}
|
||||
|
||||
private drawFanIcon(graphics: Phaser.GameObjects.Graphics, featherColor: number, ribColor: number) {
|
||||
graphics.lineStyle(2, ribColor, 1);
|
||||
graphics.beginPath();
|
||||
graphics.moveTo(16, 25);
|
||||
graphics.lineTo(5, 8);
|
||||
graphics.moveTo(16, 25);
|
||||
graphics.lineTo(10, 4);
|
||||
graphics.moveTo(16, 25);
|
||||
graphics.lineTo(16, 3);
|
||||
graphics.moveTo(16, 25);
|
||||
graphics.lineTo(22, 4);
|
||||
graphics.moveTo(16, 25);
|
||||
graphics.lineTo(27, 8);
|
||||
graphics.strokePath();
|
||||
graphics.fillStyle(featherColor, 0.96);
|
||||
graphics.fillEllipse(5, 9, 7, 15);
|
||||
graphics.fillEllipse(10, 6, 7, 17);
|
||||
graphics.fillEllipse(16, 5, 8, 18);
|
||||
graphics.fillEllipse(22, 6, 7, 17);
|
||||
graphics.fillEllipse(27, 9, 7, 15);
|
||||
graphics.fillStyle(0xd8b15f, 1);
|
||||
graphics.fillCircle(16, 25, 3);
|
||||
}
|
||||
|
||||
private drawArmorIcon(graphics: Phaser.GameObjects.Graphics, baseColor: number, accentColor: number) {
|
||||
graphics.fillStyle(baseColor, 1);
|
||||
graphics.fillTriangle(14, 4, 24, 11, 20, 24);
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
liuBiaoRecruitUnits,
|
||||
xuzhouRecruitBonds,
|
||||
xuzhouRecruitUnits,
|
||||
zhugeRecruitBonds,
|
||||
zhugeRecruitUnits,
|
||||
type PortraitKey,
|
||||
type UnitData
|
||||
} from '../data/scenario';
|
||||
@@ -218,7 +220,8 @@ const campBattleIds = {
|
||||
thirteenth: 'thirteenth-battle-xiapi-final',
|
||||
fourteenth: 'fourteenth-battle-cao-break',
|
||||
fifteenth: 'fifteenth-battle-yuan-refuge-road',
|
||||
sixteenth: 'sixteenth-battle-liu-biao-refuge'
|
||||
sixteenth: 'sixteenth-battle-liu-biao-refuge',
|
||||
seventeenth: 'seventeenth-battle-wolong-visit-road'
|
||||
} as const;
|
||||
|
||||
const requiredSortieUnitIds = new Set(['liu-bei']);
|
||||
@@ -385,6 +388,18 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
|
||||
{ unitId: 'mi-zhu', reason: '큰 맵의 장기전을 대비한 보급과 회복 운용에 유리합니다.' }
|
||||
],
|
||||
note: '유표 의탁로부터는 합류 무장이 출전 제한보다 많아집니다. 조운의 기동력을 시험할지, 책사와 보급을 두껍게 둘지 직접 고르십시오.'
|
||||
},
|
||||
'seventeenth-battle-wolong-visit-road': {
|
||||
maxUnits: 6,
|
||||
recommended: [
|
||||
{ unitId: 'liu-bei', reason: '와룡을 직접 찾아가는 주장입니다.' },
|
||||
{ unitId: 'zhao-yun', reason: '산길 척후와 기병을 빠르게 끊는 기동 역할입니다.' },
|
||||
{ unitId: 'guan-yu', reason: '초가 앞 수비병을 정면에서 밀어낼 전열 핵심입니다.' },
|
||||
{ unitId: 'zhang-fei', reason: '좁은 길목을 뚫고 채순을 압박하는 돌파 역할입니다.' },
|
||||
{ unitId: 'sun-qian', reason: '와룡 방문의 예와 명분을 정리하는 책사 역할입니다.' },
|
||||
{ unitId: 'mi-zhu', reason: '산길 장기전에 필요한 보급과 회복 운용을 맡습니다.' }
|
||||
],
|
||||
note: '와룡 단서를 모은 뒤 융중으로 향합니다. 출전 제한보다 무장이 많으니 조운의 기동, 책사의 지원, 보급 중 무엇을 중시할지 선택하십시오.'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1738,6 +1753,87 @@ const campDialogues: CampDialogue[] = [
|
||||
rewardExp: 9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'liu-zhuge-after-wolong-visit',
|
||||
title: '초가에서 열린 큰 그림',
|
||||
availableAfterBattleIds: [campBattleIds.seventeenth],
|
||||
unitIds: ['liu-bei', 'zhuge-liang'],
|
||||
bondId: 'liu-bei__zhuge-liang',
|
||||
rewardExp: 28,
|
||||
lines: [
|
||||
'제갈량: 주공께서 세 번이나 초가를 찾으신 것은 한 사람을 얻기 위함이 아니라, 백성을 살릴 길을 묻기 위함이라 보았습니다.',
|
||||
'유비: 나는 아직 작은 군영 하나도 온전히 지키기 어려운 몸이오. 그러나 선생의 말은 우리 군이 가야 할 길을 눈앞에 펼쳤소.',
|
||||
'제갈량: 그 길은 서두르면 흐트러지고, 늦추면 빼앗깁니다. 이제부터는 뜻과 때를 함께 살피겠습니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'share-three-kingdoms-plan',
|
||||
label: '천하삼분의 뜻을 묻는다',
|
||||
response: '제갈량은 형주와 익주, 그리고 북벌의 때를 차분히 설명했고, 유비는 그 말을 군영의 첫 방침으로 삼았다.',
|
||||
rewardExp: 12
|
||||
},
|
||||
{
|
||||
id: 'entrust-camp-strategy',
|
||||
label: '군영의 계책을 맡긴다',
|
||||
response: '유비는 제갈량에게 군영의 큰 판단을 맡겼고, 공명은 병사와 장수의 이름부터 조용히 살피기 시작했다.',
|
||||
rewardExp: 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'zhao-zhuge-after-wolong-visit',
|
||||
title: '말발굽과 부채',
|
||||
availableAfterBattleIds: [campBattleIds.seventeenth],
|
||||
unitIds: ['zhao-yun', 'zhuge-liang'],
|
||||
bondId: 'zhao-yun__zhuge-liang',
|
||||
rewardExp: 22,
|
||||
lines: [
|
||||
'조운: 선생의 계책은 멀리 보되, 실제 길목의 먼지까지 살피는군요. 제 말이 달릴 곳을 미리 본 듯했습니다.',
|
||||
'제갈량: 자룡의 창은 빠르지만 앞서 나가도 군의 마음을 놓치지 않습니다. 그래서 빠른 구원이 가능해집니다.',
|
||||
'조운: 그렇다면 다음 전장에서는 선생의 지시에 맞춰, 가장 필요한 곳에 먼저 닿겠습니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'map-relief-routes',
|
||||
label: '구원로를 함께 살핀다',
|
||||
response: '제갈량은 지형 위에 구원로를 표시했고, 조운은 말이 지나갈 수 있는 폭과 위험한 샛길을 덧붙였다.',
|
||||
rewardExp: 10
|
||||
},
|
||||
{
|
||||
id: 'coordinate-feint-charge',
|
||||
label: '유인 돌격을 맞춘다',
|
||||
response: '조운은 일부러 빈틈을 보이는 돌격법을 익혔고, 제갈량은 그 틈에 적을 몰아넣는 순서를 정했다.',
|
||||
rewardExp: 9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'guan-zhuge-after-wolong-visit',
|
||||
title: '의와 계책의 첫 인사',
|
||||
availableAfterBattleIds: [campBattleIds.seventeenth],
|
||||
unitIds: ['guan-yu', 'zhuge-liang'],
|
||||
bondId: 'guan-yu__zhuge-liang',
|
||||
rewardExp: 20,
|
||||
lines: [
|
||||
'관우: 선생의 말은 크고 깊으나, 전장에서는 한 걸음의 늦음도 군을 잃게 합니다. 그 점을 잊지 않으셨으면 하오.',
|
||||
'제갈량: 운장께서 전열을 지키는 까닭도 결국 주공의 뜻을 잃지 않기 위함입니다. 저는 그 의를 가벼이 여기지 않겠습니다.',
|
||||
'관우: 그렇다면 나 또한 선생의 계책을 먼저 듣겠소. 의가 길을 잃지 않게 해 주시오.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'align-duty-and-plan',
|
||||
label: '의와 계책을 맞춘다',
|
||||
response: '관우는 제갈량의 병력 운용을 듣고 전열의 기준을 새로 세웠고, 제갈량은 관우가 지켜야 할 선을 존중했다.',
|
||||
rewardExp: 9
|
||||
},
|
||||
{
|
||||
id: 'promise-clear-orders',
|
||||
label: '명령의 기준을 분명히 한다',
|
||||
response: '제갈량은 전장 명령의 우선순위를 문서로 정리했고, 관우는 그 분명함을 보고 조용히 고개를 끄덕였다.',
|
||||
rewardExp: 8
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1829,6 +1925,65 @@ const campVisits: CampVisitDefinition[] = [
|
||||
itemRewards: ['탁주 1']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'longzhong-cottage-records',
|
||||
title: '융중 초가 정리',
|
||||
location: '융중 초가',
|
||||
availableAfterBattleIds: [campBattleIds.seventeenth],
|
||||
bondId: 'liu-bei__zhuge-liang',
|
||||
description: '제갈량과 함께 초가의 지도와 서책을 정리하며 다음 큰 흐름을 준비합니다.',
|
||||
lines: [
|
||||
'제갈량: 이 지도들은 아직 군영의 전장 지도가 아니라 천하의 형세입니다. 그러나 전장은 늘 여기서 시작됩니다.',
|
||||
'유비: 우리 군이 지금 가진 것은 많지 않소. 그래서 더더욱 무엇을 먼저 지킬지 알아야 하오.',
|
||||
'초가의 낮은 책상 위에는 형주와 강동, 북방의 길이 하나씩 펼쳐집니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'study-red-cliff-winds',
|
||||
label: '강동의 바람을 살핀다',
|
||||
response: '제갈량은 강동과 조조군의 충돌 가능성을 짚었고, 유비군은 다음 큰 전장의 이름을 조심스럽게 떠올렸다.',
|
||||
bondExp: 24,
|
||||
itemRewards: ['강동 풍문 1']
|
||||
},
|
||||
{
|
||||
id: 'organize-wolong-scrolls',
|
||||
label: '와룡의 서책을 정리한다',
|
||||
response: '손상되기 쉬운 서책을 군영으로 옮기며 제갈량의 계책을 병사들도 이해할 수 있는 말로 옮기기 시작했다.',
|
||||
bondExp: 20,
|
||||
itemRewards: ['와룡의 서찰 1']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'xinye-merchant-after-wolong',
|
||||
title: '신야 상인 접견',
|
||||
location: '신야 장터',
|
||||
availableAfterBattleIds: [campBattleIds.seventeenth],
|
||||
bondId: 'liu-bei__mi-zhu',
|
||||
description: '제갈량 합류 소문을 듣고 찾아온 상인들과 다음 전투를 위한 보급 조건을 조율합니다.',
|
||||
lines: [
|
||||
'미축: 와룡이 주공의 군영에 들었다는 말이 퍼지자 상인들의 셈도 달라졌습니다. 지금 보급선을 고정할 기회입니다.',
|
||||
'유비: 값이 싸다고 무리하게 사들이지는 마시오. 백성의 삶을 해치지 않는 선에서 군을 세워야 하오.',
|
||||
'상인들은 유비군의 앞날에 걸지, 당장의 이익만 챙길지 서로 눈치를 봅니다.'
|
||||
],
|
||||
choices: [
|
||||
{
|
||||
id: 'secure-medicine-contract',
|
||||
label: '약재 계약을 맺는다',
|
||||
response: '미축은 오래 보관할 수 있는 약재 계약을 맺었고, 군영의 치료 물자가 안정되었다.',
|
||||
bondExp: 14,
|
||||
itemRewards: ['상처약 2']
|
||||
},
|
||||
{
|
||||
id: 'preserve-war-funds',
|
||||
label: '군자금을 아낀다',
|
||||
response: '미축은 급하지 않은 거래를 미루고 군자금을 보존했다. 병사들은 검소한 군영의 기준을 이해했다.',
|
||||
bondExp: 12,
|
||||
gold: 160,
|
||||
itemRewards: ['콩 2']
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1914,6 +2069,15 @@ export class CampScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
if (battleId === campBattleIds.seventeenth) {
|
||||
this.campaign = ensureCampaignRosterUnits(
|
||||
[...xuzhouRecruitUnits, ...caoBreakRecruitUnits, ...liuBiaoRecruitUnits, ...zhugeRecruitUnits],
|
||||
[...xuzhouRecruitBonds, ...caoBreakRecruitBonds, ...liuBiaoRecruitBonds, ...zhugeRecruitBonds]
|
||||
);
|
||||
this.report = this.campaign.firstBattleReport ?? this.report;
|
||||
return;
|
||||
}
|
||||
|
||||
if (battleId === campBattleIds.fifteenth || battleId === campBattleIds.sixteenth) {
|
||||
this.campaign = ensureCampaignRosterUnits(
|
||||
[...xuzhouRecruitUnits, ...caoBreakRecruitUnits, ...liuBiaoRecruitUnits],
|
||||
@@ -1962,6 +2126,9 @@ export class CampScene extends Phaser.Scene {
|
||||
|
||||
private currentCampTitle() {
|
||||
const battleId = this.currentCampBattleId();
|
||||
if (battleId === campBattleIds.seventeenth) {
|
||||
return '와룡 출려 후 군영';
|
||||
}
|
||||
if (battleId === campBattleIds.sixteenth) {
|
||||
return '형주 의탁 후 군영';
|
||||
}
|
||||
@@ -2701,6 +2868,14 @@ export class CampScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flow.nextBattleId === campBattleIds.seventeenth && this.wolongClueCount() <= 0) {
|
||||
this.hideSortiePrep();
|
||||
this.activeTab = 'visit';
|
||||
this.render();
|
||||
this.showCampNotice('와룡의 단서를 먼저 모으십시오. 방문 탭에서 형주 선비들의 말을 들어 보세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
markCampaignStep(flow.campaignStep);
|
||||
this.scene.start('StoryScene', {
|
||||
pages: flow.pages,
|
||||
@@ -3058,7 +3233,7 @@ export class CampScene extends Phaser.Scene {
|
||||
bg.setStrokeStyle(1, palette.blue, 0.42);
|
||||
this.track(this.add.text(x + 14, y + 12, '현지 준비', this.textStyle(17, '#f2e3bf', true)));
|
||||
this.track(this.add.text(x + 14, y + 40, `방문 ${completed.length}/${visits.length} 완료`, this.textStyle(13, completed.length >= visits.length && visits.length > 0 ? '#a8ffd0' : '#d4dce6', true)));
|
||||
const insightCount = this.inventoryAmount('와룡 소문') + this.inventoryAmount('민심 기록');
|
||||
const insightCount = this.wolongClueCount();
|
||||
this.track(this.add.text(x + 14, y + 66, `제갈량 단서 ${insightCount} · 군자금 ${this.campaign?.gold ?? 0}`, this.textStyle(13, '#9fb0bf', true)));
|
||||
}
|
||||
|
||||
@@ -3586,6 +3761,10 @@ export class CampScene extends Phaser.Scene {
|
||||
return this.campaign?.inventory[label] ?? 0;
|
||||
}
|
||||
|
||||
private wolongClueCount() {
|
||||
return this.inventoryAmount('와룡 소문') + this.inventoryAmount('민심 기록');
|
||||
}
|
||||
|
||||
private drawBar(x: number, y: number, width: number, height: number, ratio: number, color: number) {
|
||||
const track = this.track(this.add.rectangle(x, y, width, height, 0x070b10, 0.86));
|
||||
track.setOrigin(0);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
seventhBattleScenario,
|
||||
sixthBattleScenario,
|
||||
sixteenthBattleScenario,
|
||||
seventeenthBattleScenario,
|
||||
tenthBattleScenario,
|
||||
thirteenthBattleScenario,
|
||||
twelfthBattleScenario,
|
||||
@@ -331,7 +332,8 @@ export class TitleScene extends Phaser.Scene {
|
||||
campaign.step === 'thirteenth-camp' ||
|
||||
campaign.step === 'fourteenth-camp' ||
|
||||
campaign.step === 'fifteenth-camp' ||
|
||||
campaign.step === 'sixteenth-camp'
|
||||
campaign.step === 'sixteenth-camp' ||
|
||||
campaign.step === 'seventeenth-camp'
|
||||
) {
|
||||
this.scene.start('CampScene');
|
||||
return;
|
||||
@@ -417,6 +419,11 @@ export class TitleScene extends Phaser.Scene {
|
||||
return;
|
||||
}
|
||||
|
||||
if (campaign.step === 'seventeenth-battle') {
|
||||
this.scene.start('BattleScene', { battleId: seventeenthBattleScenario.id });
|
||||
return;
|
||||
}
|
||||
|
||||
if (campaign.step === 'first-victory-story') {
|
||||
this.scene.start('StoryScene', { pages: firstBattleVictoryPages, nextScene: 'TitleScene' });
|
||||
return;
|
||||
|
||||
@@ -72,7 +72,9 @@ export type CampaignStep =
|
||||
| 'fifteenth-battle'
|
||||
| 'fifteenth-camp'
|
||||
| 'sixteenth-battle'
|
||||
| 'sixteenth-camp';
|
||||
| 'sixteenth-camp'
|
||||
| 'seventeenth-battle'
|
||||
| 'seventeenth-camp';
|
||||
|
||||
export type CampaignUnitProgressSnapshot = {
|
||||
unitId: string;
|
||||
@@ -140,7 +142,8 @@ const campaignBattleSteps: Record<string, { victory: CampaignStep; retry: Campai
|
||||
'thirteenth-battle-xiapi-final': { victory: 'thirteenth-camp', retry: 'thirteenth-battle' },
|
||||
'fourteenth-battle-cao-break': { victory: 'fourteenth-camp', retry: 'fourteenth-battle' },
|
||||
'fifteenth-battle-yuan-refuge-road': { victory: 'fifteenth-camp', retry: 'fifteenth-battle' },
|
||||
'sixteenth-battle-liu-biao-refuge': { victory: 'sixteenth-camp', retry: 'sixteenth-battle' }
|
||||
'sixteenth-battle-liu-biao-refuge': { victory: 'sixteenth-camp', retry: 'sixteenth-battle' },
|
||||
'seventeenth-battle-wolong-visit-road': { victory: 'seventeenth-camp', retry: 'seventeenth-battle' }
|
||||
};
|
||||
|
||||
export type CampaignSaveSlotSummary = {
|
||||
|
||||
Reference in New Issue
Block a user