Add Maicheng isolation chapter

This commit is contained in:
2026-06-23 18:55:38 +09:00
parent dac4ed0f5a
commit f9f0145c02
11 changed files with 918 additions and 51 deletions

View File

@@ -36,6 +36,10 @@ import {
fortyThirdBattleMap,
fortyThirdBattleUnits,
fortyThirdBattleVictoryPages,
fortyFourthBattleBonds,
fortyFourthBattleMap,
fortyFourthBattleUnits,
fortyFourthBattleVictoryPages,
firstBattleMap,
firstBattleUnits,
firstBattleVictoryPages,
@@ -220,7 +224,8 @@ export type BattleScenarioId =
| 'fortieth-battle-han-river-flood'
| 'forty-first-battle-fan-castle-siege'
| 'forty-second-battle-jing-rear-crisis'
| 'forty-third-battle-gongan-collapse';
| 'forty-third-battle-gongan-collapse'
| 'forty-fourth-battle-maicheng-isolation';
export type BattleObjectiveKind = 'defeat-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
@@ -2789,6 +2794,69 @@ export const fortyThirdBattleScenario: BattleScenarioDefinition = {
nextCampScene: 'CampScene'
};
export const fortyFourthBattleScenario: BattleScenarioDefinition = {
id: 'forty-fourth-battle-maicheng-isolation',
title: '맥성 고립전',
victoryConditionLabel: '맥성 포위망 돌파',
defeatConditionLabel: '유비 또는 관우 퇴각',
openingObjectiveLines: [
'공안 성문을 잠시 붙들었지만 후방 소식은 끊겼습니다. 맥성 북문으로 빠지는 좁은 길을 열어 관우 전선의 잔병을 수습하십시오.',
'강동군은 숲길과 갈대 물목을 막고, 위군 추격대는 북쪽 길을 압박합니다. 포위망의 한쪽만 밀어서는 길이 다시 닫힙니다.',
'왕평, 조운, 마대, 황충처럼 지형 판단과 기동, 고지 견제에 강한 장수를 데려가면 맥성의 좁은 퇴로를 지키기 좋습니다.'
],
map: fortyFourthBattleMap,
units: fortyFourthBattleUnits,
bonds: fortyFourthBattleBonds,
mapTextureKey: 'battle-map-forty-fourth',
leaderUnitId: 'maicheng-leader-lu-meng',
quickVictoryTurnLimit: 72,
baseVictoryGold: 9280,
objectives: [
{
id: 'leader',
kind: 'defeat-leader',
label: '여몽 봉쇄선 돌파',
rewardGold: 6120,
unitId: 'maicheng-leader-lu-meng'
},
{
id: 'liu-bei',
kind: 'keep-unit-alive',
label: '유비 생존',
rewardGold: 1440,
unitId: 'liu-bei'
},
{
id: 'guan-yu',
kind: 'keep-unit-alive',
label: '관우 생존',
rewardGold: 2260,
unitId: 'guan-yu'
},
{
id: 'maicheng-gate',
kind: 'secure-terrain',
label: '맥성 북문 확보',
rewardGold: 2960,
terrain: 'fort'
},
{
id: 'quick',
kind: 'quick-victory',
label: '72턴 이내 승리',
rewardGold: 2120,
maxTurn: 72
}
],
defeatConditions: [
{ kind: 'unit-defeated', unitId: 'liu-bei' },
{ kind: 'unit-defeated', unitId: 'guan-yu' }
],
itemRewards: ['콩 44', '상처약 34', '탁주 14', '맥성 북문 지도 1', '갈대 물목 표식 1'],
victoryPages: fortyFourthBattleVictoryPages,
nextCampScene: 'CampScene'
};
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
@@ -2834,7 +2902,8 @@ export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition>
'fortieth-battle-han-river-flood': fortiethBattleScenario,
'forty-first-battle-fan-castle-siege': fortyFirstBattleScenario,
'forty-second-battle-jing-rear-crisis': fortySecondBattleScenario,
'forty-third-battle-gongan-collapse': fortyThirdBattleScenario
'forty-third-battle-gongan-collapse': fortyThirdBattleScenario,
'forty-fourth-battle-maicheng-isolation': fortyFourthBattleScenario
};
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];

View File

