Add final Meng Huo capture battle

This commit is contained in:
2026-06-24 00:35:04 +09:00
parent a54e852c2b
commit 1c26583508
11 changed files with 883 additions and 63 deletions

View File

@@ -5,6 +5,7 @@ import fiftiethBattleMapUrl from '../../assets/images/battle/fiftieth-battle-map
import fiftyFirstBattleMapUrl from '../../assets/images/battle/fifty-first-battle-map.svg';
import fiftySecondBattleMapUrl from '../../assets/images/battle/fifty-second-battle-map.svg';
import fiftyThirdBattleMapUrl from '../../assets/images/battle/fifty-third-battle-map.svg';
import fiftyFourthBattleMapUrl from '../../assets/images/battle/fifty-fourth-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';
@@ -105,5 +106,6 @@ export const battleMapAssets: Record<string, string> = {
'battle-map-fiftieth': fiftiethBattleMapUrl,
'battle-map-fifty-first': fiftyFirstBattleMapUrl,
'battle-map-fifty-second': fiftySecondBattleMapUrl,
'battle-map-fifty-third': fiftyThirdBattleMapUrl
'battle-map-fifty-third': fiftyThirdBattleMapUrl,
'battle-map-fifty-fourth': fiftyFourthBattleMapUrl
};

View File

@@ -15,6 +15,10 @@ import {
fiftyThirdBattleMap,
fiftyThirdBattleUnits,
fiftyThirdBattleVictoryPages,
fiftyFourthBattleBonds,
fiftyFourthBattleMap,
fiftyFourthBattleUnits,
fiftyFourthBattleVictoryPages,
firstBattleBonds,
fifteenthBattleBonds,
fifteenthBattleMap,
@@ -270,7 +274,8 @@ export type BattleScenarioId =
| 'fiftieth-battle-meng-huo-third-capture'
| 'fifty-first-battle-meng-huo-fourth-capture'
| 'fifty-second-battle-meng-huo-fifth-capture'
| 'fifty-third-battle-meng-huo-sixth-capture';
| 'fifty-third-battle-meng-huo-sixth-capture'
| 'fifty-fourth-battle-meng-huo-final-capture';
export type BattleObjectiveKind = 'defeat-leader' | 'pacify-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
@@ -3463,6 +3468,73 @@ export const fiftyThirdBattleScenario: BattleScenarioDefinition = {
nextCampScene: 'CampScene'
};
export const fiftyFourthBattleScenario: BattleScenarioDefinition = {
id: 'fifty-fourth-battle-meng-huo-final-capture',
title: '칠종칠금 7차전',
victoryConditionLabel: '맹획 마지막 생포와 남중 회의장 보호',
defeatConditionLabel: '제갈량 퇴각',
openingObjectiveLines: [
'맹획은 일곱 번째이자 마지막 대결을 남중의 촌장들이 보는 앞에서 열었습니다. 이번 전투는 승리뿐 아니라 군율과 약속을 증명하는 자리입니다.',
'회의장과 마을, 항복로가 무너지면 맹획을 잡아도 남중의 마음은 닫힙니다. 잔당 요새를 누르고, 물러설 자의 길과 촌장들의 증언을 지키십시오.',
'제갈량은 반드시 생존해야 합니다. 황권은 약속 장부를, 마량과 왕평은 회의장과 마을길을, 조운과 마대는 항복로 차단선을 맡기 좋습니다.'
],
map: fiftyFourthBattleMap,
units: fiftyFourthBattleUnits,
bonds: fiftyFourthBattleBonds,
mapTextureKey: 'battle-map-fifty-fourth',
leaderUnitId: 'menghuo-final-leader',
quickVictoryTurnLimit: 106,
baseVictoryGold: 14360,
objectives: [
{
id: 'pacify-meng-huo-final',
kind: 'pacify-leader',
label: '맹획 일곱 번째 생포',
rewardGold: 9640,
unitId: 'menghuo-final-leader'
},
{
id: 'zhuge-liang',
kind: 'keep-unit-alive',
label: '제갈량 생존',
rewardGold: 2420,
unitId: 'zhuge-liang'
},
{
id: 'council-road',
kind: 'secure-terrain',
label: '항복 회의장 길 확보',
rewardGold: 4820,
terrain: 'road'
},
{
id: 'village-witnesses',
kind: 'secure-terrain',
label: '촌장 증언 마을 보호',
rewardGold: 4480,
terrain: 'village'
},
{
id: 'final-remnant-forts',
kind: 'secure-terrain',
label: '최후 잔당 요새 제압',
rewardGold: 4260,
terrain: 'fort'
},
{
id: 'quick',
kind: 'quick-victory',
label: '106턴 이내 마지막 생포',
rewardGold: 3220,
maxTurn: 106
}
],
defeatConditions: [{ kind: 'unit-defeated', unitId: 'zhuge-liang' }],
itemRewards: ['콩 80', '상처약 64', '탁주 30', '남중 평정 장부 1', '맹획 항복 서약 1'],
victoryPages: fiftyFourthBattleVictoryPages,
nextCampScene: 'CampScene'
};
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
@@ -3518,7 +3590,8 @@ export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition>
'fiftieth-battle-meng-huo-third-capture': fiftiethBattleScenario,
'fifty-first-battle-meng-huo-fourth-capture': fiftyFirstBattleScenario,
'fifty-second-battle-meng-huo-fifth-capture': fiftySecondBattleScenario,
'fifty-third-battle-meng-huo-sixth-capture': fiftyThirdBattleScenario
'fifty-third-battle-meng-huo-sixth-capture': fiftyThirdBattleScenario,
'fifty-fourth-battle-meng-huo-final-capture': fiftyFourthBattleScenario
};
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];

