Add fourth Meng Huo capture battle

This commit is contained in:
2026-06-23 23:04:23 +09:00
parent aa152d827c
commit b56f613e9f
12 changed files with 997 additions and 159 deletions

View File

@@ -0,0 +1,105 @@
import eighthBattleMapUrl from '../../assets/images/battle/eighth-battle-map.svg';
import eighteenthBattleMapUrl from '../../assets/images/battle/eighteenth-battle-map.svg';
import eleventhBattleMapUrl from '../../assets/images/battle/eleventh-battle-map.svg';
import fiftiethBattleMapUrl from '../../assets/images/battle/fiftieth-battle-map.svg';
import fiftyFirstBattleMapUrl from '../../assets/images/battle/fifty-first-battle-map.svg';
import fifthBattleMapUrl from '../../assets/images/battle/fifth-battle-map.svg';
import fifteenthBattleMapUrl from '../../assets/images/battle/fifteenth-battle-map.svg';
import firstBattleMapUrl from '../../assets/images/battle/first-battle-map.png';
import fortiethBattleMapUrl from '../../assets/images/battle/fortieth-battle-map.svg';
import fortyEighthBattleMapUrl from '../../assets/images/battle/forty-eighth-battle-map.svg';
import fortyFifthBattleMapUrl from '../../assets/images/battle/forty-fifth-battle-map.svg';
import fortyFirstBattleMapUrl from '../../assets/images/battle/forty-first-battle-map.svg';
import fortyFourthBattleMapUrl from '../../assets/images/battle/forty-fourth-battle-map.svg';
import fortyNinthBattleMapUrl from '../../assets/images/battle/forty-ninth-battle-map.svg';
import fortySecondBattleMapUrl from '../../assets/images/battle/forty-second-battle-map.svg';
import fortySeventhBattleMapUrl from '../../assets/images/battle/forty-seventh-battle-map.svg';
import fortySixthBattleMapUrl from '../../assets/images/battle/forty-sixth-battle-map.svg';
import fortyThirdBattleMapUrl from '../../assets/images/battle/forty-third-battle-map.svg';
import fourteenthBattleMapUrl from '../../assets/images/battle/fourteenth-battle-map.svg';
import fourthBattleMapUrl from '../../assets/images/battle/fourth-battle-map.svg';
import nineteenthBattleMapUrl from '../../assets/images/battle/nineteenth-battle-map.svg';
import ninthBattleMapUrl from '../../assets/images/battle/ninth-battle-map.svg';
import secondBattleMapUrl from '../../assets/images/battle/second-battle-map.svg';
import seventhBattleMapUrl from '../../assets/images/battle/seventh-battle-map.svg';
import seventeenthBattleMapUrl from '../../assets/images/battle/seventeenth-battle-map.svg';
import sixteenthBattleMapUrl from '../../assets/images/battle/sixteenth-battle-map.svg';
import sixthBattleMapUrl from '../../assets/images/battle/sixth-battle-map.svg';
import tenthBattleMapUrl from '../../assets/images/battle/tenth-battle-map.svg';
import thirteenthBattleMapUrl from '../../assets/images/battle/thirteenth-battle-map.svg';
import thirtiethBattleMapUrl from '../../assets/images/battle/thirtieth-battle-map.svg';
import thirtyEighthBattleMapUrl from '../../assets/images/battle/thirty-eighth-battle-map.svg';
import thirtyFifthBattleMapUrl from '../../assets/images/battle/thirty-fifth-battle-map.svg';
import thirtyFirstBattleMapUrl from '../../assets/images/battle/thirty-first-battle-map.svg';
import thirtyFourthBattleMapUrl from '../../assets/images/battle/thirty-fourth-battle-map.svg';
import thirtyNinthBattleMapUrl from '../../assets/images/battle/thirty-ninth-battle-map.svg';
import thirtySecondBattleMapUrl from '../../assets/images/battle/thirty-second-battle-map.svg';
import thirtySeventhBattleMapUrl from '../../assets/images/battle/thirty-seventh-battle-map.svg';
import thirtySixthBattleMapUrl from '../../assets/images/battle/thirty-sixth-battle-map.svg';
import thirtyThirdBattleMapUrl from '../../assets/images/battle/thirty-third-battle-map.svg';
import thirdBattleMapUrl from '../../assets/images/battle/third-battle-map.svg';
import twentiethBattleMapUrl from '../../assets/images/battle/twentieth-battle-map.svg';
import twentyEighthBattleMapUrl from '../../assets/images/battle/twenty-eighth-battle-map.svg';
import twentyFifthBattleMapUrl from '../../assets/images/battle/twenty-fifth-battle-map.svg';
import twentyFirstBattleMapUrl from '../../assets/images/battle/twenty-first-battle-map.svg';
import twentyFourthBattleMapUrl from '../../assets/images/battle/twenty-fourth-battle-map.svg';
import twentyNinthBattleMapUrl from '../../assets/images/battle/twenty-ninth-battle-map.svg';
import twentySecondBattleMapUrl from '../../assets/images/battle/twenty-second-battle-map.svg';
import twentySeventhBattleMapUrl from '../../assets/images/battle/twenty-seventh-battle-map.svg';
import twentySixthBattleMapUrl from '../../assets/images/battle/twenty-sixth-battle-map.svg';
import twentyThirdBattleMapUrl from '../../assets/images/battle/twenty-third-battle-map.svg';
import twelfthBattleMapUrl from '../../assets/images/battle/twelfth-battle-map.svg';
export const battleMapAssets: Record<string, string> = {
'battle-map-first': firstBattleMapUrl,
'battle-map-second': secondBattleMapUrl,
'battle-map-third': thirdBattleMapUrl,
'battle-map-fourth': fourthBattleMapUrl,
'battle-map-fifth': fifthBattleMapUrl,
'battle-map-sixth': sixthBattleMapUrl,
'battle-map-seventh': seventhBattleMapUrl,
'battle-map-eighth': eighthBattleMapUrl,
'battle-map-ninth': ninthBattleMapUrl,
'battle-map-tenth': tenthBattleMapUrl,
'battle-map-eleventh': eleventhBattleMapUrl,
'battle-map-twelfth': twelfthBattleMapUrl,
'battle-map-thirteenth': thirteenthBattleMapUrl,
'battle-map-fourteenth': fourteenthBattleMapUrl,
'battle-map-fifteenth': fifteenthBattleMapUrl,
'battle-map-sixteenth': sixteenthBattleMapUrl,
'battle-map-seventeenth': seventeenthBattleMapUrl,
'battle-map-eighteenth': eighteenthBattleMapUrl,
'battle-map-nineteenth': nineteenthBattleMapUrl,
'battle-map-twentieth': twentiethBattleMapUrl,
'battle-map-twenty-first': twentyFirstBattleMapUrl,
'battle-map-twenty-second': twentySecondBattleMapUrl,
'battle-map-twenty-third': twentyThirdBattleMapUrl,
'battle-map-twenty-fourth': twentyFourthBattleMapUrl,
'battle-map-twenty-fifth': twentyFifthBattleMapUrl,
'battle-map-twenty-sixth': twentySixthBattleMapUrl,
'battle-map-twenty-seventh': twentySeventhBattleMapUrl,
'battle-map-twenty-eighth': twentyEighthBattleMapUrl,
'battle-map-twenty-ninth': twentyNinthBattleMapUrl,
'battle-map-thirtieth': thirtiethBattleMapUrl,
'battle-map-thirty-first': thirtyFirstBattleMapUrl,
'battle-map-thirty-second': thirtySecondBattleMapUrl,
'battle-map-thirty-third': thirtyThirdBattleMapUrl,
'battle-map-thirty-fourth': thirtyFourthBattleMapUrl,
'battle-map-thirty-fifth': thirtyFifthBattleMapUrl,
'battle-map-thirty-sixth': thirtySixthBattleMapUrl,
'battle-map-thirty-seventh': thirtySeventhBattleMapUrl,
'battle-map-thirty-eighth': thirtyEighthBattleMapUrl,
'battle-map-thirty-ninth': thirtyNinthBattleMapUrl,
'battle-map-fortieth': fortiethBattleMapUrl,
'battle-map-forty-first': fortyFirstBattleMapUrl,
'battle-map-forty-second': fortySecondBattleMapUrl,
'battle-map-forty-third': fortyThirdBattleMapUrl,
'battle-map-forty-fourth': fortyFourthBattleMapUrl,
'battle-map-forty-fifth': fortyFifthBattleMapUrl,
'battle-map-forty-sixth': fortySixthBattleMapUrl,
'battle-map-forty-seventh': fortySeventhBattleMapUrl,
'battle-map-forty-eighth': fortyEighthBattleMapUrl,
'battle-map-forty-ninth': fortyNinthBattleMapUrl,
'battle-map-fiftieth': fiftiethBattleMapUrl,
'battle-map-fifty-first': fiftyFirstBattleMapUrl
};