@@ -8,6 +8,7 @@ import {
fortyFirstBattleScenario,
fortySecondBattleScenario,
fortyThirdBattleScenario,
fortyFourthBattleScenario,
fifthBattleScenario,
fifteenthBattleScenario,
fourteenthBattleScenario,
@@ -60,6 +61,8 @@ import {
fortySecondBattleVictoryPages,
fortyThirdBattleIntroPages,
fortyThirdBattleVictoryPages,
fortyFourthBattleIntroPages,
fortyFourthBattleVictoryPages,
fifthBattleIntroPages,
fifthBattleVictoryPages,
fifteenthBattleIntroPages,
@@ -622,13 +625,24 @@ const sortieFlows: Record<string, SortieFlow> = {
},
[fortyThirdBattleScenario.id]: {
afterBattleId: fortyThirdBattleScenario.id,
eyebrow: '다음 장 준비',
title: '형주 고립 심화',
eyebrow: '다음 장',
title: fortyFourthBattleScenario.title,
description:
'공안 성문은 잠시 붙들었지만 미방과 부사인의 흔들림은 완전히 멈추지 않았습니다. 다음 에서는 관우의 번성 전선이 후방 상실과 맞물려 고립되는 흐름을 다룹니다.',
rewardHint: '다음 장: 맥성 고립과 형주 상실 준비 중',
pages: fortyThirdBattleVictoryPages,
unavailableNotice: '맥성 고립과 형주 상실 흐름은 다음 작업에서 이어집니다. 지금은 공안 성문 변고 뒤의 성장, 공명도, 보급을 정비할 수 있습니다.'
'공안 성문은 잠시 붙들었지만 미방과 부사인의 흔들림은 완전히 멈추지 않았습니다. 다음 출진에서는 맥성으로 향하는 좁은 퇴로를 열어 관우 전선의 고립을 늦춰야 합니다.',
rewardHint: `예상 보상: ${fortyFourthBattleScenario.title} 개방 / 맥성 북문 지도`,
nextBattleId: fortyFourthBattleScenario.id,
campaignStep: 'forty-fourth-battle',
pages: [...fortyThirdBattleVictoryPages, ...fortyFourthBattleIntroPages]
},
[fortyFourthBattleScenario.id]: {
afterBattleId: fortyFourthBattleScenario.id,
eyebrow: '다음 장 준비',
title: '형주 상실의 대가',
description:
'맥성의 포위망을 한 차례 뚫었지만 형주의 후방은 이미 크게 갈라졌습니다. 다음 장에서는 형주 상실과 유비의 분노가 더 큰 전쟁으로 번지는 흐름을 다룹니다.',
rewardHint: '다음 장: 형주 상실과 이릉으로 이어지는 분노 준비 중',
pages: fortyFourthBattleVictoryPages,
unavailableNotice: '형주 상실과 이릉 전쟁 흐름은 다음 작업에서 이어집니다. 지금은 맥성 고립전 뒤의 성장, 공명도, 보급을 정비할 수 있습니다.'
}
};

View File

@@ -2842,6 +2842,69 @@ export const fortyThirdBattleVictoryPages: StoryPage[] = [
}
];
export const fortyFourthBattleIntroPages: StoryPage[] = [
{
id: 'forty-fourth-maicheng-orders',
bgm: 'story-dark',
chapter: '끊어진 후방',
background: 'story-militia',
speaker: '마량',
text: '공안 성문을 다시 잠갔으나 강릉과 나루의 소식이 끊겼습니다. 관우 장군의 번성 전선은 앞의 조조군과 뒤의 강동군 사이에서 길을 잃고 있습니다.'
},
{
id: 'forty-fourth-lu-meng-seals-roads',
bgm: 'story-dark',
chapter: '봉쇄되는 길',
background: 'story-three-heroes',
speaker: '왕평',
text: '맥성으로 빠지는 길목마다 흰 옷을 벗은 강동 병사가 서 있습니다. 큰길은 막혔고, 숲과 물목의 작은 길도 오래 버티지 못할 것입니다.'
},
{
id: 'forty-fourth-guan-yu-resolve',
bgm: 'battle-prep',
chapter: '남은 깃발',
background: 'story-liu-bei',
speaker: '관우',
portrait: 'guanYu',
text: '성 하나가 아니라 의리를 지키는 싸움이 되었소. 맥성으로 길을 내고 남은 병사들을 수습하겠소. 길이 좁을수록 마음이 먼저 무너지지 않게 하시오.'
},
{
id: 'forty-fourth-sortie',
bgm: 'battle-prep',
chapter: '맥성 고립전',
background: 'story-sortie',
speaker: '유비',
portrait: 'liuBei',
text: '운장의 깃발이 고립되었다면, 늦더라도 길을 열어야 하오. 북문과 갈대 물목을 동시에 살펴 포위망을 찢고 맥성의 퇴로를 확보하시오.'
}
];
export const fortyFourthBattleVictoryPages: StoryPage[] = [
{
id: 'forty-fourth-victory-road-opened',
bgm: 'militia-theme',
chapter: '뚫린 좁은 길',
background: 'story-sortie',
text: '맥성 북문의 좁은 길은 간신히 열렸고, 흩어진 병사들이 다시 깃발 아래로 모였습니다. 그러나 길 밖의 횃불은 여전히 더 많았습니다.'
},
{
id: 'forty-fourth-lu-meng-tightens',
bgm: 'story-dark',
chapter: '좁아지는 포위',
background: 'story-three-heroes',
speaker: '제갈량',
text: '여몽은 물러난 것이 아니라 더 넓게 둘러섰습니다. 맥성의 작은 승리는 시간을 벌었을 뿐, 형주를 되찾는 길은 아직 멀고 험합니다.'
},
{
id: 'forty-fourth-next-jing-loss',
bgm: 'story-dark',
chapter: '형주의 상실',
background: 'story-militia',
speaker: '마량',
text: '맥성의 포위는 풀렸으나 강릉과 공안의 마음은 이미 갈라졌습니다. 다음 장에서는 형주 상실의 대가와 유비의 분노가 더 큰 전쟁으로 번지는 흐름을 준비해야 합니다.'
}
];
export const firstBattleMap: BattleMap = {
width: 20,
height: 18,
@@ -3245,6 +3308,12 @@ export const fortyThirdBattleMap: BattleMap = {
terrain: createFortyThirdBattleTerrain()
};
export const fortyFourthBattleMap: BattleMap = {
width: 88,
height: 70,
terrain: createFortyFourthBattleTerrain()
};
export const firstBattleUnits: UnitData[] = [
{
id: 'liu-bei',
@@ -14953,6 +15022,100 @@ export const fortyThirdBattleUnits: UnitData[] = [
createThirtyFirstEnemyUnit('jing-collapse-leader-lu-meng', '여몽', '백의도강 도독', 'rebelLeader', 103, 720, 182, 83, 24)
];
const fortyFourthBattleAllyPositions: Record<string, { x: number; y: number }> = {
'liu-bei': { x: 24, y: 45 },
'guan-yu': { x: 30, y: 38 },
'zhang-fei': { x: 24, y: 49 },
'jian-yong': { x: 20, y: 50 },
'mi-zhu': { x: 23, y: 43 },
'sun-qian': { x: 22, y: 53 },
'zhao-yun': { x: 33, y: 42 },
'zhuge-liang': { x: 25, y: 41 },
'ma-liang': { x: 31, y: 45 },
'yi-ji': { x: 28, y: 51 },
'gong-zhi': { x: 29, y: 54 },
'huang-zhong': { x: 35, y: 36 },
'wei-yan': { x: 32, y: 34 },
'pang-tong': { x: 27, y: 47 },
'fa-zheng': { x: 36, y: 46 },
'wu-yi': { x: 38, y: 41 },
'yan-yan': { x: 39, y: 44 },
'li-yan': { x: 35, y: 32 },
'huang-quan': { x: 40, y: 48 },
'ma-chao': { x: 41, y: 36 },
'ma-dai': { x: 43, y: 39 },
'wang-ping': { x: 37, y: 34 }
};
export const fortyFourthBattleUnits: UnitData[] = [
...[
...firstBattleUnits.filter((unit) => unit.faction === 'ally'),
...xuzhouRecruitUnits,
...caoBreakRecruitUnits,
...liuBiaoRecruitUnits,
...zhugeRecruitUnits,
...jingzhouRecruitUnits,
...guiyangRecruitUnits,
...wulingRecruitUnits,
...changshaRecruitUnits,
...yizhouRecruitUnits,
...fuPassRecruitUnits,
...luoCastleRecruitUnits,
...luoCastleProperRecruitUnits,
...chengduPressureRecruitUnits,
...chengduSurrenderRecruitUnits,
...hanzhongOpeningRecruitUnits,
...hanzhongScoutRecruitUnits,
...hanzhongMainRecruitUnits
].map((unit) => placeScenarioUnit(unit, fortyFourthBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
createThirtyFirstEnemyUnit('maicheng-wu-scout-a', '강동 척후', '북문 척후', 'bandit', 101, 426, 138, 48, 30),
createThirtyFirstEnemyUnit('maicheng-wu-scout-b', '강동 척후', '갈대 척후', 'bandit', 101, 426, 138, 53, 52),
createThirtyFirstEnemyUnit('maicheng-wu-scout-c', '강동 척후', '서림 척후', 'bandit', 102, 434, 140, 18, 41),
createThirtyFirstEnemyUnit('maicheng-wu-scout-d', '강동 척후', '남문 척후', 'bandit', 102, 434, 140, 45, 63),
createThirtyFirstEnemyUnit('maicheng-wu-infantry-a', '강동 보병', '북문 보병', 'yellowTurban', 102, 620, 164, 55, 28),
createThirtyFirstEnemyUnit('maicheng-wu-infantry-b', '강동 보병', '북로 보병', 'yellowTurban', 102, 620, 164, 62, 34),
createThirtyFirstEnemyUnit('maicheng-wu-infantry-c', '강동 보병', '동문 보병', 'yellowTurban', 103, 632, 166, 70, 43),
createThirtyFirstEnemyUnit('maicheng-wu-infantry-d', '강동 보병', '남문 보병', 'yellowTurban', 103, 632, 166, 58, 59),
createThirtyFirstEnemyUnit('maicheng-wu-infantry-e', '강동 보병', '서림 보병', 'yellowTurban', 104, 644, 168, 22, 52),
createThirtyFirstEnemyUnit('maicheng-wu-infantry-f', '강동 보병', '포위 보병', 'yellowTurban', 104, 644, 168, 76, 28),
createThirtyFirstEnemyUnit('maicheng-wu-archer-a', '강동 궁병', '북문 궁병', 'archer', 102, 456, 146, 50, 24),
createThirtyFirstEnemyUnit('maicheng-wu-archer-b', '강동 궁병', '동림 궁병', 'archer', 103, 464, 148, 72, 38),
createThirtyFirstEnemyUnit('maicheng-wu-archer-c', '강동 궁병', '남문 궁병', 'archer', 103, 464, 148, 61, 64),
createThirtyFirstEnemyUnit('maicheng-wu-archer-d', '강동 궁병', '서림 궁병', 'archer', 104, 472, 150, 19, 47),
createThirtyFirstEnemyUnit('maicheng-wu-archer-e', '강동 궁병', '갈대 궁병', 'archer', 104, 472, 150, 43, 56),
createThirtyFirstEnemyUnit('maicheng-wu-archer-f', '강동 궁병', '산길 궁병', 'archer', 105, 480, 152, 66, 21),
createThirtyFirstEnemyUnit('maicheng-wu-cavalry-a', '강동 기병', '북로 기병', 'cavalry', 103, 632, 166, 57, 18),
createThirtyFirstEnemyUnit('maicheng-wu-cavalry-b', '강동 기병', '동로 기병', 'cavalry', 103, 632, 166, 80, 36),
createThirtyFirstEnemyUnit('maicheng-wu-cavalry-c', '강동 기병', '남로 기병', 'cavalry', 104, 644, 168, 66, 61),
createThirtyFirstEnemyUnit('maicheng-wu-cavalry-d', '강동 기병', '서로 기병', 'cavalry', 104, 644, 168, 16, 58),
createThirtyFirstEnemyUnit('maicheng-wu-guard-a', '강동 친위대', '북문 친위대', 'yellowTurban', 105, 668, 172, 63, 27),
createThirtyFirstEnemyUnit('maicheng-wu-guard-b', '강동 친위대', '동문 친위대', 'yellowTurban', 105, 668, 172, 78, 45),
createThirtyFirstEnemyUnit('maicheng-wu-guard-c', '강동 친위대', '남문 친위대', 'yellowTurban', 106, 680, 174, 54, 66),
createThirtyFirstEnemyUnit('maicheng-wu-guard-d', '강동 친위대', '서문 친위대', 'yellowTurban', 106, 680, 174, 25, 57),
createThirtyFirstEnemyUnit('maicheng-wu-ambusher-a', '백의 복병', '북문 복병', 'bandit', 102, 442, 142, 44, 28),
createThirtyFirstEnemyUnit('maicheng-wu-ambusher-b', '백의 복병', '숲길 복병', 'bandit', 103, 450, 144, 27, 33),
createThirtyFirstEnemyUnit('maicheng-wu-ambusher-c', '백의 복병', '갈대 복병', 'bandit', 103, 450, 144, 48, 58),
createThirtyFirstEnemyUnit('maicheng-wu-ambusher-d', '백의 복병', '서림 복병', 'bandit', 104, 458, 146, 12, 44),
createThirtyFirstEnemyUnit('maicheng-wu-ambusher-e', '백의 복병', '퇴로 복병', 'bandit', 104, 458, 146, 72, 55),
createThirtyFirstEnemyUnit('maicheng-wu-marine-a', '강동 수군', '갈대 수군', 'yellowTurban', 103, 636, 166, 35, 61),
createThirtyFirstEnemyUnit('maicheng-wu-marine-b', '강동 수군', '물목 수군', 'yellowTurban', 104, 648, 168, 42, 66),
createThirtyFirstEnemyUnit('maicheng-wu-marine-c', '강동 수군', '나루 수군', 'yellowTurban', 104, 648, 168, 52, 67),
createThirtyFirstEnemyUnit('maicheng-wei-cavalry-a', '위군 기병', '번성 추격대', 'cavalry', 104, 654, 170, 67, 15),
createThirtyFirstEnemyUnit('maicheng-wei-cavalry-b', '위군 기병', '북로 추격대', 'cavalry', 105, 666, 172, 74, 19),
createThirtyFirstEnemyUnit('maicheng-wei-cavalry-c', '위군 기병', '동로 추격대', 'cavalry', 105, 666, 172, 82, 25),
createThirtyFirstEnemyUnit('maicheng-wei-infantry-a', '위군 보병', '번성 보병', 'yellowTurban', 104, 650, 168, 69, 12),
createThirtyFirstEnemyUnit('maicheng-wei-infantry-b', '위군 보병', '북로 보병', 'yellowTurban', 105, 662, 170, 78, 16),
createThirtyFirstEnemyUnit('maicheng-wei-infantry-c', '위군 보병', '동로 보병', 'yellowTurban', 105, 662, 170, 84, 30),
createThirtyFirstEnemyUnit('maicheng-strategist-a', '강동 책사', '봉쇄 책사', 'strategist', 105, 492, 152, 61, 31),
createThirtyFirstEnemyUnit('maicheng-strategist-b', '강동 책사', '서찰 책사', 'strategist', 105, 492, 152, 75, 50),
createThirtyFirstEnemyUnit('maicheng-strategist-c', '위군 책사', '추격 책사', 'strategist', 106, 500, 154, 78, 22),
createThirtyFirstEnemyUnit('maicheng-officer-pan-zhang', '반장', '강동 포위장', 'rebelLeader', 106, 690, 176, 68, 53),
createThirtyFirstEnemyUnit('maicheng-officer-ma-zhong', '마충', '매복 지휘관', 'bandit', 106, 520, 156, 52, 36),
createThirtyFirstEnemyUnit('maicheng-officer-lu-xun', '육손', '강동 설객', 'strategist', 107, 512, 156, 73, 34),
createThirtyFirstEnemyUnit('maicheng-officer-xu-huang', '서황', '번성 추격장', 'cavalry', 107, 706, 180, 82, 18),
createThirtyFirstEnemyUnit('maicheng-leader-lu-meng', '여몽', '형주 봉쇄 도독', 'rebelLeader', 108, 742, 186, 80, 43)
];
export const firstBattleBonds: BattleBond[] = [
{
id: 'liu-bei__guan-yu',
@@ -15685,6 +15848,35 @@ export const jingCollapseBonds: BattleBond[] = [
export const fortyThirdBattleBonds: BattleBond[] = [...fortySecondBattleBonds, ...jingCollapseBonds].map(
cloneBattleBondForScenario
);
export const maichengIsolationBonds: BattleBond[] = [
{
id: 'guan-yu__wang-ping_maicheng',
unitIds: ['guan-yu', 'wang-ping'],
title: '맥성 북문',
level: 40,
exp: 0,
description: '관우의 결단과 왕평의 지형 판단은 맥성 북문의 좁은 퇴로를 찾는 힘이 된다.'
},
{
id: 'zhao-yun__ma-dai_maicheng',
unitIds: ['zhao-yun', 'ma-dai'],
title: '기동 차단',
level: 36,
exp: 0,
description: '조운의 빠른 판단과 마대의 안정된 기병 운용은 포위망의 틈을 빠르게 찢는다.'
},
{
id: 'guan-yu__huang-zhong_maicheng',
unitIds: ['guan-yu', 'huang-zhong'],
title: '노장의 깃발',
level: 34,
exp: 0,
description: '관우의 정면 돌파와 황충의 고지 견제는 좁은 맥성 길목에서 포위군을 늦춘다.'
}
];
export const fortyFourthBattleBonds: BattleBond[] = [...fortyThirdBattleBonds, ...maichengIsolationBonds].map(
cloneBattleBondForScenario
);
function createEighthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 22 }, (_, y) =>
@@ -17809,6 +18001,77 @@ function createFortyThirdBattleTerrain(): TerrainType[][] {
);
}
function createFortyFourthBattleTerrain(): TerrainType[][] {
return Array.from({ length: 70 }, (_, y) =>
Array.from({ length: 88 }, (_, x): TerrainType => {
if (x >= 27 && x <= 39 && y >= 33 && y <= 46) {
return 'fort';
}
if (
(x >= 31 && x <= 35 && y >= 36 && y <= 42) ||
(x >= 44 && x <= 49 && y >= 50 && y <= 56) ||
(x >= 12 && x <= 18 && y >= 45 && y <= 51) ||
(x >= 60 && x <= 66 && y >= 22 && y <= 28)
) {
return 'village';
}
if (
(x >= 36 && x <= 42 && y >= 48 && y <= 69) ||
(x >= 43 && x <= 50 && y >= 55 && y <= 69) ||
(x >= 51 && x <= 57 && y >= 61 && y <= 69) ||
(x >= 0 && x <= 9 && y >= 28 && y <= 69)
) {
return 'river';
}
if (
(x >= 1 && x <= 31 && y >= 39 && y <= 43) ||
(x >= 29 && x <= 57 && y >= 37 && y <= 41) ||
(x >= 38 && x <= 82 && y >= 29 && y <= 33) ||
(x >= 44 && x <= 80 && y >= 48 && y <= 52) ||
(x >= 22 && x <= 32 && y >= 46 && y <= 62) ||
(x >= 55 && x <= 64 && y >= 18 && y <= 36)
) {
return 'road';
}
if (
(x >= 4 && x <= 26 && y >= 20 && y <= 56) ||
(x >= 18 && x <= 36 && y >= 4 && y <= 31) ||
(x >= 42 && x <= 66 && y >= 5 && y <= 25) ||
(x >= 58 && x <= 86 && y >= 34 && y <= 64)
) {
return 'forest';
}
if (
(x >= 0 && x <= 25 && y <= 21) ||
(x >= 34 && x <= 62 && y <= 15) ||
(x >= 67 && x <= 87 && y <= 31) ||
(x >= 58 && x <= 87 && y >= 60) ||
(x >= 12 && x <= 31 && y >= 56)
) {
return 'hill';
}
if (
(x <= 2 && y <= 27) ||
(x >= 85 && y >= 32) ||
(x >= 38 && x <= 43 && y <= 8) ||
(x >= 66 && x <= 70 && y >= 6 && y <= 31) ||
(x >= 9 && x <= 13 && y >= 52 && y <= 69) ||
(x >= 25 && x <= 27 && y >= 30 && y <= 49)
) {
return 'cliff';
}
if (
(x >= 24 && x <= 42 && y >= 30 && y <= 49) ||
(x >= 48 && x <= 60 && y >= 28 && y <= 44) ||
(x >= 14 && x <= 27 && y >= 34 && y <= 53)
) {
return 'camp';
}
return 'plain';
})
);
}
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
return {
...cloneUnitForScenario(unit),