View File

@@ -8,6 +8,7 @@ import {
fiftyFirstBattleScenario,
fiftySecondBattleScenario,
fiftyThirdBattleScenario,
fiftyFourthBattleScenario,
fortiethBattleScenario,
fortyFirstBattleScenario,
fortySecondBattleScenario,
@@ -71,6 +72,8 @@ import {
fiftySecondBattleVictoryPages,
fiftyThirdBattleIntroPages,
fiftyThirdBattleVictoryPages,
fiftyFourthBattleIntroPages,
fiftyFourthBattleVictoryPages,
fortiethBattleIntroPages,
fortiethBattleVictoryPages,
fortyFirstBattleIntroPages,
@@ -773,13 +776,24 @@ const sortieFlows: Record<string, SortieFlow> = {
},
[fiftyThirdBattleScenario.id]: {
afterBattleId: fiftyThirdBattleScenario.id,
eyebrow: '다음 장 준비',
title: '칠종칠금의 마지막 문턱',
eyebrow: '다음 장',
title: fiftyFourthBattleScenario.title,
description:
'맹획은 여섯 번째로 붙잡혔고, 남중의 마을들은 촉한군의 약속을 직접 보았습니다. 다음 장에서는 칠종칠금의 마지막 설득과 남중 안정의 결말을 준비합니다.',
rewardHint: '다음 장: 칠종칠금 7차전과 남중 완전 회유 준비 중',
pages: fiftyThirdBattleVictoryPages,
unavailableNotice: '칠종칠금 7차전은 다음 작업에서 이어집니다. 지금은 여섯 번째 생포 뒤의 신뢰 장부와 계곡 회유 표식을 정비할 수 있습니다.'
'맹획은 여섯 번째로 붙잡혔고, 남중의 마을들은 촉한군의 약속을 직접 보았습니다. 이제 마지막 회의장 앞에서 맹획의 고집과 남중의 마음을 함께 마주합니다.',
rewardHint: `예상 보상: ${fiftyFourthBattleScenario.title} 개방 / 남중 평정 장부`,
nextBattleId: fiftyFourthBattleScenario.id,
campaignStep: 'fifty-fourth-battle',
pages: [...fiftyThirdBattleVictoryPages, ...fiftyFourthBattleIntroPages]
},
[fiftyFourthBattleScenario.id]: {
afterBattleId: fiftyFourthBattleScenario.id,
eyebrow: '다음 장 준비',
title: '남중 평정 이후',
description:
'맹획은 일곱 번의 생포 끝에 항복했고, 남중은 촉한의 약속을 받아들였습니다. 이제 제갈량은 뒤를 안정시킨 뒤 북쪽을 향한 다음 장기전을 준비해야 합니다.',
rewardHint: '다음 장: 북벌 준비와 촉한 내부 정비 준비 중',
pages: fiftyFourthBattleVictoryPages,
unavailableNotice: '북벌 준비 장은 다음 작업에서 이어집니다. 지금은 남중 평정 장부와 맹획 항복 서약을 정비할 수 있습니다.'
}
};

View File

@@ -3456,6 +3456,59 @@ export const fiftyThirdBattleVictoryPages: StoryPage[] = [
}
];
export const fiftyFourthBattleIntroPages: StoryPage[] = [
{
id: 'fifty-fourth-final-council',
bgm: 'story-dark',
chapter: '마지막 문턱',
background: 'story-militia',
speaker: '마량',
text: '여섯 번째 생포 뒤 남중의 촌장들은 더는 맹획의 말만 듣지 않았습니다. 그러나 맹획은 마지막 자존심을 걸고, 모든 부족 앞에서 다시 한 번 싸워 보자고 외쳤습니다.'
},
{
id: 'fifty-fourth-seventh-capture-plan',
bgm: 'battle-prep',
chapter: '일곱 번째 생포',
background: 'story-three-heroes',
speaker: '제갈량',
text: '이번 싸움은 남중을 꺾는 전투가 아니라 남중이 스스로 고개를 끄덕이게 만드는 전투입니다. 맹획을 마지막으로 생포하되, 회의장과 마을, 신뢰 장부를 모두 지키십시오.'
},
{
id: 'fifty-fourth-sortie',
bgm: 'battle-prep',
chapter: '칠종칠금 7차전',
background: 'story-sortie',
speaker: '왕평',
text: '마지막 전장은 길이 많아 보이지만, 잘못 밀고 들어가면 촌장들이 보는 앞에서 군율을 잃게 됩니다. 빠른 장수는 추격을 멈추고, 문사는 약속을 남기며, 전열은 회의장을 지켜야 합니다.'
}
];
export const fiftyFourthBattleVictoryPages: StoryPage[] = [
{
id: 'fifty-fourth-victory-seventh-capture',
bgm: 'militia-theme',
chapter: '일곱 번째 생포',
background: 'story-sortie',
text: '맹획은 일곱 번째로 포위되었습니다. 그러나 이번에는 포로장의 침묵이 아니라, 촌장들의 눈앞에서 지켜진 약속과 무너진 고집이 함께 남았습니다.'
},
{
id: 'fifty-fourth-victory-meng-huo-yields',
bgm: 'story-dark',
chapter: '맹획의 항복',
background: 'story-three-heroes',
speaker: '맹획',
text: '일곱 번 잡히고 일곱 번 풀려도 그대들은 남중의 백성을 짓밟지 않았다. 이제는 내가 졌음을 인정하겠다. 남중의 길은 촉한의 길과 함께하겠다.'
},
{
id: 'fifty-fourth-nanzhong-pacified',
bgm: 'story-dark',
chapter: '남중 평정',
background: 'story-militia',
speaker: '제갈량',
text: '남중은 힘으로만 묶인 땅이 아닙니다. 약속을 지킨 뒤 얻은 땅입니다. 이제 촉한은 뒤를 안정시키고, 북쪽을 바라볼 준비를 시작해야 합니다.'
}
];
export const firstBattleMap: BattleMap = {
width: 20,
height: 18,
@@ -3919,6 +3972,12 @@ export const fiftyThirdBattleMap: BattleMap = {
terrain: createFiftyThirdBattleTerrain()
};
export const fiftyFourthBattleMap: BattleMap = {
width: 108,
height: 90,
terrain: createFiftyFourthBattleTerrain()
};
export const firstBattleUnits: UnitData[] = [
{
id: 'liu-bei',
@@ -16482,6 +16541,96 @@ export const fiftyThirdBattleUnits: UnitData[] = [
createThirtyFirstEnemyUnit('menghuo-sixth-leader', '맹획', '남만왕', 'rebelLeader', 168, 1140, 280, 100, 47)
];
const fiftyFourthBattleAllyPositions: Record<string, { x: number; y: number }> = {
'guan-yu': { x: 17, y: 69 },
'zhang-fei': { x: 22, y: 71 },
'jian-yong': { x: 13, y: 76 },
'mi-zhu': { x: 15, y: 74 },
'sun-qian': { x: 19, y: 78 },
'zhao-yun': { x: 27, y: 66 },
'zhuge-liang': { x: 16, y: 66 },
'ma-liang': { x: 20, y: 63 },
'yi-ji': { x: 13, y: 81 },
'gong-zhi': { x: 23, y: 79 },
'huang-zhong': { x: 30, y: 67 },
'wei-yan': { x: 35, y: 71 },
'pang-tong': { x: 18, y: 60 },
'fa-zheng': { x: 24, y: 61 },
'wu-yi': { x: 37, y: 76 },
'yan-yan': { x: 40, y: 69 },
'li-yan': { x: 29, y: 59 },
'huang-quan': { x: 13, y: 64 },
'ma-chao': { x: 42, y: 66 },
'ma-dai': { x: 45, y: 71 },
'wang-ping': { x: 32, y: 62 }
};
export const fiftyFourthBattleUnits: 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, fiftyFourthBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
createThirtyFirstEnemyUnit('menghuo-final-scout-a', '남만 최후 척후', '서쪽 회의장 정찰', 'bandit', 166, 748, 222, 50, 42),
createThirtyFirstEnemyUnit('menghuo-final-scout-b', '남만 최후 척후', '물길 정찰', 'bandit', 166, 748, 222, 66, 40),
createThirtyFirstEnemyUnit('menghuo-final-scout-c', '남만 최후 척후', '마을 감시', 'bandit', 167, 756, 224, 82, 57),
createThirtyFirstEnemyUnit('menghuo-final-scout-d', '남만 최후 척후', '동쪽 산문 감시', 'bandit', 167, 756, 224, 98, 72),
createThirtyFirstEnemyUnit('menghuo-final-scout-e', '남만 최후 척후', '북쪽 절벽 감시', 'bandit', 168, 764, 226, 59, 30),
createThirtyFirstEnemyUnit('menghuo-final-scout-f', '남만 최후 척후', '항복로 감시', 'bandit', 168, 764, 226, 74, 78),
createThirtyFirstEnemyUnit('menghuo-final-vine-a', '최후 등갑병', '회의장 등갑병', 'yellowTurban', 167, 1044, 260, 56, 51),
createThirtyFirstEnemyUnit('menghuo-final-vine-b', '최후 등갑병', '불씨 등갑병', 'yellowTurban', 168, 1056, 262, 69, 54),
createThirtyFirstEnemyUnit('menghuo-final-vine-c', '최후 등갑병', '마을 등갑병', 'yellowTurban', 168, 1056, 262, 82, 64),
createThirtyFirstEnemyUnit('menghuo-final-vine-d', '최후 등갑병', '본영 등갑병', 'yellowTurban', 169, 1068, 264, 94, 56),
createThirtyFirstEnemyUnit('menghuo-final-vine-e', '최후 등갑병', '후위 등갑병', 'yellowTurban', 169, 1068, 264, 102, 48),
createThirtyFirstEnemyUnit('menghuo-final-vine-f', '최후 등갑병', '산문 등갑병', 'yellowTurban', 170, 1080, 266, 90, 37),
createThirtyFirstEnemyUnit('menghuo-final-archer-a', '남만 회의장 궁병', '독천 궁병', 'archer', 166, 800, 234, 52, 34),
createThirtyFirstEnemyUnit('menghuo-final-archer-b', '남만 회의장 궁병', '절벽 궁병', 'archer', 167, 808, 236, 68, 32),
createThirtyFirstEnemyUnit('menghuo-final-archer-c', '남만 회의장 궁병', '마을 궁병', 'archer', 167, 808, 236, 80, 50),
createThirtyFirstEnemyUnit('menghuo-final-archer-d', '남만 회의장 궁병', '물길 궁병', 'archer', 168, 816, 238, 92, 68),
createThirtyFirstEnemyUnit('menghuo-final-archer-e', '남만 회의장 궁병', '본영 궁병', 'archer', 168, 816, 238, 101, 61),
createThirtyFirstEnemyUnit('menghuo-final-beast-a', '남만 최후 맹수대', '강가 맹수대', 'cavalry', 168, 1060, 264, 62, 44),
createThirtyFirstEnemyUnit('menghuo-final-beast-b', '남만 최후 맹수대', '물길 맹수대', 'cavalry', 168, 1060, 264, 75, 46),
createThirtyFirstEnemyUnit('menghuo-final-beast-c', '남만 최후 맹수대', '산채 맹수대', 'cavalry', 169, 1072, 266, 87, 59),
createThirtyFirstEnemyUnit('menghuo-final-beast-d', '남만 최후 맹수대', '추격 맹수대', 'cavalry', 169, 1072, 266, 99, 65),
createThirtyFirstEnemyUnit('menghuo-final-beast-e', '남만 최후 맹수대', '항복로 차단대', 'cavalry', 170, 1084, 268, 73, 74),
createThirtyFirstEnemyUnit('menghuo-final-ambusher-a', '최후 매복병', '회의장 매복병', 'bandit', 167, 768, 228, 43, 57),
createThirtyFirstEnemyUnit('menghuo-final-ambusher-b', '최후 매복병', '숲속 매복병', 'bandit', 168, 776, 230, 59, 60),
createThirtyFirstEnemyUnit('menghuo-final-ambusher-c', '최후 매복병', '강가 매복병', 'bandit', 168, 776, 230, 72, 73),
createThirtyFirstEnemyUnit('menghuo-final-ambusher-d', '최후 매복병', '후방 차단대', 'bandit', 169, 784, 232, 92, 80),
createThirtyFirstEnemyUnit('menghuo-final-ambusher-e', '최후 매복병', '서쪽 차단대', 'bandit', 169, 784, 232, 38, 70),
createThirtyFirstEnemyUnit('menghuo-final-ambusher-f', '최후 매복병', '항복로 감시대', 'bandit', 170, 792, 234, 79, 78),
createThirtyFirstEnemyUnit('menghuo-final-guard-a', '맹획 최후 친위', '포로장 친위대', 'yellowTurban', 170, 1096, 270, 76, 48),
createThirtyFirstEnemyUnit('menghuo-final-guard-b', '맹획 최후 친위', '산채 친위대', 'yellowTurban', 170, 1096, 270, 89, 54),
createThirtyFirstEnemyUnit('menghuo-final-guard-c', '맹획 최후 친위', '본영 친위대', 'yellowTurban', 171, 1108, 272, 100, 51),
createThirtyFirstEnemyUnit('menghuo-final-guard-d', '맹획 최후 친위', '회의장 친위대', 'yellowTurban', 171, 1108, 272, 95, 41),
createThirtyFirstEnemyUnit('menghuo-final-shaman-a', '마지막 독천 제사장', '물길 제사장', 'strategist', 169, 848, 246, 68, 42),
createThirtyFirstEnemyUnit('menghuo-final-shaman-b', '마지막 독천 제사장', '강가 제사장', 'strategist', 170, 856, 248, 83, 55),
createThirtyFirstEnemyUnit('menghuo-final-shaman-c', '마지막 독천 제사장', '산채 제사장', 'strategist', 170, 856, 248, 94, 44),
createThirtyFirstEnemyUnit('menghuo-final-shaman-d', '마지막 독천 제사장', '회의장 제사장', 'strategist', 171, 864, 250, 88, 63),
createThirtyFirstEnemyUnit('menghuo-final-officer-zhurong', '축융 부인', '남중 화전장', 'rebelLeader', 172, 1138, 280, 86, 71),
createThirtyFirstEnemyUnit('menghuo-final-officer-mulu', '목록대왕', '맹수대왕', 'rebelLeader', 172, 1138, 280, 92, 43),
createThirtyFirstEnemyUnit('menghuo-final-officer-duosi', '타사대왕', '독천 호족장', 'rebelLeader', 171, 1118, 274, 76, 66),
createThirtyFirstEnemyUnit('menghuo-final-officer-mengyou', '맹우', '맹획의 아우', 'rebelLeader', 171, 1118, 274, 72, 58),
createThirtyFirstEnemyUnit('menghuo-final-officer-dailai', '대래동주', '깊은 산채 호족', 'rebelLeader', 171, 1118, 274, 85, 73),
createThirtyFirstEnemyUnit('menghuo-final-officer-ahuinan', '아회남', '흔들린 호족 대표', 'rebelLeader', 170, 1098, 270, 74, 70),
createThirtyFirstEnemyUnit('menghuo-final-leader', '맹획', '남만왕', 'rebelLeader', 174, 1180, 288, 102, 49)
];
export const firstBattleBonds: BattleBond[] = [
{
id: 'liu-bei__guan-yu',
@@ -17504,6 +17653,35 @@ export const mengHuoSixthCaptureBonds: BattleBond[] = [
export const fiftyThirdBattleBonds: BattleBond[] = [...fiftySecondBattleBonds, ...mengHuoSixthCaptureBonds].map(
cloneBattleBondForScenario
);
export const mengHuoFinalCaptureBonds: BattleBond[] = [
{
id: 'zhuge-liang__huang-quan_final-capture',
unitIds: ['zhuge-liang', 'huang-quan'],
title: '일곱 번의 약속',
level: 60,
exp: 0,
description: '제갈량의 마지막 회유와 황권의 약속 장부는 맹획의 항복이 굴욕이 아니라 남중의 새 질서가 되게 한다.'
},
{
id: 'ma-liang__wang-ping_final-capture',
unitIds: ['ma-liang', 'wang-ping'],
title: '마을과 회의장',
level: 56,
exp: 0,
description: '마량의 말과 왕평의 길 표식은 촌장들이 보는 앞에서도 촉한군의 군율이 흔들리지 않게 한다.'
},
{
id: 'zhao-yun__ma-dai_final-capture',
unitIds: ['zhao-yun', 'ma-dai'],
title: '멈추는 추격',
level: 50,
exp: 0,
description: '조운과 마대는 빠른 기동으로 잔당을 끊되, 항복로를 밟지 않는 절제의 선을 함께 지킨다.'
}
];
export const fiftyFourthBattleBonds: BattleBond[] = [...fiftyThirdBattleBonds, ...mengHuoFinalCaptureBonds].map(
cloneBattleBondForScenario
);
function createEighthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 22 }, (_, y) =>
@@ -20292,6 +20470,81 @@ function createFiftyThirdBattleTerrain(): TerrainType[][] {
);
}
function createFiftyFourthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 90 }, (_, y) =>
Array.from({ length: 108 }, (_, x): TerrainType => {
if (
(x >= 0 && x <= 107 && y >= 82) ||
(x >= 69 && x <= 75 && y >= 0 && y <= 84) ||
(x >= 7 && x <= 36 && y >= 73 && y <= 89) ||
(x >= 82 && x <= 100 && y >= 64 && y <= 82)
) {
return 'river';
}
if (
(x >= 10 && x <= 103 && y >= 69 && y <= 75) ||
(x >= 30 && x <= 80 && y >= 46 && y <= 54) ||
(x >= 75 && x <= 103 && y >= 38 && y <= 44) ||
(x >= 41 && x <= 50 && y >= 43 && y <= 78) ||
(x >= 82 && x <= 88 && y >= 52 && y <= 86) ||
(x >= 18 && x <= 56 && y >= 61 && y <= 65) ||
(x >= 54 && x <= 69 && y >= 55 && y <= 61) ||
(x >= 60 && x <= 76 && y >= 45 && y <= 53)
) {
return 'road';
}
if (
(x >= 18 && x <= 78 && y >= 23 && y <= 80) ||
(x >= 58 && x <= 102 && y >= 31 && y <= 76) ||
(x >= 2 && x <= 43 && y >= 54 && y <= 80) ||
(x >= 84 && x <= 107 && y >= 45 && y <= 79)
) {
return 'forest';
}
if (
(x >= 0 && x <= 34 && y <= 42) ||
(x >= 36 && x <= 74 && y <= 32) ||
(x >= 77 && x <= 107 && y <= 41) ||
(x >= 92 && x <= 107 && y >= 37 && y <= 61)
) {
return 'hill';
}
if (
(x <= 2 && y <= 80) ||
(x >= 105 && y <= 76) ||
(x >= 33 && x <= 39 && y >= 0 && y <= 44) ||
(x >= 74 && x <= 80 && y >= 0 && y <= 38) ||
(x >= 48 && x <= 54 && y >= 70 && y <= 89)
) {
return 'cliff';
}
if (
(x >= 13 && x <= 30 && y >= 65 && y <= 77) ||
(x >= 42 && x <= 60 && y >= 48 && y <= 62) ||
(x >= 81 && x <= 97 && y >= 54 && y <= 67) ||
(x >= 86 && x <= 100 && y >= 36 && y <= 49)
) {
return 'village';
}
if (
(x >= 26 && x <= 42 && y >= 57 && y <= 68) ||
(x >= 69 && x <= 84 && y >= 62 && y <= 74) ||
(x >= 87 && x <= 102 && y >= 43 && y <= 57)
) {
return 'camp';
}
if (
(x >= 51 && x <= 69 && y >= 35 && y <= 46) ||
(x >= 78 && x <= 99 && y >= 35 && y <= 50) ||
(x >= 90 && x <= 103 && y >= 48 && y <= 60)
) {
return 'fort';
}
return 'plain';
})
);
}
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
return {
...cloneUnitForScenario(unit),