View File

@@ -3,6 +3,10 @@ import {
fiftiethBattleMap,
fiftiethBattleUnits,
fiftiethBattleVictoryPages,
fiftyFirstBattleBonds,
fiftyFirstBattleMap,
fiftyFirstBattleUnits,
fiftyFirstBattleVictoryPages,
firstBattleBonds,
fifteenthBattleBonds,
fifteenthBattleMap,
@@ -255,7 +259,8 @@ export type BattleScenarioId =
| 'forty-seventh-battle-nanzhong-stabilization'
| 'forty-eighth-battle-meng-huo-main-force'
| 'forty-ninth-battle-meng-huo-second-capture'
| 'fiftieth-battle-meng-huo-third-capture';
| 'fiftieth-battle-meng-huo-third-capture'
| 'fifty-first-battle-meng-huo-fourth-capture';
export type BattleObjectiveKind = 'defeat-leader' | 'pacify-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
@@ -3247,6 +3252,73 @@ export const fiftiethBattleScenario: BattleScenarioDefinition = {
nextCampScene: 'CampScene'
};
export const fiftyFirstBattleScenario: BattleScenarioDefinition = {
id: 'fifty-first-battle-meng-huo-fourth-capture',
title: '칠종칠금 4차전',
victoryConditionLabel: '맹획 네 번째 생포와 회유 퇴로 유지',
defeatConditionLabel: '제갈량 퇴각',
openingObjectiveLines: [
'세 번째 생포 뒤 호족 회의에서 열어 둔 퇴로가 이번 전장의 핵심입니다. 물러설 뜻이 있는 호족을 몰살하면 남중은 다시 모두 적이 됩니다.',
'오돌골의 등갑병과 독천 제사장들이 화덕 주변을 지키고 있습니다. 화덕 요새를 제압하되 마을과 포로장을 지켜, 촉한군의 약속이 전투 중에도 지켜진다는 것을 보여야 합니다.',
'제갈량은 반드시 생존해야 합니다. 마량으로 호족 문서를 전하고, 황권과 왕평으로 장부와 퇴로를 지키며, 마초와 마대로 추격선을 조절하십시오.'
],
map: fiftyFirstBattleMap,
units: fiftyFirstBattleUnits,
bonds: fiftyFirstBattleBonds,
mapTextureKey: 'battle-map-fifty-first',
leaderUnitId: 'menghuo-fourth-leader',
quickVictoryTurnLimit: 94,
baseVictoryGold: 12280,
objectives: [
{
id: 'pacify-meng-huo-fourth',
kind: 'pacify-leader',
label: '맹획 네 번째 생포',
rewardGold: 8420,
unitId: 'menghuo-fourth-leader'
},
{
id: 'zhuge-liang',
kind: 'keep-unit-alive',
label: '제갈량 생존',
rewardGold: 2140,
unitId: 'zhuge-liang'
},
{
id: 'amnesty-route',
kind: 'secure-terrain',
label: '회유 퇴로 유지',
rewardGold: 4140,
terrain: 'road'
},
{
id: 'captive-camps',
kind: 'secure-terrain',
label: '포로장 보증 유지',
rewardGold: 3360,
terrain: 'camp'
},
{
id: 'fire-forts',
kind: 'secure-terrain',
label: '화덕 요새 제압',
rewardGold: 3640,
terrain: 'fort'
},
{
id: 'quick',
kind: 'quick-victory',
label: '94턴 이내 네 번째 생포',
rewardGold: 2780,
maxTurn: 94
}
],
defeatConditions: [{ kind: 'unit-defeated', unitId: 'zhuge-liang' }],
itemRewards: ['콩 66', '상처약 50', '탁주 22', '호족 보증 장부 1', '회유 퇴로 표식 1'],
victoryPages: fiftyFirstBattleVictoryPages,
nextCampScene: 'CampScene'
};
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
@@ -3299,7 +3371,8 @@ export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition>
'forty-seventh-battle-nanzhong-stabilization': fortySeventhBattleScenario,
'forty-eighth-battle-meng-huo-main-force': fortyEighthBattleScenario,
'forty-ninth-battle-meng-huo-second-capture': fortyNinthBattleScenario,
'fiftieth-battle-meng-huo-third-capture': fiftiethBattleScenario
'fiftieth-battle-meng-huo-third-capture': fiftiethBattleScenario,
'fifty-first-battle-meng-huo-fourth-capture': fiftyFirstBattleScenario
};
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];

View File

@@ -5,6 +5,7 @@ import {
eighteenthBattleScenario,
eleventhBattleScenario,
fiftiethBattleScenario,
fiftyFirstBattleScenario,
fortiethBattleScenario,
fortyFirstBattleScenario,
fortySecondBattleScenario,
@@ -62,6 +63,8 @@ import {
eleventhBattleVictoryPages,
fiftiethBattleIntroPages,
fiftiethBattleVictoryPages,
fiftyFirstBattleIntroPages,
fiftyFirstBattleVictoryPages,
fortiethBattleIntroPages,
fortiethBattleVictoryPages,
fortyFirstBattleIntroPages,
@@ -731,13 +734,24 @@ const sortieFlows: Record<string, SortieFlow> = {
},
[fiftiethBattleScenario.id]: {
afterBattleId: fiftiethBattleScenario.id,
eyebrow: '다음 장 준비',
title: '호족 회유 회의',
eyebrow: '다음 장',
title: fiftyFirstBattleScenario.title,
description:
'맹획은 세 번째로 붙잡혔고, 그를 따르던 호족들의 말도 흔들리기 시작했습니다. 다음 장에서는 전투 전 회의에서 어떤 호족을 먼저 달랠지 고르고, 그 선택이 다음 남중 전장의 목표와 추천 출전에 영향을 주는 흐름을 준비합니다.',
rewardHint: '다음 장: 남중 호족 회유 회의와 칠종칠금 4차전 준비 중',
pages: fiftiethBattleVictoryPages,
unavailableNotice: '칠종칠금 4차전은 다음 작업에서 이어집니다. 지금은 세 번째 생포 뒤의 호족 회유 선택지와 출전 추천 변화를 정비할 수 있습니다.'
'세 번째 생포 뒤 열린 호족 회의는 전장의 조건을 바꾸었습니다. 이제 회유 퇴로를 남기고, 독천과 화덕 요새를 억제하며, 흔들리는 호족들이 직접 촉한군의 약속을 보게 해야 합니다.',
rewardHint: `예상 보상: ${fiftyFirstBattleScenario.title} 개방 / 호족 보증 장부`,
nextBattleId: fiftyFirstBattleScenario.id,
campaignStep: 'fifty-first-battle',
pages: [...fiftiethBattleVictoryPages, ...fiftyFirstBattleIntroPages]
},
[fiftyFirstBattleScenario.id]: {
afterBattleId: fiftyFirstBattleScenario.id,
eyebrow: '다음 장 준비',
title: '더 깊은 남중 회유',
description:
'맹획은 네 번째로 붙잡혔고, 회유 퇴로와 보증 장부는 남중 호족들의 말 속에 남았습니다. 다음 장에서는 더 깊은 산채와 강경파 호족을 상대로 같은 약속을 지킬 수 있는지 다룹니다.',
rewardHint: '다음 장: 칠종칠금 5차전과 남중 강경파 회유 준비 중',
pages: fiftyFirstBattleVictoryPages,
unavailableNotice: '칠종칠금 5차전은 다음 작업에서 이어집니다. 지금은 네 번째 생포 뒤의 보증 장부, 퇴로 표식, 강경파 분리 흐름을 정비할 수 있습니다.'
}
};

View File

@@ -3297,6 +3297,59 @@ export const fiftiethBattleVictoryPages: StoryPage[] = [
}
];
export const fiftyFirstBattleIntroPages: StoryPage[] = [
{
id: 'fifty-first-clan-council-result',
bgm: 'story-dark',
chapter: '회유가 전장으로',
background: 'story-militia',
speaker: '마량',
text: '호족 회의 뒤 일부 촌장은 맹획을 따르되 끝까지 싸우지는 않겠다고 속내를 보였습니다. 그들이 물러날 길을 남겨 두면 다음 전투는 섬멸보다 설득에 가까워질 것입니다.'
},
{
id: 'fifty-first-fourth-capture-plan',
bgm: 'battle-prep',
chapter: '네 번째 생포',
background: 'story-three-heroes',
speaker: '제갈량',
text: '이번에는 맹획의 본영뿐 아니라 오돌골의 등갑병과 독천 제사장들이 전장을 뒤덮을 것입니다. 화덕과 독천을 함부로 건드리지 말고, 회유 퇴로와 마을 보증을 함께 지키십시오.'
},
{
id: 'fifty-first-sortie',
bgm: 'battle-prep',
chapter: '칠종칠금 4차전',
background: 'story-sortie',
speaker: '왕평',
text: '숲길은 더 좁고 강물은 더 깊습니다. 마량이 호족의 말을 붙잡고, 황권이 보증 장부를 지키며, 왕평과 마대가 열어 둔 산길을 따라 맹획을 네 번째 생포해야 합니다.'
}
];
export const fiftyFirstBattleVictoryPages: StoryPage[] = [
{
id: 'fifty-first-victory-fourth-capture',
bgm: 'militia-theme',
chapter: '네 번째 생포',
background: 'story-sortie',
text: '맹획은 네 번째로 포위되었고, 등갑병의 화덕과 독천 제사장들은 마을까지 밀려오지 못했습니다. 회유 퇴로로 물러난 호족들은 촉한군이 약속한 길을 지켰다는 사실을 직접 보았습니다.'
},
{
id: 'fifty-first-victory-amnesty-route',
bgm: 'story-dark',
chapter: '열어 둔 길',
background: 'story-militia',
speaker: '황권',
text: '돌아간 자와 끝까지 싸운 자의 이름이 장부에 나뉘었습니다. 이제 남중의 호족들은 맹획의 고집만이 아니라, 촉한군의 약속이 지켜지는지도 함께 따지게 될 것입니다.'
},
{
id: 'fifty-first-next-deeper-nanzhong',
bgm: 'story-dark',
chapter: '더 깊은 남중',
background: 'story-three-heroes',
speaker: '제갈량',
text: '네 번 잡아도 맹획은 아직 남중 전체의 마음을 대표한다고 말합니다. 그렇다면 더 깊은 산채와 더 어려운 조건 앞에서도 같은 군율을 지켜 보여야 합니다.'
}
];
export const firstBattleMap: BattleMap = {
width: 20,
height: 18,
@@ -3742,6 +3795,12 @@ export const fiftiethBattleMap: BattleMap = {
terrain: createFiftiethBattleTerrain()
};
export const fiftyFirstBattleMap: BattleMap = {
width: 102,
height: 84,
terrain: createFiftyFirstBattleTerrain()
};
export const firstBattleUnits: UnitData[] = [
{
id: 'liu-bei',
@@ -16041,6 +16100,93 @@ export const fiftiethBattleUnits: UnitData[] = [
createThirtyFirstEnemyUnit('menghuo-third-leader', '맹획', '남만왕', 'rebelLeader', 150, 1010, 248, 94, 41)
];
const fiftyFirstBattleAllyPositions: Record<string, { x: number; y: number }> = {
'guan-yu': { x: 14, y: 63 },
'zhang-fei': { x: 19, y: 65 },
'jian-yong': { x: 10, y: 70 },
'mi-zhu': { x: 12, y: 68 },
'sun-qian': { x: 16, y: 72 },
'zhao-yun': { x: 24, y: 60 },
'zhuge-liang': { x: 13, y: 60 },
'ma-liang': { x: 17, y: 57 },
'yi-ji': { x: 10, y: 75 },
'gong-zhi': { x: 20, y: 73 },
'huang-zhong': { x: 27, y: 61 },
'wei-yan': { x: 32, y: 65 },
'pang-tong': { x: 15, y: 54 },
'fa-zheng': { x: 21, y: 55 },
'wu-yi': { x: 34, y: 70 },
'yan-yan': { x: 37, y: 63 },
'li-yan': { x: 26, y: 53 },
'huang-quan': { x: 10, y: 58 },
'ma-chao': { x: 39, y: 60 },
'ma-dai': { x: 42, y: 65 },
'wang-ping': { x: 29, y: 56 }
};
export const fiftyFirstBattleUnits: UnitData[] = [
...[
...firstBattleUnits.filter((unit) => unit.faction === 'ally' && unit.id !== 'liu-bei'),
...xuzhouRecruitUnits,
...caoBreakRecruitUnits,
...liuBiaoRecruitUnits,
...zhugeRecruitUnits,
...jingzhouRecruitUnits,
...guiyangRecruitUnits,
...wulingRecruitUnits,
...changshaRecruitUnits,
...yizhouRecruitUnits,
...fuPassRecruitUnits,
...luoCastleRecruitUnits,
...luoCastleProperRecruitUnits,
...chengduPressureRecruitUnits,
...chengduSurrenderRecruitUnits,
...hanzhongOpeningRecruitUnits,
...hanzhongScoutRecruitUnits,
...hanzhongMainRecruitUnits
].map((unit) => placeScenarioUnit(unit, fiftyFirstBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
createThirtyFirstEnemyUnit('menghuo-fourth-scout-a', '남만 회유 감시병', '서쪽 퇴로 감시', 'bandit', 148, 650, 196, 46, 36),
createThirtyFirstEnemyUnit('menghuo-fourth-scout-b', '남만 회유 감시병', '늪지 감시', 'bandit', 148, 650, 196, 61, 34),
createThirtyFirstEnemyUnit('menghuo-fourth-scout-c', '남만 회유 감시병', '장터 감시', 'bandit', 149, 658, 198, 76, 51),
createThirtyFirstEnemyUnit('menghuo-fourth-scout-d', '남만 회유 감시병', '동쪽 산길 감시', 'bandit', 149, 658, 198, 92, 66),
createThirtyFirstEnemyUnit('menghuo-fourth-scout-e', '남만 회유 감시병', '북쪽 협곡 감시', 'bandit', 150, 666, 200, 54, 24),
createThirtyFirstEnemyUnit('menghuo-fourth-vine-a', '등갑 화덕병', '늪지 등갑병', 'yellowTurban', 149, 914, 232, 51, 45),
createThirtyFirstEnemyUnit('menghuo-fourth-vine-b', '등갑 화덕병', '화덕 등갑병', 'yellowTurban', 150, 926, 234, 63, 48),
createThirtyFirstEnemyUnit('menghuo-fourth-vine-c', '등갑 화덕병', '마을 등갑병', 'yellowTurban', 150, 926, 234, 76, 58),
createThirtyFirstEnemyUnit('menghuo-fourth-vine-d', '등갑 화덕병', '본대 등갑병', 'yellowTurban', 151, 938, 236, 88, 50),
createThirtyFirstEnemyUnit('menghuo-fourth-vine-e', '등갑 화덕병', '후위 등갑병', 'yellowTurban', 151, 938, 236, 96, 42),
createThirtyFirstEnemyUnit('menghuo-fourth-vine-f', '등갑 화덕병', '협곡 등갑병', 'yellowTurban', 152, 950, 238, 84, 31),
createThirtyFirstEnemyUnit('menghuo-fourth-archer-a', '남만 산림 궁병', '독천 궁병', 'archer', 148, 702, 208, 47, 28),
createThirtyFirstEnemyUnit('menghuo-fourth-archer-b', '남만 산림 궁병', '절벽 궁병', 'archer', 149, 710, 210, 62, 26),
createThirtyFirstEnemyUnit('menghuo-fourth-archer-c', '남만 산림 궁병', '마을 궁병', 'archer', 149, 710, 210, 74, 44),
createThirtyFirstEnemyUnit('menghuo-fourth-archer-d', '남만 산림 궁병', '늪지 궁병', 'archer', 150, 718, 212, 86, 62),
createThirtyFirstEnemyUnit('menghuo-fourth-archer-e', '남만 산림 궁병', '본영 궁병', 'archer', 150, 718, 212, 95, 55),
createThirtyFirstEnemyUnit('menghuo-fourth-beast-a', '남만 맹수 유인대', '강가 맹수대', 'cavalry', 150, 930, 236, 56, 38),
createThirtyFirstEnemyUnit('menghuo-fourth-beast-b', '남만 맹수 유인대', '늪지 맹수대', 'cavalry', 150, 930, 236, 69, 40),
createThirtyFirstEnemyUnit('menghuo-fourth-beast-c', '남만 맹수 유인대', '산채 맹수대', 'cavalry', 151, 942, 238, 81, 53),
createThirtyFirstEnemyUnit('menghuo-fourth-beast-d', '남만 맹수 유인대', '추격 맹수대', 'cavalry', 151, 942, 238, 93, 59),
createThirtyFirstEnemyUnit('menghuo-fourth-beast-e', '남만 맹수 유인대', '회유로 차단대', 'cavalry', 152, 954, 240, 67, 68),
createThirtyFirstEnemyUnit('menghuo-fourth-ambusher-a', '호족 반전 매복병', '덩굴 매복병', 'bandit', 149, 670, 202, 38, 51),
createThirtyFirstEnemyUnit('menghuo-fourth-ambusher-b', '호족 반전 매복병', '숲속 매복병', 'bandit', 150, 678, 204, 54, 54),
createThirtyFirstEnemyUnit('menghuo-fourth-ambusher-c', '호족 반전 매복병', '강가 매복병', 'bandit', 150, 678, 204, 67, 67),
createThirtyFirstEnemyUnit('menghuo-fourth-ambusher-d', '호족 반전 매복병', '후방 차단대', 'bandit', 151, 686, 206, 86, 74),
createThirtyFirstEnemyUnit('menghuo-fourth-ambusher-e', '호족 반전 매복병', '서쪽 차단대', 'bandit', 151, 686, 206, 33, 64),
createThirtyFirstEnemyUnit('menghuo-fourth-ambusher-f', '호족 반전 매복병', '회유로 감시대', 'bandit', 152, 694, 208, 73, 72),
createThirtyFirstEnemyUnit('menghuo-fourth-guard-a', '맹획 사차 친위', '포로장 친위대', 'yellowTurban', 152, 966, 242, 71, 42),
createThirtyFirstEnemyUnit('menghuo-fourth-guard-b', '맹획 사차 친위', '산채 친위대', 'yellowTurban', 152, 966, 242, 83, 48),
createThirtyFirstEnemyUnit('menghuo-fourth-guard-c', '맹획 사차 친위', '본영 친위대', 'yellowTurban', 153, 978, 244, 94, 45),
createThirtyFirstEnemyUnit('menghuo-fourth-guard-d', '맹획 사차 친위', '화덕 친위대', 'yellowTurban', 153, 978, 244, 89, 35),
createThirtyFirstEnemyUnit('menghuo-fourth-shaman-a', '독천 제사장', '늪지 제사장', 'strategist', 151, 744, 218, 63, 36),
createThirtyFirstEnemyUnit('menghuo-fourth-shaman-b', '독천 제사장', '강가 제사장', 'strategist', 152, 752, 220, 77, 49),
createThirtyFirstEnemyUnit('menghuo-fourth-shaman-c', '독천 제사장', '산채 제사장', 'strategist', 152, 752, 220, 88, 38),
createThirtyFirstEnemyUnit('menghuo-fourth-shaman-d', '독천 제사장', '화덕 제사장', 'strategist', 153, 760, 222, 82, 57),
createThirtyFirstEnemyUnit('menghuo-fourth-officer-wutugu', '오돌골', '등갑병 두령', 'rebelLeader', 154, 1010, 252, 86, 37),
createThirtyFirstEnemyUnit('menghuo-fourth-officer-mangyachang', '망아장', '맹수 선봉장', 'rebelLeader', 154, 1010, 252, 81, 65),
createThirtyFirstEnemyUnit('menghuo-fourth-officer-dongtuna', '동도나', '흔들리는 호족장', 'rebelLeader', 153, 990, 246, 70, 60),
createThirtyFirstEnemyUnit('menghuo-fourth-officer-ahuinan', '아회남', '회유로 감시 호족', 'rebelLeader', 153, 990, 246, 66, 52),
createThirtyFirstEnemyUnit('menghuo-fourth-leader', '맹획', '남만왕', 'rebelLeader', 156, 1048, 258, 96, 43)
];
export const firstBattleBonds: BattleBond[] = [
{
id: 'liu-bei__guan-yu',
@@ -16976,6 +17122,35 @@ export const mengHuoThirdCaptureBonds: BattleBond[] = [
export const fiftiethBattleBonds: BattleBond[] = [...fortyNinthBattleBonds, ...mengHuoThirdCaptureBonds].map(
cloneBattleBondForScenario
);
export const mengHuoFourthCaptureBonds: BattleBond[] = [
{
id: 'zhuge-liang__ma-liang_fourth-capture',
unitIds: ['zhuge-liang', 'ma-liang'],
title: '회유 회의의 결실',
level: 51,
exp: 0,
description: '제갈량의 큰 회유책과 마량의 호족 설득문은 전장 안에서 물러날 길과 항복의 명분을 함께 만든다.'
},
{
id: 'huang-quan__wang-ping_fourth-capture',
unitIds: ['huang-quan', 'wang-ping'],
title: '보증 장부와 퇴로',
level: 47,
exp: 0,
description: '황권의 보증 장부와 왕평의 산길 판단은 흔들리는 호족들이 다시 창을 들지 않고 물러날 길을 보장한다.'
},
{
id: 'ma-chao__ma-dai_fourth-capture',
unitIds: ['ma-chao', 'ma-dai'],
title: '남중 추격 차단',
level: 43,
exp: 0,
description: '마초와 마대는 거친 남만 기병을 몰아붙이되, 회유 퇴로를 짓밟지 않도록 돌격의 선을 맞춘다.'
}
];
export const fiftyFirstBattleBonds: BattleBond[] = [...fiftiethBattleBonds, ...mengHuoFourthCaptureBonds].map(
cloneBattleBondForScenario
);
function createEighthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 22 }, (_, y) =>
@@ -19549,6 +19724,74 @@ function createFiftiethBattleTerrain(): TerrainType[][] {
);
}
function createFiftyFirstBattleTerrain(): TerrainType[][] {
return Array.from({ length: 84 }, (_, y) =>
Array.from({ length: 102 }, (_, x): TerrainType => {
if (
(x >= 0 && x <= 101 && y >= 76) ||
(x >= 62 && x <= 68 && y >= 0 && y <= 78) ||
(x >= 5 && x <= 30 && y >= 67 && y <= 83) ||
(x >= 76 && x <= 92 && y >= 58 && y <= 76)
) {
return 'river';
}
if (
(x >= 9 && x <= 96 && y >= 63 && y <= 69) ||
(x >= 27 && x <= 74 && y >= 42 && y <= 49) ||
(x >= 70 && x <= 96 && y >= 34 && y <= 40) ||
(x >= 37 && x <= 45 && y >= 39 && y <= 72) ||
(x >= 76 && x <= 82 && y >= 48 && y <= 80)
) {
return 'road';
}
if (
(x >= 18 && x <= 72 && y >= 20 && y <= 74) ||
(x >= 55 && x <= 96 && y >= 28 && y <= 70) ||
(x >= 2 && x <= 38 && y >= 49 && y <= 74) ||
(x >= 78 && x <= 101 && y >= 41 && y <= 73)
) {
return 'forest';
}
if (
(x >= 0 && x <= 31 && y <= 38) ||
(x >= 33 && x <= 68 && y <= 28) ||
(x >= 71 && x <= 101 && y <= 37) ||
(x >= 86 && x <= 101 && y >= 33 && y <= 55)
) {
return 'hill';
}
if (
(x <= 2 && y <= 74) ||
(x >= 99 && y <= 70) ||
(x >= 30 && x <= 36 && y >= 0 && y <= 40) ||
(x >= 68 && x <= 74 && y >= 0 && y <= 34) ||
(x >= 42 && x <= 48 && y >= 64 && y <= 83)
) {
return 'cliff';
}
if (
(x >= 10 && x <= 25 && y >= 59 && y <= 71) ||
(x >= 39 && x <= 54 && y >= 43 && y <= 56) ||
(x >= 75 && x <= 91 && y >= 49 && y <= 61) ||
(x >= 80 && x <= 94 && y >= 32 && y <= 44)
) {
return 'village';
}
if ((x >= 23 && x <= 37 && y >= 51 && y <= 62) || (x >= 63 && x <= 78 && y >= 56 && y <= 68)) {
return 'camp';
}
if (
(x >= 47 && x <= 63 && y >= 31 && y <= 42) ||
(x >= 72 && x <= 92 && y >= 31 && y <= 45) ||
(x >= 84 && x <= 96 && y >= 43 && y <= 54)
) {
return 'fort';
}
return 'plain';
})
);
}
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
return {
...cloneUnitForScenario(unit),