Add Hanzhong decisive battle chapter
This commit is contained in:
@@ -58,16 +58,17 @@ Build a small complete tactical RPG loop that can grow into a longer Romance of
|
|||||||
- Thirty-fourth battle Jiameng Pass Ma Chao route, using Huang Quan's first sortie choice across a 68x50 Hanzhong gate battlefield and recruiting Ma Chao after his charge is redirected
|
- Thirty-fourth battle Jiameng Pass Ma Chao route, using Huang Quan's first sortie choice across a 68x50 Hanzhong gate battlefield and recruiting Ma Chao after his charge is redirected
|
||||||
- Thirty-fifth battle Yangping scout route, using Ma Chao's first allied sortie across a 70x52 Hanzhong gate battlefield and recruiting Ma Dai after the pass is surveyed
|
- Thirty-fifth battle Yangping scout route, using Ma Chao's first allied sortie across a 70x52 Hanzhong gate battlefield and recruiting Ma Dai after the pass is surveyed
|
||||||
- Thirty-sixth battle Dingjun Mountain vanguard route, using Huang Zhong and Fa Zheng's high-ground plan across a 72x54 Hanzhong battlefield and recruiting Wang Ping after the ridge is secured
|
- Thirty-sixth battle Dingjun Mountain vanguard route, using Huang Zhong and Fa Zheng's high-ground plan across a 72x54 Hanzhong battlefield and recruiting Wang Ping after the ridge is secured
|
||||||
|
- Thirty-seventh battle Hanzhong decisive route, using Wang Ping's terrain knowledge and a seven-officer sortie choice across a 74x56 Hanzhong battlefield to push Cao Cao out and prepare Liu Bei's King of Hanzhong step
|
||||||
- Camp progress timeline tab that summarizes Liu Bei's long campaign arc, completed battles, current chapter, latest battle, and next major chapter
|
- Camp progress timeline tab that summarizes Liu Bei's long campaign arc, completed battles, current chapter, latest battle, and next major chapter
|
||||||
- Tactical sortie preparation panel with battle-specific sortie limits, recommended officers with reasons, class role, named equipment, core stats, bond partner, next-map terrain suitability, deployment preview, formation roles, active bond count, recruited-officer count, reserve roster summary, and readiness advice for each deployable officer
|
- Tactical sortie preparation panel with battle-specific sortie limits, recommended officers with reasons, class role, named equipment, core stats, bond partner, next-map terrain suitability, deployment preview, formation roles, active bond count, recruited-officer count, reserve roster summary, and readiness advice for each deployable officer
|
||||||
- Officer collection support in camp, including full roster status, selected/reserve/recommended markers, and post-battle reserve training growth for benched officers
|
- Officer collection support in camp, including full roster status, selected/reserve/recommended markers, and post-battle reserve training growth for benched officers
|
||||||
- Treasure equipment effects wired into battle previews and resolution, including named weapon damage bonuses, defensive treasure mitigation, support recovery bonuses, turn-start charm recovery, and equipment-specific growth bonuses
|
- Treasure equipment effects wired into battle previews and resolution, including named weapon damage bonuses, defensive treasure mitigation, support recovery bonuses, turn-start charm recovery, and equipment-specific growth bonuses
|
||||||
- Flow verification script from title through the thirty-sixth battle victory, recruit sortie selection, Liu Biao visit rewards, Zhuge Liang recruitment, Bowang/Changban/Jiangdong/Red Cliffs/Jing Province/Guiyang/Wuling/Changsha/Yi Province/Fu Pass/Luo Castle/Luofeng/Luo main gate/Mianzhu/Chengdu/Jiameng/Yangping/Dingjun camp states, campaign timeline state, and camp save state
|
- Flow verification script from title through the thirty-seventh battle victory, recruit sortie selection, Liu Biao visit rewards, Zhuge Liang recruitment, Bowang/Changban/Jiangdong/Red Cliffs/Jing Province/Guiyang/Wuling/Changsha/Yi Province/Fu Pass/Luo Castle/Luofeng/Luo main gate/Mianzhu/Chengdu/Jiameng/Yangping/Dingjun/Hanzhong camp states, campaign timeline state, and camp save state
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
1. Continue from Dingjun Mountain into the Hanzhong decisive battle, using Huang Zhong/Fa Zheng and Wang Ping's terrain knowledge as the tactical axis
|
1. Continue from Hanzhong victory into the King of Hanzhong and Shu-Han foundation setup, making the political transition playable in camp rather than a single text page
|
||||||
2. Add the formal Shu-Han foundation setup once Hanzhong's military basis is strong enough
|
2. Add the next tension around Guan Yu's Jing Province defense so the Shu-Han foundation has an immediate strategic cost
|
||||||
3. Expand sortie selection into richer pre-battle officer planning, including explicit reserve drills, class practice, and bond-focused camp assignments
|
3. Expand sortie selection into richer pre-battle officer planning, including explicit reserve drills, class practice, and bond-focused camp assignments
|
||||||
4. Add a dedicated treasure/equipment management view so players can compare special effects and growth
|
4. Add a dedicated treasure/equipment management view so players can compare special effects and growth
|
||||||
5. Keep expanding scenarios through the long campaign instead of treating the current slice as an ending
|
5. Keep expanding scenarios through the long campaign instead of treating the current slice as an ending
|
||||||
|
|||||||
@@ -1736,7 +1736,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
progressTabState?.activeTab !== 'progress' ||
|
progressTabState?.activeTab !== 'progress' ||
|
||||||
progressTabState.campaignProgress?.completedKnown !== 17 ||
|
progressTabState.campaignProgress?.completedKnown !== 17 ||
|
||||||
progressTabState.campaignProgress?.totalKnown !== 36 ||
|
progressTabState.campaignProgress?.totalKnown !== 37 ||
|
||||||
progressTabState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
progressTabState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
||||||
progressTabState.campaignProgress?.latestBattleTitle !== '융중 방문로' ||
|
progressTabState.campaignProgress?.latestBattleTitle !== '융중 방문로' ||
|
||||||
progressTabState.campaignProgress?.nextBattleTitle !== '박망파 매복전'
|
progressTabState.campaignProgress?.nextBattleTitle !== '박망파 매복전'
|
||||||
@@ -1888,7 +1888,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postBowangProgressState?.activeTab !== 'progress' ||
|
postBowangProgressState?.activeTab !== 'progress' ||
|
||||||
postBowangProgressState.campaignProgress?.completedKnown !== 18 ||
|
postBowangProgressState.campaignProgress?.completedKnown !== 18 ||
|
||||||
postBowangProgressState.campaignProgress?.totalKnown !== 36 ||
|
postBowangProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postBowangProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
postBowangProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
||||||
postBowangProgressState.campaignProgress?.latestBattleTitle !== '박망파 매복전' ||
|
postBowangProgressState.campaignProgress?.latestBattleTitle !== '박망파 매복전' ||
|
||||||
postBowangProgressState.campaignProgress?.nextBattleTitle !== '장판파 피난로'
|
postBowangProgressState.campaignProgress?.nextBattleTitle !== '장판파 피난로'
|
||||||
@@ -2026,7 +2026,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postChangbanProgressState?.activeTab !== 'progress' ||
|
postChangbanProgressState?.activeTab !== 'progress' ||
|
||||||
postChangbanProgressState.campaignProgress?.completedKnown !== 19 ||
|
postChangbanProgressState.campaignProgress?.completedKnown !== 19 ||
|
||||||
postChangbanProgressState.campaignProgress?.totalKnown !== 36 ||
|
postChangbanProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postChangbanProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
postChangbanProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
||||||
postChangbanProgressState.campaignProgress?.latestBattleTitle !== '장판파 피난로' ||
|
postChangbanProgressState.campaignProgress?.latestBattleTitle !== '장판파 피난로' ||
|
||||||
postChangbanProgressState.campaignProgress?.nextBattleTitle !== '강동 사절로'
|
postChangbanProgressState.campaignProgress?.nextBattleTitle !== '강동 사절로'
|
||||||
@@ -2164,7 +2164,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postJiangdongProgressState?.activeTab !== 'progress' ||
|
postJiangdongProgressState?.activeTab !== 'progress' ||
|
||||||
postJiangdongProgressState.campaignProgress?.completedKnown !== 20 ||
|
postJiangdongProgressState.campaignProgress?.completedKnown !== 20 ||
|
||||||
postJiangdongProgressState.campaignProgress?.totalKnown !== 36 ||
|
postJiangdongProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postJiangdongProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
postJiangdongProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
||||||
postJiangdongProgressState.campaignProgress?.latestBattleTitle !== '강동 사절로' ||
|
postJiangdongProgressState.campaignProgress?.latestBattleTitle !== '강동 사절로' ||
|
||||||
postJiangdongProgressState.campaignProgress?.nextBattleTitle !== '적벽 전초전'
|
postJiangdongProgressState.campaignProgress?.nextBattleTitle !== '적벽 전초전'
|
||||||
@@ -2304,7 +2304,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postRedCliffsProgressState?.activeTab !== 'progress' ||
|
postRedCliffsProgressState?.activeTab !== 'progress' ||
|
||||||
postRedCliffsProgressState.campaignProgress?.completedKnown !== 21 ||
|
postRedCliffsProgressState.campaignProgress?.completedKnown !== 21 ||
|
||||||
postRedCliffsProgressState.campaignProgress?.totalKnown !== 36 ||
|
postRedCliffsProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postRedCliffsProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
postRedCliffsProgressState.campaignProgress?.activeChapter?.title !== '적벽대전' ||
|
||||||
postRedCliffsProgressState.campaignProgress?.latestBattleTitle !== '적벽 전초전' ||
|
postRedCliffsProgressState.campaignProgress?.latestBattleTitle !== '적벽 전초전' ||
|
||||||
postRedCliffsProgressState.campaignProgress?.nextBattleTitle !== '적벽 화공전'
|
postRedCliffsProgressState.campaignProgress?.nextBattleTitle !== '적벽 화공전'
|
||||||
@@ -2444,7 +2444,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postFireAttackProgressState?.activeTab !== 'progress' ||
|
postFireAttackProgressState?.activeTab !== 'progress' ||
|
||||||
postFireAttackProgressState.campaignProgress?.completedKnown !== 22 ||
|
postFireAttackProgressState.campaignProgress?.completedKnown !== 22 ||
|
||||||
postFireAttackProgressState.campaignProgress?.totalKnown !== 36 ||
|
postFireAttackProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postFireAttackProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postFireAttackProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postFireAttackProgressState.campaignProgress?.latestBattleTitle !== '적벽 화공전' ||
|
postFireAttackProgressState.campaignProgress?.latestBattleTitle !== '적벽 화공전' ||
|
||||||
postFireAttackProgressState.campaignProgress?.nextBattleTitle !== '형주 남부 진입전'
|
postFireAttackProgressState.campaignProgress?.nextBattleTitle !== '형주 남부 진입전'
|
||||||
@@ -2587,7 +2587,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postJingzhouProgressState?.activeTab !== 'progress' ||
|
postJingzhouProgressState?.activeTab !== 'progress' ||
|
||||||
postJingzhouProgressState.campaignProgress?.completedKnown !== 23 ||
|
postJingzhouProgressState.campaignProgress?.completedKnown !== 23 ||
|
||||||
postJingzhouProgressState.campaignProgress?.totalKnown !== 36 ||
|
postJingzhouProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postJingzhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postJingzhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postJingzhouProgressState.campaignProgress?.latestBattleTitle !== '형주 남부 진입전' ||
|
postJingzhouProgressState.campaignProgress?.latestBattleTitle !== '형주 남부 진입전' ||
|
||||||
postJingzhouProgressState.campaignProgress?.nextBattleTitle !== '계양 설득전'
|
postJingzhouProgressState.campaignProgress?.nextBattleTitle !== '계양 설득전'
|
||||||
@@ -2729,7 +2729,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postGuiyangProgressState?.activeTab !== 'progress' ||
|
postGuiyangProgressState?.activeTab !== 'progress' ||
|
||||||
postGuiyangProgressState.campaignProgress?.completedKnown !== 24 ||
|
postGuiyangProgressState.campaignProgress?.completedKnown !== 24 ||
|
||||||
postGuiyangProgressState.campaignProgress?.totalKnown !== 36 ||
|
postGuiyangProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postGuiyangProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postGuiyangProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postGuiyangProgressState.campaignProgress?.latestBattleTitle !== '계양 설득전' ||
|
postGuiyangProgressState.campaignProgress?.latestBattleTitle !== '계양 설득전' ||
|
||||||
postGuiyangProgressState.campaignProgress?.nextBattleTitle !== '무릉 산길 확보전'
|
postGuiyangProgressState.campaignProgress?.nextBattleTitle !== '무릉 산길 확보전'
|
||||||
@@ -2872,7 +2872,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postWulingProgressState?.activeTab !== 'progress' ||
|
postWulingProgressState?.activeTab !== 'progress' ||
|
||||||
postWulingProgressState.campaignProgress?.completedKnown !== 25 ||
|
postWulingProgressState.campaignProgress?.completedKnown !== 25 ||
|
||||||
postWulingProgressState.campaignProgress?.totalKnown !== 36 ||
|
postWulingProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postWulingProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postWulingProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postWulingProgressState.campaignProgress?.latestBattleTitle !== '무릉 산길 확보전' ||
|
postWulingProgressState.campaignProgress?.latestBattleTitle !== '무릉 산길 확보전' ||
|
||||||
postWulingProgressState.campaignProgress?.nextBattleTitle !== '장사 노장 대면전'
|
postWulingProgressState.campaignProgress?.nextBattleTitle !== '장사 노장 대면전'
|
||||||
@@ -3021,7 +3021,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postChangshaProgressState?.activeTab !== 'progress' ||
|
postChangshaProgressState?.activeTab !== 'progress' ||
|
||||||
postChangshaProgressState.campaignProgress?.completedKnown !== 26 ||
|
postChangshaProgressState.campaignProgress?.completedKnown !== 26 ||
|
||||||
postChangshaProgressState.campaignProgress?.totalKnown !== 36 ||
|
postChangshaProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postChangshaProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postChangshaProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postChangshaProgressState.campaignProgress?.latestBattleTitle !== '장사 노장 대면전' ||
|
postChangshaProgressState.campaignProgress?.latestBattleTitle !== '장사 노장 대면전' ||
|
||||||
postChangshaProgressState.campaignProgress?.nextBattleTitle !== '익주 원군로'
|
postChangshaProgressState.campaignProgress?.nextBattleTitle !== '익주 원군로'
|
||||||
@@ -3166,7 +3166,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postYizhouProgressState?.activeTab !== 'progress' ||
|
postYizhouProgressState?.activeTab !== 'progress' ||
|
||||||
postYizhouProgressState.campaignProgress?.completedKnown !== 27 ||
|
postYizhouProgressState.campaignProgress?.completedKnown !== 27 ||
|
||||||
postYizhouProgressState.campaignProgress?.totalKnown !== 36 ||
|
postYizhouProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postYizhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postYizhouProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postYizhouProgressState.campaignProgress?.latestBattleTitle !== '익주 원군로' ||
|
postYizhouProgressState.campaignProgress?.latestBattleTitle !== '익주 원군로' ||
|
||||||
postYizhouProgressState.campaignProgress?.nextBattleTitle !== '부수관 진입전'
|
postYizhouProgressState.campaignProgress?.nextBattleTitle !== '부수관 진입전'
|
||||||
@@ -3313,7 +3313,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postFuPassProgressState?.activeTab !== 'progress' ||
|
postFuPassProgressState?.activeTab !== 'progress' ||
|
||||||
postFuPassProgressState.campaignProgress?.completedKnown !== 28 ||
|
postFuPassProgressState.campaignProgress?.completedKnown !== 28 ||
|
||||||
postFuPassProgressState.campaignProgress?.totalKnown !== 36 ||
|
postFuPassProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postFuPassProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postFuPassProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postFuPassProgressState.campaignProgress?.latestBattleTitle !== '부수관 진입전' ||
|
postFuPassProgressState.campaignProgress?.latestBattleTitle !== '부수관 진입전' ||
|
||||||
postFuPassProgressState.campaignProgress?.nextBattleTitle !== '낙성 외곽전'
|
postFuPassProgressState.campaignProgress?.nextBattleTitle !== '낙성 외곽전'
|
||||||
@@ -3462,7 +3462,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postLuoProgressState?.activeTab !== 'progress' ||
|
postLuoProgressState?.activeTab !== 'progress' ||
|
||||||
postLuoProgressState.campaignProgress?.completedKnown !== 29 ||
|
postLuoProgressState.campaignProgress?.completedKnown !== 29 ||
|
||||||
postLuoProgressState.campaignProgress?.totalKnown !== 36 ||
|
postLuoProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postLuoProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postLuoProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postLuoProgressState.campaignProgress?.latestBattleTitle !== '낙성 외곽전' ||
|
postLuoProgressState.campaignProgress?.latestBattleTitle !== '낙성 외곽전' ||
|
||||||
postLuoProgressState.campaignProgress?.nextBattleTitle !== '낙봉파 매복전'
|
postLuoProgressState.campaignProgress?.nextBattleTitle !== '낙봉파 매복전'
|
||||||
@@ -3608,7 +3608,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postLuofengProgressState?.activeTab !== 'progress' ||
|
postLuofengProgressState?.activeTab !== 'progress' ||
|
||||||
postLuofengProgressState.campaignProgress?.completedKnown !== 30 ||
|
postLuofengProgressState.campaignProgress?.completedKnown !== 30 ||
|
||||||
postLuofengProgressState.campaignProgress?.totalKnown !== 36 ||
|
postLuofengProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postLuofengProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postLuofengProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postLuofengProgressState.campaignProgress?.latestBattleTitle !== '낙봉파 매복전' ||
|
postLuofengProgressState.campaignProgress?.latestBattleTitle !== '낙봉파 매복전' ||
|
||||||
postLuofengProgressState.campaignProgress?.nextBattleTitle !== '낙성 본성 공략'
|
postLuofengProgressState.campaignProgress?.nextBattleTitle !== '낙성 본성 공략'
|
||||||
@@ -3760,7 +3760,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postLuoMainProgressState?.activeTab !== 'progress' ||
|
postLuoMainProgressState?.activeTab !== 'progress' ||
|
||||||
postLuoMainProgressState.campaignProgress?.completedKnown !== 31 ||
|
postLuoMainProgressState.campaignProgress?.completedKnown !== 31 ||
|
||||||
postLuoMainProgressState.campaignProgress?.totalKnown !== 36 ||
|
postLuoMainProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postLuoMainProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postLuoMainProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postLuoMainProgressState.campaignProgress?.latestBattleTitle !== '낙성 본성 공략' ||
|
postLuoMainProgressState.campaignProgress?.latestBattleTitle !== '낙성 본성 공략' ||
|
||||||
postLuoMainProgressState.campaignProgress?.nextBattleTitle !== '면죽관 압박전'
|
postLuoMainProgressState.campaignProgress?.nextBattleTitle !== '면죽관 압박전'
|
||||||
@@ -3913,7 +3913,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postMianzhuProgressState?.activeTab !== 'progress' ||
|
postMianzhuProgressState?.activeTab !== 'progress' ||
|
||||||
postMianzhuProgressState.campaignProgress?.completedKnown !== 32 ||
|
postMianzhuProgressState.campaignProgress?.completedKnown !== 32 ||
|
||||||
postMianzhuProgressState.campaignProgress?.totalKnown !== 36 ||
|
postMianzhuProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postMianzhuProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
postMianzhuProgressState.campaignProgress?.activeChapter?.title !== '형주·익주 확보' ||
|
||||||
postMianzhuProgressState.campaignProgress?.latestBattleTitle !== '면죽관 압박전' ||
|
postMianzhuProgressState.campaignProgress?.latestBattleTitle !== '면죽관 압박전' ||
|
||||||
postMianzhuProgressState.campaignProgress?.nextBattleTitle !== '성도 항복 권고전'
|
postMianzhuProgressState.campaignProgress?.nextBattleTitle !== '성도 항복 권고전'
|
||||||
@@ -4067,7 +4067,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postChengduProgressState?.activeTab !== 'progress' ||
|
postChengduProgressState?.activeTab !== 'progress' ||
|
||||||
postChengduProgressState.campaignProgress?.completedKnown !== 33 ||
|
postChengduProgressState.campaignProgress?.completedKnown !== 33 ||
|
||||||
postChengduProgressState.campaignProgress?.totalKnown !== 36 ||
|
postChengduProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postChengduProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
postChengduProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
||||||
postChengduProgressState.campaignProgress?.latestBattleTitle !== '성도 항복 권고전' ||
|
postChengduProgressState.campaignProgress?.latestBattleTitle !== '성도 항복 권고전' ||
|
||||||
postChengduProgressState.campaignProgress?.nextBattleTitle !== '가맹관 마초 대면전'
|
postChengduProgressState.campaignProgress?.nextBattleTitle !== '가맹관 마초 대면전'
|
||||||
@@ -4222,7 +4222,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postJiamengProgressState?.activeTab !== 'progress' ||
|
postJiamengProgressState?.activeTab !== 'progress' ||
|
||||||
postJiamengProgressState.campaignProgress?.completedKnown !== 34 ||
|
postJiamengProgressState.campaignProgress?.completedKnown !== 34 ||
|
||||||
postJiamengProgressState.campaignProgress?.totalKnown !== 36 ||
|
postJiamengProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postJiamengProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
postJiamengProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
||||||
postJiamengProgressState.campaignProgress?.latestBattleTitle !== '가맹관 마초 대면전' ||
|
postJiamengProgressState.campaignProgress?.latestBattleTitle !== '가맹관 마초 대면전' ||
|
||||||
postJiamengProgressState.campaignProgress?.nextBattleTitle !== '양평관 정찰전'
|
postJiamengProgressState.campaignProgress?.nextBattleTitle !== '양평관 정찰전'
|
||||||
@@ -4378,7 +4378,7 @@ try {
|
|||||||
if (
|
if (
|
||||||
postYangpingProgressState?.activeTab !== 'progress' ||
|
postYangpingProgressState?.activeTab !== 'progress' ||
|
||||||
postYangpingProgressState.campaignProgress?.completedKnown !== 35 ||
|
postYangpingProgressState.campaignProgress?.completedKnown !== 35 ||
|
||||||
postYangpingProgressState.campaignProgress?.totalKnown !== 36 ||
|
postYangpingProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postYangpingProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
postYangpingProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
||||||
postYangpingProgressState.campaignProgress?.latestBattleTitle !== '양평관 정찰전' ||
|
postYangpingProgressState.campaignProgress?.latestBattleTitle !== '양평관 정찰전' ||
|
||||||
postYangpingProgressState.campaignProgress?.nextBattleTitle !== '정군산 전초전'
|
postYangpingProgressState.campaignProgress?.nextBattleTitle !== '정군산 전초전'
|
||||||
@@ -4535,15 +4535,168 @@ try {
|
|||||||
if (
|
if (
|
||||||
postDingjunProgressState?.activeTab !== 'progress' ||
|
postDingjunProgressState?.activeTab !== 'progress' ||
|
||||||
postDingjunProgressState.campaignProgress?.completedKnown !== 36 ||
|
postDingjunProgressState.campaignProgress?.completedKnown !== 36 ||
|
||||||
postDingjunProgressState.campaignProgress?.totalKnown !== 36 ||
|
postDingjunProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
postDingjunProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
postDingjunProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
||||||
postDingjunProgressState.campaignProgress?.latestBattleTitle !== '정군산 전초전' ||
|
postDingjunProgressState.campaignProgress?.latestBattleTitle !== '정군산 전초전' ||
|
||||||
postDingjunProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
|
postDingjunProgressState.campaignProgress?.nextBattleTitle !== '한중 결전'
|
||||||
) {
|
) {
|
||||||
throw new Error(`Expected post-Dingjun progress tab to complete Wang Ping chapter and pause on the next Hanzhong step: ${JSON.stringify(postDingjunProgressState?.campaignProgress)}`);
|
throw new Error(`Expected post-Dingjun progress tab to complete Wang Ping chapter and open the Hanzhong decisive battle: ${JSON.stringify(postDingjunProgressState?.campaignProgress)}`);
|
||||||
}
|
}
|
||||||
await page.screenshot({ path: 'dist/verification-post-dingjun-progress.png', fullPage: true });
|
await page.screenshot({ path: 'dist/verification-post-dingjun-progress.png', fullPage: true });
|
||||||
|
|
||||||
|
await page.mouse.click(1120, 38);
|
||||||
|
await page.waitForTimeout(180);
|
||||||
|
const hanzhongSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||||
|
if (
|
||||||
|
!hanzhongSortieState?.sortieVisible ||
|
||||||
|
!hanzhongSortieState.sortiePlan?.objectiveLine?.includes('한중 결전') ||
|
||||||
|
hanzhongSortieState.sortiePlan?.maxCount !== 7 ||
|
||||||
|
hanzhongSortieState.sortiePlan?.recommendedTotal !== 7 ||
|
||||||
|
!hanzhongSortieState.sortieRoster?.some((unit) => unit.id === 'wang-ping' && unit.recruited && unit.recommended)
|
||||||
|
) {
|
||||||
|
throw new Error(`Expected Hanzhong decisive sortie prep to use a seven-officer roster and recommend Wang Ping: ${JSON.stringify(hanzhongSortieState)}`);
|
||||||
|
}
|
||||||
|
assertSortieTacticalRoster(hanzhongSortieState, [
|
||||||
|
'liu-bei',
|
||||||
|
'guan-yu',
|
||||||
|
'zhang-fei',
|
||||||
|
'jian-yong',
|
||||||
|
'mi-zhu',
|
||||||
|
'sun-qian',
|
||||||
|
'zhao-yun',
|
||||||
|
'zhuge-liang',
|
||||||
|
'ma-liang',
|
||||||
|
'yi-ji',
|
||||||
|
'gong-zhi',
|
||||||
|
'huang-zhong',
|
||||||
|
'wei-yan',
|
||||||
|
'pang-tong',
|
||||||
|
'fa-zheng',
|
||||||
|
'wu-yi',
|
||||||
|
'yan-yan',
|
||||||
|
'li-yan',
|
||||||
|
'huang-quan',
|
||||||
|
'ma-chao',
|
||||||
|
'ma-dai',
|
||||||
|
'wang-ping'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const hanzhongPriorityUnits = ['huang-zhong', 'fa-zheng', 'wang-ping', 'ma-chao', 'ma-dai', 'zhuge-liang'];
|
||||||
|
for (const unitId of hanzhongPriorityUnits) {
|
||||||
|
const currentSortieState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||||
|
if (!currentSortieState.sortieRoster?.some((unit) => unit.id === unitId && unit.selected)) {
|
||||||
|
const removable = currentSortieState.sortieRoster?.find(
|
||||||
|
(unit) => unit.selected && unit.id !== 'liu-bei' && !hanzhongPriorityUnits.includes(unit.id)
|
||||||
|
);
|
||||||
|
if (removable) {
|
||||||
|
await clickSortieRosterUnit(page, removable.id);
|
||||||
|
}
|
||||||
|
await clickSortieRosterUnit(page, unitId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hanzhongSortieReadyState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||||
|
if (
|
||||||
|
!hanzhongPriorityUnits.every((unitId) =>
|
||||||
|
hanzhongSortieReadyState.sortieRoster?.some((unit) => unit.id === unitId && unit.selected)
|
||||||
|
) ||
|
||||||
|
hanzhongSortieReadyState.sortiePlan?.selectedCount !== 7 ||
|
||||||
|
hanzhongSortieReadyState.sortiePlan?.recommendedSelectedCount < 7
|
||||||
|
) {
|
||||||
|
throw new Error(`Expected Hanzhong decisive sortie to deploy Huang Zhong, Fa Zheng, Wang Ping, Ma Chao, Ma Dai, and Zhuge Liang with seven-officer pressure: ${JSON.stringify(hanzhongSortieReadyState)}`);
|
||||||
|
}
|
||||||
|
await page.screenshot({ path: 'dist/verification-hanzhong-decisive-sortie.png', fullPage: true });
|
||||||
|
|
||||||
|
await page.mouse.click(1068, 646);
|
||||||
|
await page.waitForFunction(() => {
|
||||||
|
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||||
|
return activeScenes.includes('StoryScene');
|
||||||
|
});
|
||||||
|
await page.screenshot({ path: 'dist/verification-hanzhong-decisive-story.png', fullPage: true });
|
||||||
|
|
||||||
|
for (let i = 0; i < 55; i += 1) {
|
||||||
|
const enteredThirtySeventhBattle = await page.evaluate(() => {
|
||||||
|
const state = window.__HEROS_DEBUG__?.battle();
|
||||||
|
return state?.scene === 'BattleScene' && state?.battleId === 'thirty-seventh-battle-hanzhong-decisive';
|
||||||
|
});
|
||||||
|
if (enteredThirtySeventhBattle) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await page.keyboard.press('Space');
|
||||||
|
await page.waitForTimeout(320);
|
||||||
|
}
|
||||||
|
await page.waitForFunction(() => {
|
||||||
|
const state = window.__HEROS_DEBUG__?.battle();
|
||||||
|
return state?.scene === 'BattleScene' && state?.battleId === 'thirty-seventh-battle-hanzhong-decisive' && state?.battleOutcome === null && state?.phase === 'idle';
|
||||||
|
});
|
||||||
|
await page.screenshot({ path: 'dist/verification-thirty-seventh-battle.png', fullPage: true });
|
||||||
|
|
||||||
|
const thirtySeventhBattleState = await page.evaluate(() => window.__HEROS_DEBUG__?.battle());
|
||||||
|
const thirtySeventhEnemies = thirtySeventhBattleState.units.filter((unit) => unit.faction === 'enemy');
|
||||||
|
const thirtySeventhAllies = thirtySeventhBattleState.units.filter((unit) => unit.faction === 'ally');
|
||||||
|
const thirtySeventhEnemyBehaviors = new Set(thirtySeventhEnemies.map((unit) => unit.ai));
|
||||||
|
if (
|
||||||
|
thirtySeventhBattleState.camera?.mapWidth !== 74 ||
|
||||||
|
thirtySeventhBattleState.camera?.mapHeight !== 56 ||
|
||||||
|
thirtySeventhBattleState.victoryConditionLabel !== '조조 본진 격파' ||
|
||||||
|
thirtySeventhEnemies.length < 30 ||
|
||||||
|
!thirtySeventhEnemyBehaviors.has('aggressive') ||
|
||||||
|
!thirtySeventhEnemyBehaviors.has('guard') ||
|
||||||
|
!thirtySeventhEnemyBehaviors.has('hold') ||
|
||||||
|
!thirtySeventhEnemies.some((unit) => unit.id === 'hanzhong-leader-cao-cao') ||
|
||||||
|
!thirtySeventhEnemies.some((unit) => unit.id === 'hanzhong-officer-zhang-he') ||
|
||||||
|
!thirtySeventhEnemies.some((unit) => unit.id === 'hanzhong-officer-xu-huang') ||
|
||||||
|
!thirtySeventhAllies.some((unit) => unit.id === 'huang-zhong') ||
|
||||||
|
!thirtySeventhAllies.some((unit) => unit.id === 'fa-zheng') ||
|
||||||
|
!thirtySeventhAllies.some((unit) => unit.id === 'wang-ping') ||
|
||||||
|
!thirtySeventhAllies.some((unit) => unit.id === 'ma-chao') ||
|
||||||
|
!thirtySeventhAllies.some((unit) => unit.id === 'ma-dai') ||
|
||||||
|
!thirtySeventhAllies.some((unit) => unit.id === 'zhuge-liang')
|
||||||
|
) {
|
||||||
|
throw new Error(`Expected thirty-seventh battle to use Hanzhong map, Cao Cao objective, Wang Ping terrain pressure, selected allied officers, and mixed AI: ${JSON.stringify(thirtySeventhBattleState)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.evaluate(() => window.__HEROS_DEBUG__?.forceBattleOutcome('victory'));
|
||||||
|
await page.waitForFunction(() => {
|
||||||
|
const state = window.__HEROS_DEBUG__?.battle();
|
||||||
|
return state?.battleOutcome === 'victory' && state?.phase === 'resolved' && state?.resultVisible === true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.mouse.click(738, 642);
|
||||||
|
await page.waitForFunction(() => {
|
||||||
|
const activeScenes = window.__HEROS_DEBUG__?.activeScenes() ?? [];
|
||||||
|
return activeScenes.includes('CampScene');
|
||||||
|
});
|
||||||
|
|
||||||
|
const thirtySeventhCampState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||||
|
if (
|
||||||
|
thirtySeventhCampState?.campBattleId !== 'thirty-seventh-battle-hanzhong-decisive' ||
|
||||||
|
thirtySeventhCampState.campTitle !== '한중 결전 후 군영' ||
|
||||||
|
thirtySeventhCampState.availableDialogueIds?.length !== 3 ||
|
||||||
|
!thirtySeventhCampState.availableDialogueIds.every((id) => id.endsWith('hanzhong-decisive')) ||
|
||||||
|
thirtySeventhCampState.availableVisitIds?.length !== 2 ||
|
||||||
|
!thirtySeventhCampState.campaign?.roster?.some((unit) => unit.id === 'wang-ping') ||
|
||||||
|
thirtySeventhCampState.rosterCollection?.total < 22
|
||||||
|
) {
|
||||||
|
throw new Error(`Expected thirty-seventh camp to expose Hanzhong decisive dialogue/visit sets and preserve Wang Ping roster: ${JSON.stringify(thirtySeventhCampState)}`);
|
||||||
|
}
|
||||||
|
await page.screenshot({ path: 'dist/verification-hanzhong-decisive-camp.png', fullPage: true });
|
||||||
|
|
||||||
|
await page.mouse.click(966, 38);
|
||||||
|
await page.waitForTimeout(180);
|
||||||
|
const postHanzhongProgressState = await page.evaluate(() => window.__HEROS_DEBUG__?.camp());
|
||||||
|
if (
|
||||||
|
postHanzhongProgressState?.activeTab !== 'progress' ||
|
||||||
|
postHanzhongProgressState.campaignProgress?.completedKnown !== 37 ||
|
||||||
|
postHanzhongProgressState.campaignProgress?.totalKnown !== 37 ||
|
||||||
|
postHanzhongProgressState.campaignProgress?.activeChapter?.title !== '촉한 건국' ||
|
||||||
|
postHanzhongProgressState.campaignProgress?.latestBattleTitle !== '한중 결전' ||
|
||||||
|
postHanzhongProgressState.campaignProgress?.nextBattleTitle !== '준비 중'
|
||||||
|
) {
|
||||||
|
throw new Error(`Expected post-Hanzhong progress tab to complete the decisive battle and pause on Shu-Han foundation prep: ${JSON.stringify(postHanzhongProgressState?.campaignProgress)}`);
|
||||||
|
}
|
||||||
|
await page.screenshot({ path: 'dist/verification-post-hanzhong-progress.png', fullPage: true });
|
||||||
|
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
const game = window.__HEROS_GAME__;
|
const game = window.__HEROS_GAME__;
|
||||||
game?.scene.stop('CampScene');
|
game?.scene.stop('CampScene');
|
||||||
@@ -4562,7 +4715,7 @@ try {
|
|||||||
return activeScenes.includes('CampScene');
|
return activeScenes.includes('CampScene');
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Verified title-to-thirty-sixth-battle flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan, Ma Chao, Ma Dai, and Wang Ping joins, Luofeng, Luo main gate, Mianzhu, Chengdu surrender, Jiameng Pass, Yangping scout, and Dingjun vanguard battles, result states, and debug API at ${targetUrl}`);
|
console.log(`Verified title-to-thirty-seventh-battle flow, recruited officer sortie selection, Ma Liang, Yi Ji, Gong Zhi, Huang Zhong, Wei Yan, Pang Tong, Fa Zheng, Wu Yi, Yan Yan, Li Yan, Huang Quan, Ma Chao, Ma Dai, and Wang Ping joins, Luofeng, Luo main gate, Mianzhu, Chengdu surrender, Jiameng, Yangping, Dingjun, and Hanzhong decisive battles, result states, and debug API at ${targetUrl}`);
|
||||||
} finally {
|
} finally {
|
||||||
await browser?.close();
|
await browser?.close();
|
||||||
if (serverProcess && !serverProcess.killed) {
|
if (serverProcess && !serverProcess.killed) {
|
||||||
|
|||||||
87
src/assets/images/battle/thirty-seventh-battle-map.svg
Normal file
87
src/assets/images/battle/thirty-seventh-battle-map.svg
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7400 5600" width="7400" height="5600">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="plain" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0" stop-color="#9f8f57"/>
|
||||||
|
<stop offset="0.48" stop-color="#c1ad6a"/>
|
||||||
|
<stop offset="1" stop-color="#7d7447"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="ridge" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0" stop-color="#766c41"/>
|
||||||
|
<stop offset="0.45" stop-color="#a99a5b"/>
|
||||||
|
<stop offset="1" stop-color="#504b31"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="water" x1="0" y1="0" x2="1" y2="0">
|
||||||
|
<stop offset="0" stop-color="#234e73"/>
|
||||||
|
<stop offset="0.5" stop-color="#5d9caa"/>
|
||||||
|
<stop offset="1" stop-color="#1d3c62"/>
|
||||||
|
</linearGradient>
|
||||||
|
<pattern id="grain" width="120" height="120" patternUnits="userSpaceOnUse">
|
||||||
|
<path d="M12 16h18M48 22h24M88 18h16M28 58h32M78 68h26M14 104h22M58 100h18" stroke="#453f27" stroke-width="8" stroke-linecap="round" opacity="0.18"/>
|
||||||
|
<circle cx="102" cy="92" r="8" fill="#e2cf85" opacity="0.26"/>
|
||||||
|
<circle cx="34" cy="34" r="6" fill="#6d653e" opacity="0.24"/>
|
||||||
|
</pattern>
|
||||||
|
<pattern id="forestDots" width="180" height="160" patternUnits="userSpaceOnUse">
|
||||||
|
<circle cx="40" cy="48" r="34" fill="#31491f"/>
|
||||||
|
<circle cx="76" cy="34" r="30" fill="#49682a"/>
|
||||||
|
<circle cx="108" cy="68" r="38" fill="#263a1d"/>
|
||||||
|
<circle cx="136" cy="42" r="24" fill="#6f8740"/>
|
||||||
|
<path d="M40 82c32 18 70 16 102-3" stroke="#151d11" stroke-width="10" opacity="0.35"/>
|
||||||
|
</pattern>
|
||||||
|
<pattern id="fortStone" width="140" height="120" patternUnits="userSpaceOnUse">
|
||||||
|
<rect width="140" height="120" fill="#6f6858"/>
|
||||||
|
<path d="M0 40h140M0 82h140M32 0v40M92 40v42M46 82v38M118 82v38" stroke="#332e27" stroke-width="8" opacity="0.42"/>
|
||||||
|
<path d="M12 20h28M76 62h34M20 102h24" stroke="#b4a377" stroke-width="8" opacity="0.34"/>
|
||||||
|
</pattern>
|
||||||
|
<filter id="softShadow" x="-10%" y="-10%" width="120%" height="120%">
|
||||||
|
<feDropShadow dx="0" dy="12" stdDeviation="16" flood-color="#1a160d" flood-opacity="0.38"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect width="7400" height="5600" fill="url(#plain)"/>
|
||||||
|
<rect width="7400" height="5600" fill="url(#grain)" opacity="0.9"/>
|
||||||
|
|
||||||
|
<path d="M1760 -80 C1670 600 1850 1190 1730 1880 C1600 2630 1820 3310 1730 4540" fill="none" stroke="#17375d" stroke-width="280" stroke-linecap="round"/>
|
||||||
|
<path d="M1760 -80 C1670 600 1850 1190 1730 1880 C1600 2630 1820 3310 1730 4540" fill="none" stroke="url(#water)" stroke-width="215" stroke-linecap="round"/>
|
||||||
|
<path d="M4250 390 C4100 1080 4360 1800 4210 2520 C4070 3180 4380 3550 4250 3940" fill="none" stroke="#17375d" stroke-width="250" stroke-linecap="round"/>
|
||||||
|
<path d="M4250 390 C4100 1080 4360 1800 4210 2520 C4070 3180 4380 3550 4250 3940" fill="none" stroke="url(#water)" stroke-width="188" stroke-linecap="round"/>
|
||||||
|
<path d="M5450 3900 C5580 4420 5330 5050 5470 5680" fill="none" stroke="#17375d" stroke-width="240" stroke-linecap="round"/>
|
||||||
|
<path d="M5450 3900 C5580 4420 5330 5050 5470 5680" fill="none" stroke="url(#water)" stroke-width="178" stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<path d="M-80 0 L1650 0 L1570 2420 L760 2200 L220 1550 Z" fill="url(#ridge)" filter="url(#softShadow)" opacity="0.88"/>
|
||||||
|
<path d="M2700 40 L6050 70 L5870 1820 L4200 1700 L3500 1180 L2620 1480 Z" fill="url(#ridge)" filter="url(#softShadow)" opacity="0.86"/>
|
||||||
|
<path d="M6250 -40 L7480 -40 L7460 1540 L6260 1510 Z" fill="url(#ridge)" filter="url(#softShadow)" opacity="0.9"/>
|
||||||
|
<path d="M3050 4820 L4660 4800 L4720 5660 L2940 5660 Z" fill="url(#ridge)" filter="url(#softShadow)" opacity="0.84"/>
|
||||||
|
|
||||||
|
<path d="M360 860 C1000 680 1720 820 2460 940 L2420 3920 C1700 3900 900 3720 340 4000 Z" fill="url(#forestDots)" opacity="0.9"/>
|
||||||
|
<path d="M2730 1620 C3200 1430 3800 1620 4050 2100 L4010 4160 C3410 4220 2910 3880 2680 3420 Z" fill="url(#forestDots)" opacity="0.85"/>
|
||||||
|
<path d="M4520 4250 C5300 3980 6330 4100 7380 3950 L7380 5480 C6300 5480 5350 5580 4480 5460 Z" fill="url(#forestDots)" opacity="0.88"/>
|
||||||
|
|
||||||
|
<path d="M390 5200 C1360 5070 2450 5030 3810 4580 C4700 4300 5560 3920 6480 3180 C6810 2920 7060 2630 7360 2240" fill="none" stroke="#6f5630" stroke-width="250" stroke-linecap="round" stroke-linejoin="round" opacity="0.95"/>
|
||||||
|
<path d="M390 5200 C1360 5070 2450 5030 3810 4580 C4700 4300 5560 3920 6480 3180 C6810 2920 7060 2630 7360 2240" fill="none" stroke="#c5a66b" stroke-width="168" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5840 1790 C6280 1750 6800 1810 7270 1880" fill="none" stroke="#c5a66b" stroke-width="150" stroke-linecap="round"/>
|
||||||
|
|
||||||
|
<rect x="5600" y="860" width="1660" height="2210" rx="24" fill="url(#fortStone)" filter="url(#softShadow)"/>
|
||||||
|
<rect x="5040" y="560" width="1420" height="1420" rx="24" fill="url(#fortStone)" opacity="0.82"/>
|
||||||
|
<rect x="6150" y="2380" width="1250" height="1650" rx="24" fill="url(#fortStone)" opacity="0.78"/>
|
||||||
|
<path d="M5550 3180 L6200 3000 L7060 3200 L7130 3780 L6500 4010 L5750 3740 Z" fill="#76654a" stroke="#2f2a21" stroke-width="36" opacity="0.9"/>
|
||||||
|
|
||||||
|
<g filter="url(#softShadow)">
|
||||||
|
<rect x="1800" y="4700" width="440" height="330" fill="#a2763b" stroke="#31261c" stroke-width="28"/>
|
||||||
|
<path d="M1760 4700 L2020 4440 L2280 4700 Z" fill="#c08c37" stroke="#31261c" stroke-width="28"/>
|
||||||
|
<rect x="3990" y="4020" width="520" height="360" fill="#8f7a42" stroke="#31261c" stroke-width="26"/>
|
||||||
|
<path d="M3960 4020 L4250 3760 L4540 4020 Z" fill="#b88831" stroke="#31261c" stroke-width="26"/>
|
||||||
|
<rect x="5320" y="3420" width="420" height="330" fill="#a2763b" stroke="#31261c" stroke-width="24"/>
|
||||||
|
<path d="M5290 3420 L5530 3210 L5770 3420 Z" fill="#c08c37" stroke="#31261c" stroke-width="24"/>
|
||||||
|
<rect x="6630" y="3620" width="460" height="340" fill="#8e6c36" stroke="#31261c" stroke-width="24"/>
|
||||||
|
<path d="M6600 3620 L6860 3390 L7120 3620 Z" fill="#ba8432" stroke="#31261c" stroke-width="24"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<path d="M2480 2520 L3070 3860" stroke="#231d16" stroke-width="74" stroke-linecap="round" opacity="0.55"/>
|
||||||
|
<path d="M5530 120 L5870 880" stroke="#211a14" stroke-width="70" stroke-linecap="round" opacity="0.55"/>
|
||||||
|
<path d="M7200 3540 L7420 4140" stroke="#211a14" stroke-width="70" stroke-linecap="round" opacity="0.55"/>
|
||||||
|
|
||||||
|
<g opacity="0.2" stroke="#241e14" stroke-width="7">
|
||||||
|
<path d="M0 100H7400M0 200H7400M0 300H7400M0 400H7400M0 500H7400M0 600H7400M0 700H7400M0 800H7400M0 900H7400M0 1000H7400M0 1100H7400M0 1200H7400M0 1300H7400M0 1400H7400M0 1500H7400M0 1600H7400M0 1700H7400M0 1800H7400M0 1900H7400M0 2000H7400M0 2100H7400M0 2200H7400M0 2300H7400M0 2400H7400M0 2500H7400M0 2600H7400M0 2700H7400M0 2800H7400M0 2900H7400M0 3000H7400M0 3100H7400M0 3200H7400M0 3300H7400M0 3400H7400M0 3500H7400M0 3600H7400M0 3700H7400M0 3800H7400M0 3900H7400M0 4000H7400M0 4100H7400M0 4200H7400M0 4300H7400M0 4400H7400M0 4500H7400M0 4600H7400M0 4700H7400M0 4800H7400M0 4900H7400M0 5000H7400M0 5100H7400M0 5200H7400M0 5300H7400M0 5400H7400M0 5500H7400"/>
|
||||||
|
<path d="M100 0V5600M200 0V5600M300 0V5600M400 0V5600M500 0V5600M600 0V5600M700 0V5600M800 0V5600M900 0V5600M1000 0V5600M1100 0V5600M1200 0V5600M1300 0V5600M1400 0V5600M1500 0V5600M1600 0V5600M1700 0V5600M1800 0V5600M1900 0V5600M2000 0V5600M2100 0V5600M2200 0V5600M2300 0V5600M2400 0V5600M2500 0V5600M2600 0V5600M2700 0V5600M2800 0V5600M2900 0V5600M3000 0V5600M3100 0V5600M3200 0V5600M3300 0V5600M3400 0V5600M3500 0V5600M3600 0V5600M3700 0V5600M3800 0V5600M3900 0V5600M4000 0V5600M4100 0V5600M4200 0V5600M4300 0V5600M4400 0V5600M4500 0V5600M4600 0V5600M4700 0V5600M4800 0V5600M4900 0V5600M5000 0V5600M5100 0V5600M5200 0V5600M5300 0V5600M5400 0V5600M5500 0V5600M5600 0V5600M5700 0V5600M5800 0V5600M5900 0V5600M6000 0V5600M6100 0V5600M6200 0V5600M6300 0V5600M6400 0V5600M6500 0V5600M6600 0V5600M6700 0V5600M6800 0V5600M6900 0V5600M7000 0V5600M7100 0V5600M7200 0V5600M7300 0V5600"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.7 KiB |
@@ -67,6 +67,10 @@ import {
|
|||||||
thirtySixthBattleMap,
|
thirtySixthBattleMap,
|
||||||
thirtySixthBattleUnits,
|
thirtySixthBattleUnits,
|
||||||
thirtySixthBattleVictoryPages,
|
thirtySixthBattleVictoryPages,
|
||||||
|
thirtySeventhBattleBonds,
|
||||||
|
thirtySeventhBattleMap,
|
||||||
|
thirtySeventhBattleUnits,
|
||||||
|
thirtySeventhBattleVictoryPages,
|
||||||
thirteenthBattleBonds,
|
thirteenthBattleBonds,
|
||||||
thirteenthBattleMap,
|
thirteenthBattleMap,
|
||||||
thirteenthBattleUnits,
|
thirteenthBattleUnits,
|
||||||
@@ -185,7 +189,8 @@ export type BattleScenarioId =
|
|||||||
| 'thirty-third-battle-chengdu-surrender'
|
| 'thirty-third-battle-chengdu-surrender'
|
||||||
| 'thirty-fourth-battle-jiameng-pass'
|
| 'thirty-fourth-battle-jiameng-pass'
|
||||||
| 'thirty-fifth-battle-yangping-scout'
|
| 'thirty-fifth-battle-yangping-scout'
|
||||||
| 'thirty-sixth-battle-dingjun-vanguard';
|
| 'thirty-sixth-battle-dingjun-vanguard'
|
||||||
|
| 'thirty-seventh-battle-hanzhong-decisive';
|
||||||
|
|
||||||
export type BattleObjectiveKind = 'defeat-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
|
export type BattleObjectiveKind = 'defeat-leader' | 'keep-unit-alive' | 'secure-terrain' | 'quick-victory';
|
||||||
|
|
||||||
@@ -2313,6 +2318,69 @@ export const thirtySixthBattleScenario: BattleScenarioDefinition = {
|
|||||||
nextCampScene: 'CampScene'
|
nextCampScene: 'CampScene'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const thirtySeventhBattleScenario: BattleScenarioDefinition = {
|
||||||
|
id: 'thirty-seventh-battle-hanzhong-decisive',
|
||||||
|
title: '한중 결전',
|
||||||
|
victoryConditionLabel: '조조 본진 격파',
|
||||||
|
defeatConditionLabel: '유비 또는 왕평 퇴각',
|
||||||
|
openingObjectiveLines: [
|
||||||
|
'한중 결전은 정군산 이후 북문 전체를 안정시키는 싸움입니다. 조조군 본진을 흔들어 한중의 주도권을 완전히 가져오십시오.',
|
||||||
|
'왕평은 이번 전장의 길잡이입니다. 왕평이 무너지면 산길과 보급로를 잇는 계획도 무너집니다.',
|
||||||
|
'황충과 법정은 정군산의 여세를 이어 고지를 누르고, 마초와 마대는 조조군 기병의 퇴로를 끊어 한중을 유비군의 깃발 아래 묶으십시오.'
|
||||||
|
],
|
||||||
|
map: thirtySeventhBattleMap,
|
||||||
|
units: thirtySeventhBattleUnits,
|
||||||
|
bonds: thirtySeventhBattleBonds,
|
||||||
|
mapTextureKey: 'battle-map-thirty-seventh',
|
||||||
|
leaderUnitId: 'hanzhong-leader-cao-cao',
|
||||||
|
quickVictoryTurnLimit: 58,
|
||||||
|
baseVictoryGold: 6840,
|
||||||
|
objectives: [
|
||||||
|
{
|
||||||
|
id: 'leader',
|
||||||
|
kind: 'defeat-leader',
|
||||||
|
label: '조조 본진 격파',
|
||||||
|
rewardGold: 4320,
|
||||||
|
unitId: 'hanzhong-leader-cao-cao'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'liu-bei',
|
||||||
|
kind: 'keep-unit-alive',
|
||||||
|
label: '유비 생존',
|
||||||
|
rewardGold: 1120,
|
||||||
|
unitId: 'liu-bei'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'wang-ping',
|
||||||
|
kind: 'keep-unit-alive',
|
||||||
|
label: '왕평 생존',
|
||||||
|
rewardGold: 1680,
|
||||||
|
unitId: 'wang-ping'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'hanzhong-storehouse',
|
||||||
|
kind: 'secure-terrain',
|
||||||
|
label: '한중 보급 창고 확보',
|
||||||
|
rewardGold: 2040,
|
||||||
|
terrain: 'village'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'quick',
|
||||||
|
kind: 'quick-victory',
|
||||||
|
label: '58턴 이내 승리',
|
||||||
|
rewardGold: 1560,
|
||||||
|
maxTurn: 58
|
||||||
|
}
|
||||||
|
],
|
||||||
|
defeatConditions: [
|
||||||
|
{ kind: 'unit-defeated', unitId: 'liu-bei' },
|
||||||
|
{ kind: 'unit-defeated', unitId: 'wang-ping' }
|
||||||
|
],
|
||||||
|
itemRewards: ['콩 30', '상처약 22', '탁주 10', '한중 병법서 1', '한중왕 즉위 준비'],
|
||||||
|
victoryPages: thirtySeventhBattleVictoryPages,
|
||||||
|
nextCampScene: 'CampScene'
|
||||||
|
};
|
||||||
|
|
||||||
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
|
export const defaultBattleScenarioId: BattleScenarioId = firstBattleScenario.id;
|
||||||
|
|
||||||
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
|
export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition> = {
|
||||||
@@ -2351,7 +2419,8 @@ export const battleScenarios: Record<BattleScenarioId, BattleScenarioDefinition>
|
|||||||
'thirty-third-battle-chengdu-surrender': thirtyThirdBattleScenario,
|
'thirty-third-battle-chengdu-surrender': thirtyThirdBattleScenario,
|
||||||
'thirty-fourth-battle-jiameng-pass': thirtyFourthBattleScenario,
|
'thirty-fourth-battle-jiameng-pass': thirtyFourthBattleScenario,
|
||||||
'thirty-fifth-battle-yangping-scout': thirtyFifthBattleScenario,
|
'thirty-fifth-battle-yangping-scout': thirtyFifthBattleScenario,
|
||||||
'thirty-sixth-battle-dingjun-vanguard': thirtySixthBattleScenario
|
'thirty-sixth-battle-dingjun-vanguard': thirtySixthBattleScenario,
|
||||||
|
'thirty-seventh-battle-hanzhong-decisive': thirtySeventhBattleScenario
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];
|
export const defaultBattleScenario = battleScenarios[defaultBattleScenarioId];
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
thirtySecondBattleScenario,
|
thirtySecondBattleScenario,
|
||||||
thirtyThirdBattleScenario,
|
thirtyThirdBattleScenario,
|
||||||
thirtySixthBattleScenario,
|
thirtySixthBattleScenario,
|
||||||
|
thirtySeventhBattleScenario,
|
||||||
thirtiethBattleScenario,
|
thirtiethBattleScenario,
|
||||||
twentyEighthBattleScenario,
|
twentyEighthBattleScenario,
|
||||||
twentyNinthBattleScenario,
|
twentyNinthBattleScenario,
|
||||||
@@ -84,6 +85,8 @@ import {
|
|||||||
thirtyThirdBattleVictoryPages,
|
thirtyThirdBattleVictoryPages,
|
||||||
thirtySixthBattleIntroPages,
|
thirtySixthBattleIntroPages,
|
||||||
thirtySixthBattleVictoryPages,
|
thirtySixthBattleVictoryPages,
|
||||||
|
thirtySeventhBattleIntroPages,
|
||||||
|
thirtySeventhBattleVictoryPages,
|
||||||
thirtiethBattleIntroPages,
|
thirtiethBattleIntroPages,
|
||||||
thirtiethBattleVictoryPages,
|
thirtiethBattleVictoryPages,
|
||||||
twentyEighthBattleIntroPages,
|
twentyEighthBattleIntroPages,
|
||||||
@@ -501,13 +504,24 @@ const sortieFlows: Record<string, SortieFlow> = {
|
|||||||
},
|
},
|
||||||
[thirtySixthBattleScenario.id]: {
|
[thirtySixthBattleScenario.id]: {
|
||||||
afterBattleId: thirtySixthBattleScenario.id,
|
afterBattleId: thirtySixthBattleScenario.id,
|
||||||
eyebrow: '다음 장 준비',
|
eyebrow: '다음 전장',
|
||||||
title: '한중 결전 준비',
|
title: thirtySeventhBattleScenario.title,
|
||||||
description:
|
description:
|
||||||
'정군산 전초전으로 한중의 고지를 확보했고 왕평이 합류했습니다. 다음은 한중 결전과 촉한 건국 선포로 이어질 큰 흐름을 준비해야 합니다.',
|
'정군산 전초전으로 한중의 고지를 확보했고 왕평이 합류했습니다. 이제 한중 결전에서 조조군 본진을 밀어내고 촉의 북문을 완전히 안정시킬 차례입니다.',
|
||||||
rewardHint: '다음 장: 한중 결전 준비 중',
|
rewardHint: `예상 보상: ${thirtySeventhBattleScenario.title} 개방 / 한중왕 즉위 준비`,
|
||||||
pages: thirtySixthBattleVictoryPages,
|
nextBattleId: thirtySeventhBattleScenario.id,
|
||||||
unavailableNotice: '한중 결전과 촉한 건국 선포는 다음 작업에서 이어집니다. 황충, 법정, 왕평의 산악 전선과 마초·마대의 기병 축을 준비하십시오.'
|
campaignStep: 'thirty-seventh-battle',
|
||||||
|
pages: [...thirtySixthBattleVictoryPages, ...thirtySeventhBattleIntroPages]
|
||||||
|
},
|
||||||
|
[thirtySeventhBattleScenario.id]: {
|
||||||
|
afterBattleId: thirtySeventhBattleScenario.id,
|
||||||
|
eyebrow: '다음 장 준비',
|
||||||
|
title: '촉한 건국 준비',
|
||||||
|
description:
|
||||||
|
'한중 결전에서 조조군을 물리치고 북문을 얻었습니다. 다음은 한중왕 즉위와 촉한의 이름을 세우는 정치적 전환을 군영 이벤트와 다음 전장으로 준비해야 합니다.',
|
||||||
|
rewardHint: '다음 장: 한중왕 즉위와 촉한 건국 준비 중',
|
||||||
|
pages: thirtySeventhBattleVictoryPages,
|
||||||
|
unavailableNotice: '한중왕 즉위와 촉한 건국 선포는 다음 작업에서 이어집니다. 유비의 명분, 제갈량의 국정 구상, 관우가 지키는 형주의 긴장을 함께 준비하십시오.'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2324,6 +2324,69 @@ export const thirtySixthBattleVictoryPages: StoryPage[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const thirtySeventhBattleIntroPages: StoryPage[] = [
|
||||||
|
{
|
||||||
|
id: 'thirty-seventh-hanzhong-front',
|
||||||
|
bgm: 'story-dark',
|
||||||
|
chapter: '한중 결전으로',
|
||||||
|
background: 'story-three-heroes',
|
||||||
|
speaker: '제갈량',
|
||||||
|
text: '정군산의 능선이 열리자 한중의 길은 마침내 하나의 전장으로 이어졌습니다. 조조군은 물러나기 전에 마지막으로 북문을 움켜쥐려 합니다.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'thirty-seventh-wang-ping-map',
|
||||||
|
bgm: 'battle-prep',
|
||||||
|
chapter: '산길의 눈',
|
||||||
|
background: 'story-liu-bei',
|
||||||
|
speaker: '왕평',
|
||||||
|
text: '본진으로 곧장 오르는 길은 적이 기다리는 길입니다. 강변 창고를 잡고 서쪽 숲길을 열면 조조군의 퇴로와 보급이 동시에 흔들립니다.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'thirty-seventh-huang-fa-plan',
|
||||||
|
bgm: 'battle-prep',
|
||||||
|
chapter: '노장과 군사의 합',
|
||||||
|
background: 'story-sortie',
|
||||||
|
speaker: '법정',
|
||||||
|
text: '황충 장군이 고지를 누르고 왕평이 길을 잇는 사이, 마초와 마대가 북쪽 기병대를 묶어야 합니다. 이 싸움은 힘보다 순서가 중요합니다.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'thirty-seventh-sortie',
|
||||||
|
bgm: 'battle-prep',
|
||||||
|
chapter: '한중 결전',
|
||||||
|
background: 'story-militia',
|
||||||
|
speaker: '유비',
|
||||||
|
portrait: 'liuBei',
|
||||||
|
text: '한중을 얻는 것은 북문을 얻는 일이고, 북문을 얻는 것은 촉의 백성을 지킬 이름을 얻는 일이오. 모두 각자의 길에서 하나의 깃발을 세우시오.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const thirtySeventhBattleVictoryPages: StoryPage[] = [
|
||||||
|
{
|
||||||
|
id: 'thirty-seventh-victory-hanzhong-held',
|
||||||
|
bgm: 'militia-theme',
|
||||||
|
chapter: '한중을 얻다',
|
||||||
|
background: 'story-sortie',
|
||||||
|
text: '조조군의 본진이 흔들리고 한중의 창고와 산길이 유비군의 손에 들어왔습니다. 북문을 지키던 군세는 물러났고, 촉으로 향하는 길은 비로소 안정되었습니다.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'thirty-seventh-king-of-hanzhong',
|
||||||
|
bgm: 'battle-prep',
|
||||||
|
chapter: '한중왕의 이름',
|
||||||
|
background: 'story-liu-bei',
|
||||||
|
speaker: '제갈량',
|
||||||
|
text: '주공께서 한중을 얻었으니 이제 사람들은 촉의 주인이 누구인지 묻게 될 것입니다. 이름은 칼보다 늦게 움직이나, 때로는 칼보다 멀리 갑니다.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'thirty-seventh-next-shu-han',
|
||||||
|
bgm: 'story-dark',
|
||||||
|
chapter: '촉한의 문턱',
|
||||||
|
background: 'story-three-heroes',
|
||||||
|
speaker: '유비',
|
||||||
|
portrait: 'liuBei',
|
||||||
|
text: '우리가 세우려는 것은 땅의 이름만이 아니오. 한실을 잇고 백성을 품을 뜻이라면, 이제 그 뜻을 나라의 이름으로 밝힐 준비를 해야 하오.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export const firstBattleMap: BattleMap = {
|
export const firstBattleMap: BattleMap = {
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 18,
|
height: 18,
|
||||||
@@ -2685,6 +2748,12 @@ export const thirtySixthBattleMap: BattleMap = {
|
|||||||
terrain: createThirtySixthBattleTerrain()
|
terrain: createThirtySixthBattleTerrain()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const thirtySeventhBattleMap: BattleMap = {
|
||||||
|
width: 74,
|
||||||
|
height: 56,
|
||||||
|
terrain: createThirtySeventhBattleTerrain()
|
||||||
|
};
|
||||||
|
|
||||||
export const firstBattleUnits: UnitData[] = [
|
export const firstBattleUnits: UnitData[] = [
|
||||||
{
|
{
|
||||||
id: 'liu-bei',
|
id: 'liu-bei',
|
||||||
@@ -13830,6 +13899,84 @@ export const thirtySixthBattleUnits: UnitData[] = [
|
|||||||
createThirtyFirstEnemyUnit('dingjun-leader-xiahou-yuan', '하후연', '정군산 주장', 'rebelLeader', 77, 418, 116, 68, 25)
|
createThirtyFirstEnemyUnit('dingjun-leader-xiahou-yuan', '하후연', '정군산 주장', 'rebelLeader', 77, 418, 116, 68, 25)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const thirtySeventhBattleAllyPositions: Record<string, { x: number; y: number }> = {
|
||||||
|
'liu-bei': { x: 4, y: 50 },
|
||||||
|
'guan-yu': { x: 5, y: 48 },
|
||||||
|
'zhang-fei': { x: 4, y: 52 },
|
||||||
|
'jian-yong': { x: 3, y: 53 },
|
||||||
|
'mi-zhu': { x: 5, y: 54 },
|
||||||
|
'sun-qian': { x: 7, y: 53 },
|
||||||
|
'zhao-yun': { x: 8, y: 49 },
|
||||||
|
'zhuge-liang': { x: 6, y: 48 },
|
||||||
|
'ma-liang': { x: 8, y: 54 },
|
||||||
|
'yi-ji': { x: 9, y: 51 },
|
||||||
|
'gong-zhi': { x: 10, y: 54 },
|
||||||
|
'huang-zhong': { x: 7, y: 50 },
|
||||||
|
'wei-yan': { x: 10, y: 48 },
|
||||||
|
'pang-tong': { x: 9, y: 49 },
|
||||||
|
'fa-zheng': { x: 11, y: 51 },
|
||||||
|
'wu-yi': { x: 12, y: 49 },
|
||||||
|
'yan-yan': { x: 11, y: 47 },
|
||||||
|
'li-yan': { x: 13, y: 48 },
|
||||||
|
'huang-quan': { x: 14, y: 50 },
|
||||||
|
'ma-chao': { x: 13, y: 46 },
|
||||||
|
'ma-dai': { x: 15, y: 47 },
|
||||||
|
'wang-ping': { x: 16, y: 49 }
|
||||||
|
};
|
||||||
|
|
||||||
|
export const thirtySeventhBattleUnits: 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, thirtySeventhBattleAllyPositions[unit.id] ?? { x: unit.x, y: unit.y })),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-scout-a', '조조 척후', '서곡 척후', 'bandit', 76, 254, 88, 21, 49),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-scout-b', '조조 척후', '강변 척후', 'bandit', 76, 254, 88, 30, 47),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-scout-c', '조조 척후', '북로 척후', 'bandit', 77, 262, 90, 40, 45),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-infantry-a', '조조 보병', '서곡 보병', 'yellowTurban', 77, 386, 110, 36, 42),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-infantry-b', '조조 보병', '중로 보병', 'yellowTurban', 77, 386, 110, 42, 40),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-infantry-c', '한중 보병', '능선 보병', 'yellowTurban', 78, 398, 114, 49, 37),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-infantry-d', '한중 보병', '창고 보병', 'yellowTurban', 78, 398, 114, 56, 34),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-infantry-e', '조조 보병', '본진 보병', 'yellowTurban', 79, 410, 116, 64, 29),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-infantry-f', '조조 보병', '퇴로 보병', 'yellowTurban', 79, 410, 116, 69, 24),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-archer-a', '조조 궁병', '서벽 궁병', 'archer', 77, 270, 92, 39, 39),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-archer-b', '조조 궁병', '능선 궁병', 'archer', 78, 278, 94, 51, 31),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-archer-c', '조조 궁병', '고지 궁병', 'archer', 78, 278, 94, 60, 26),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-archer-d', '조조 궁병', '본진 궁병', 'archer', 79, 286, 96, 68, 22),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-archer-e', '조조 궁병', '퇴로 궁병', 'archer', 79, 286, 96, 70, 31),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-cavalry-a', '조조 기병', '좌익 기병', 'cavalry', 78, 410, 116, 31, 50),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-cavalry-b', '조조 기병', '우익 기병', 'cavalry', 78, 410, 116, 47, 46),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-cavalry-c', '조조 기병', '돌격 기병', 'cavalry', 79, 422, 118, 59, 40),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-cavalry-d', '조조 기병', '친위 기병', 'cavalry', 79, 422, 118, 66, 36),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-cavalry-e', '조조 기병', '북로 기병', 'cavalry', 80, 434, 120, 71, 28),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-guard-a', '조조 친위대', '능선 친위대', 'yellowTurban', 80, 444, 122, 57, 31),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-guard-b', '조조 친위대', '본진 친위대', 'yellowTurban', 80, 444, 122, 65, 27),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-guard-c', '조조 친위대', '퇴로 친위대', 'yellowTurban', 81, 456, 124, 70, 20),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-strategist-a', '조조 책사', '능선 책사', 'strategist', 78, 278, 96, 54, 27),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-strategist-b', '조조 책사', '본진 책사', 'strategist', 79, 286, 98, 66, 24),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-strategist-c', '조조 책사', '퇴로 책사', 'strategist', 80, 294, 100, 71, 18),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-ambusher-a', '조조 복병', '남령 복병', 'bandit', 77, 264, 92, 43, 49),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-ambusher-b', '조조 복병', '동령 복병', 'bandit', 77, 264, 92, 56, 43),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-officer-zhang-he', '장합', '조조 선봉장', 'cavalry', 81, 462, 126, 62, 31),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-officer-xu-huang', '서황', '조조 우장군', 'rebelLeader', 82, 474, 128, 67, 26),
|
||||||
|
createThirtyFirstEnemyUnit('hanzhong-leader-cao-cao', '조조', '위왕', 'rebelLeader', 84, 520, 138, 70, 18)
|
||||||
|
];
|
||||||
|
|
||||||
export const firstBattleBonds: BattleBond[] = [
|
export const firstBattleBonds: BattleBond[] = [
|
||||||
{
|
{
|
||||||
id: 'liu-bei__guan-yu',
|
id: 'liu-bei__guan-yu',
|
||||||
@@ -14316,6 +14463,33 @@ export const hanzhongMainRecruitBonds: BattleBond[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const hanzhongDecisiveBonds: BattleBond[] = [
|
||||||
|
{
|
||||||
|
id: 'liu-bei__wang-ping',
|
||||||
|
unitIds: ['liu-bei', 'wang-ping'],
|
||||||
|
title: '한중의 새 주인',
|
||||||
|
level: 25,
|
||||||
|
exp: 0,
|
||||||
|
description: '유비의 명분과 왕평의 산길 판단이 맞물려 한중 병사들이 새 깃발을 받아들이는 속도를 높입니다.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'fa-zheng__wang-ping',
|
||||||
|
unitIds: ['fa-zheng', 'wang-ping'],
|
||||||
|
title: '산길 계책',
|
||||||
|
level: 27,
|
||||||
|
exp: 0,
|
||||||
|
description: '법정의 유인책과 왕평의 실제 길 지식이 합쳐져 적의 보급로와 퇴로를 동시에 흔듭니다.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'huang-zhong__fa-zheng',
|
||||||
|
unitIds: ['huang-zhong', 'fa-zheng'],
|
||||||
|
title: '정군산의 여세',
|
||||||
|
level: 32,
|
||||||
|
exp: 0,
|
||||||
|
description: '황충의 고지 돌파와 법정의 결단이 다시 맞물리며 한중 결전의 첫 압박을 강하게 만듭니다.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export const secondBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
export const secondBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||||
export const thirdBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
export const thirdBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||||
export const fourthBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
export const fourthBattleBonds: BattleBond[] = firstBattleBonds.map(cloneBattleBondForScenario);
|
||||||
@@ -14367,6 +14541,11 @@ export const thirtyFifthBattleBonds: BattleBond[] = [...thirtyFourthBattleBonds,
|
|||||||
export const thirtySixthBattleBonds: BattleBond[] = [...thirtyFifthBattleBonds, ...hanzhongScoutRecruitBonds].map(
|
export const thirtySixthBattleBonds: BattleBond[] = [...thirtyFifthBattleBonds, ...hanzhongScoutRecruitBonds].map(
|
||||||
cloneBattleBondForScenario
|
cloneBattleBondForScenario
|
||||||
);
|
);
|
||||||
|
export const thirtySeventhBattleBonds: BattleBond[] = [
|
||||||
|
...thirtySixthBattleBonds,
|
||||||
|
...hanzhongMainRecruitBonds,
|
||||||
|
...hanzhongDecisiveBonds
|
||||||
|
].map(cloneBattleBondForScenario);
|
||||||
|
|
||||||
function createEighthBattleTerrain(): TerrainType[][] {
|
function createEighthBattleTerrain(): TerrainType[][] {
|
||||||
return Array.from({ length: 22 }, (_, y) =>
|
return Array.from({ length: 22 }, (_, y) =>
|
||||||
@@ -15973,6 +16152,78 @@ function createThirtySixthBattleTerrain(): TerrainType[][] {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createThirtySeventhBattleTerrain(): TerrainType[][] {
|
||||||
|
return Array.from({ length: 56 }, (_, y) =>
|
||||||
|
Array.from({ length: 74 }, (_, x): TerrainType => {
|
||||||
|
if (x <= 4 && y >= 49) {
|
||||||
|
return 'camp';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(x >= 56 && x <= 72 && y >= 9 && y <= 30) ||
|
||||||
|
(x >= 50 && x <= 64 && y >= 6 && y <= 19) ||
|
||||||
|
(x >= 61 && x <= 73 && y >= 24 && y <= 39) ||
|
||||||
|
(x >= 64 && x <= 72 && y >= 16 && y <= 23)
|
||||||
|
) {
|
||||||
|
return 'fort';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(x >= 18 && x <= 22 && y >= 47 && y <= 50) ||
|
||||||
|
(x >= 40 && x <= 44 && y >= 40 && y <= 43) ||
|
||||||
|
(x >= 53 && x <= 56 && y >= 34 && y <= 37) ||
|
||||||
|
(x >= 66 && x <= 69 && y >= 36 && y <= 39)
|
||||||
|
) {
|
||||||
|
return 'village';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(y >= 51 && x >= 4 && x <= 24) ||
|
||||||
|
(x >= 23 && x <= 38 && y >= 46 && y <= 51) ||
|
||||||
|
(x >= 37 && x <= 52 && y >= 41 && y <= 46) ||
|
||||||
|
(x >= 51 && x <= 64 && y >= 35 && y <= 41) ||
|
||||||
|
(x >= 63 && x <= 72 && y >= 29 && y <= 35) ||
|
||||||
|
(x >= 67 && x <= 73 && y >= 22 && y <= 29) ||
|
||||||
|
(x >= 58 && x <= 72 && y >= 16 && y <= 20)
|
||||||
|
) {
|
||||||
|
return 'road';
|
||||||
|
}
|
||||||
|
if ((x === 17 || x === 18) && y >= 0 && y <= 45) {
|
||||||
|
return 'river';
|
||||||
|
}
|
||||||
|
if ((x === 42 || x === 43) && y >= 4 && y <= 39) {
|
||||||
|
return 'river';
|
||||||
|
}
|
||||||
|
if ((x === 54 || x === 55) && y >= 39 && y <= 55) {
|
||||||
|
return 'river';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(x >= 4 && x <= 25 && y >= 8 && y <= 39) ||
|
||||||
|
(x >= 27 && x <= 40 && y >= 16 && y <= 41) ||
|
||||||
|
(x >= 45 && x <= 59 && y >= 42 && y <= 55) ||
|
||||||
|
(x >= 57 && x <= 73 && y >= 39 && y <= 54)
|
||||||
|
) {
|
||||||
|
return 'forest';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(x >= 0 && x <= 16 && y <= 24) ||
|
||||||
|
(x >= 26 && x <= 41 && y <= 15) ||
|
||||||
|
(x >= 42 && x <= 60 && y >= 1 && y <= 18) ||
|
||||||
|
(x >= 62 && x <= 73 && y <= 15) ||
|
||||||
|
(x >= 30 && x <= 46 && y >= 48 && y <= 55)
|
||||||
|
) {
|
||||||
|
return 'hill';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(x <= 2 && y <= 48) ||
|
||||||
|
(x >= 71 && y >= 35) ||
|
||||||
|
(x >= 55 && x <= 58 && y <= 8) ||
|
||||||
|
(x >= 25 && x <= 30 && y >= 25 && y <= 38)
|
||||||
|
) {
|
||||||
|
return 'cliff';
|
||||||
|
}
|
||||||
|
return 'plain';
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
|
function placeScenarioUnit(unit: UnitData, position: { x: number; y: number }): UnitData {
|
||||||
return {
|
return {
|
||||||
...cloneUnitForScenario(unit),
|
...cloneUnitForScenario(unit),
|
||||||
|
|||||||
@@ -555,7 +555,37 @@ const unitTexture: Record<string, string> = {
|
|||||||
'dingjun-ambusher-b': 'unit-rebel',
|
'dingjun-ambusher-b': 'unit-rebel',
|
||||||
'dingjun-officer-zhang-he': 'unit-rebel-cavalry',
|
'dingjun-officer-zhang-he': 'unit-rebel-cavalry',
|
||||||
'dingjun-officer-wang-ping': 'unit-rebel',
|
'dingjun-officer-wang-ping': 'unit-rebel',
|
||||||
'dingjun-leader-xiahou-yuan': 'unit-rebel-leader'
|
'dingjun-leader-xiahou-yuan': 'unit-rebel-leader',
|
||||||
|
'hanzhong-scout-a': 'unit-rebel',
|
||||||
|
'hanzhong-scout-b': 'unit-rebel',
|
||||||
|
'hanzhong-scout-c': 'unit-rebel',
|
||||||
|
'hanzhong-infantry-a': 'unit-rebel',
|
||||||
|
'hanzhong-infantry-b': 'unit-rebel',
|
||||||
|
'hanzhong-infantry-c': 'unit-rebel',
|
||||||
|
'hanzhong-infantry-d': 'unit-rebel',
|
||||||
|
'hanzhong-infantry-e': 'unit-rebel',
|
||||||
|
'hanzhong-infantry-f': 'unit-rebel',
|
||||||
|
'hanzhong-archer-a': 'unit-rebel-archer',
|
||||||
|
'hanzhong-archer-b': 'unit-rebel-archer',
|
||||||
|
'hanzhong-archer-c': 'unit-rebel-archer',
|
||||||
|
'hanzhong-archer-d': 'unit-rebel-archer',
|
||||||
|
'hanzhong-archer-e': 'unit-rebel-archer',
|
||||||
|
'hanzhong-cavalry-a': 'unit-rebel-cavalry',
|
||||||
|
'hanzhong-cavalry-b': 'unit-rebel-cavalry',
|
||||||
|
'hanzhong-cavalry-c': 'unit-rebel-cavalry',
|
||||||
|
'hanzhong-cavalry-d': 'unit-rebel-cavalry',
|
||||||
|
'hanzhong-cavalry-e': 'unit-rebel-cavalry',
|
||||||
|
'hanzhong-guard-a': 'unit-rebel',
|
||||||
|
'hanzhong-guard-b': 'unit-rebel',
|
||||||
|
'hanzhong-guard-c': 'unit-rebel',
|
||||||
|
'hanzhong-strategist-a': 'unit-rebel-archer',
|
||||||
|
'hanzhong-strategist-b': 'unit-rebel-archer',
|
||||||
|
'hanzhong-strategist-c': 'unit-rebel-archer',
|
||||||
|
'hanzhong-ambusher-a': 'unit-rebel',
|
||||||
|
'hanzhong-ambusher-b': 'unit-rebel',
|
||||||
|
'hanzhong-officer-zhang-he': 'unit-rebel-cavalry',
|
||||||
|
'hanzhong-officer-xu-huang': 'unit-rebel-leader',
|
||||||
|
'hanzhong-leader-cao-cao': 'unit-rebel-leader'
|
||||||
};
|
};
|
||||||
|
|
||||||
const unitTextureByClass: Partial<Record<UnitClassKey, string>> = {
|
const unitTextureByClass: Partial<Record<UnitClassKey, string>> = {
|
||||||
@@ -1568,7 +1598,37 @@ const enemyAiByUnitId: Record<string, EnemyAiBehavior> = {
|
|||||||
'dingjun-ambusher-b': 'aggressive',
|
'dingjun-ambusher-b': 'aggressive',
|
||||||
'dingjun-officer-zhang-he': 'aggressive',
|
'dingjun-officer-zhang-he': 'aggressive',
|
||||||
'dingjun-officer-wang-ping': 'guard',
|
'dingjun-officer-wang-ping': 'guard',
|
||||||
'dingjun-leader-xiahou-yuan': 'guard'
|
'dingjun-leader-xiahou-yuan': 'guard',
|
||||||
|
'hanzhong-scout-a': 'aggressive',
|
||||||
|
'hanzhong-scout-b': 'aggressive',
|
||||||
|
'hanzhong-scout-c': 'aggressive',
|
||||||
|
'hanzhong-infantry-a': 'guard',
|
||||||
|
'hanzhong-infantry-b': 'guard',
|
||||||
|
'hanzhong-infantry-c': 'guard',
|
||||||
|
'hanzhong-infantry-d': 'guard',
|
||||||
|
'hanzhong-infantry-e': 'guard',
|
||||||
|
'hanzhong-infantry-f': 'guard',
|
||||||
|
'hanzhong-archer-a': 'hold',
|
||||||
|
'hanzhong-archer-b': 'hold',
|
||||||
|
'hanzhong-archer-c': 'hold',
|
||||||
|
'hanzhong-archer-d': 'hold',
|
||||||
|
'hanzhong-archer-e': 'hold',
|
||||||
|
'hanzhong-cavalry-a': 'aggressive',
|
||||||
|
'hanzhong-cavalry-b': 'aggressive',
|
||||||
|
'hanzhong-cavalry-c': 'aggressive',
|
||||||
|
'hanzhong-cavalry-d': 'aggressive',
|
||||||
|
'hanzhong-cavalry-e': 'aggressive',
|
||||||
|
'hanzhong-guard-a': 'guard',
|
||||||
|
'hanzhong-guard-b': 'guard',
|
||||||
|
'hanzhong-guard-c': 'guard',
|
||||||
|
'hanzhong-strategist-a': 'hold',
|
||||||
|
'hanzhong-strategist-b': 'hold',
|
||||||
|
'hanzhong-strategist-c': 'hold',
|
||||||
|
'hanzhong-ambusher-a': 'aggressive',
|
||||||
|
'hanzhong-ambusher-b': 'aggressive',
|
||||||
|
'hanzhong-officer-zhang-he': 'aggressive',
|
||||||
|
'hanzhong-officer-xu-huang': 'guard',
|
||||||
|
'hanzhong-leader-cao-cao': 'guard'
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultEnemyAiByClass: Partial<Record<UnitClassKey, EnemyAiBehavior>> = {
|
const defaultEnemyAiByClass: Partial<Record<UnitClassKey, EnemyAiBehavior>> = {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import thirtyFirstBattleMapUrl from '../../assets/images/battle/thirty-first-bat
|
|||||||
import thirtySecondBattleMapUrl from '../../assets/images/battle/thirty-second-battle-map.svg';
|
import thirtySecondBattleMapUrl from '../../assets/images/battle/thirty-second-battle-map.svg';
|
||||||
import thirtyThirdBattleMapUrl from '../../assets/images/battle/thirty-third-battle-map.svg';
|
import thirtyThirdBattleMapUrl from '../../assets/images/battle/thirty-third-battle-map.svg';
|
||||||
import thirtySixthBattleMapUrl from '../../assets/images/battle/thirty-sixth-battle-map.svg';
|
import thirtySixthBattleMapUrl from '../../assets/images/battle/thirty-sixth-battle-map.svg';
|
||||||
|
import thirtySeventhBattleMapUrl from '../../assets/images/battle/thirty-seventh-battle-map.svg';
|
||||||
import thirtiethBattleMapUrl from '../../assets/images/battle/thirtieth-battle-map.svg';
|
import thirtiethBattleMapUrl from '../../assets/images/battle/thirtieth-battle-map.svg';
|
||||||
import thirdBattleMapUrl from '../../assets/images/battle/third-battle-map.svg';
|
import thirdBattleMapUrl from '../../assets/images/battle/third-battle-map.svg';
|
||||||
import twentyEighthBattleMapUrl from '../../assets/images/battle/twenty-eighth-battle-map.svg';
|
import twentyEighthBattleMapUrl from '../../assets/images/battle/twenty-eighth-battle-map.svg';
|
||||||
@@ -130,6 +131,7 @@ export class BootScene extends Phaser.Scene {
|
|||||||
this.load.image('battle-map-thirty-fourth', thirtyFourthBattleMapUrl);
|
this.load.image('battle-map-thirty-fourth', thirtyFourthBattleMapUrl);
|
||||||
this.load.image('battle-map-thirty-fifth', thirtyFifthBattleMapUrl);
|
this.load.image('battle-map-thirty-fifth', thirtyFifthBattleMapUrl);
|
||||||
this.load.image('battle-map-thirty-sixth', thirtySixthBattleMapUrl);
|
this.load.image('battle-map-thirty-sixth', thirtySixthBattleMapUrl);
|
||||||
|
this.load.image('battle-map-thirty-seventh', thirtySeventhBattleMapUrl);
|
||||||
this.load.image('portrait-liu-bei', liuBeiPortraitUrl);
|
this.load.image('portrait-liu-bei', liuBeiPortraitUrl);
|
||||||
this.load.image('portrait-guan-yu', guanYuPortraitUrl);
|
this.load.image('portrait-guan-yu', guanYuPortraitUrl);
|
||||||
this.load.image('portrait-zhang-fei', zhangFeiPortraitUrl);
|
this.load.image('portrait-zhang-fei', zhangFeiPortraitUrl);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
fuPassRecruitUnits,
|
fuPassRecruitUnits,
|
||||||
guiyangRecruitBonds,
|
guiyangRecruitBonds,
|
||||||
guiyangRecruitUnits,
|
guiyangRecruitUnits,
|
||||||
|
hanzhongDecisiveBonds,
|
||||||
hanzhongOpeningRecruitBonds,
|
hanzhongOpeningRecruitBonds,
|
||||||
hanzhongOpeningRecruitUnits,
|
hanzhongOpeningRecruitUnits,
|
||||||
hanzhongMainRecruitBonds,
|
hanzhongMainRecruitBonds,
|
||||||
@@ -346,7 +347,8 @@ const campaignTimelineChapters: CampaignTimelineChapter[] = [
|
|||||||
battleIds: [
|
battleIds: [
|
||||||
'thirty-fourth-battle-jiameng-pass',
|
'thirty-fourth-battle-jiameng-pass',
|
||||||
'thirty-fifth-battle-yangping-scout',
|
'thirty-fifth-battle-yangping-scout',
|
||||||
'thirty-sixth-battle-dingjun-vanguard'
|
'thirty-sixth-battle-dingjun-vanguard',
|
||||||
|
'thirty-seventh-battle-hanzhong-decisive'
|
||||||
],
|
],
|
||||||
nextHints: ['왕업 선언', '오호대장군', '북벌 준비']
|
nextHints: ['왕업 선언', '오호대장군', '북벌 준비']
|
||||||
}
|
}
|
||||||
@@ -388,7 +390,8 @@ const campBattleIds = {
|
|||||||
thirtyThird: 'thirty-third-battle-chengdu-surrender',
|
thirtyThird: 'thirty-third-battle-chengdu-surrender',
|
||||||
thirtyFourth: 'thirty-fourth-battle-jiameng-pass',
|
thirtyFourth: 'thirty-fourth-battle-jiameng-pass',
|
||||||
thirtyFifth: 'thirty-fifth-battle-yangping-scout',
|
thirtyFifth: 'thirty-fifth-battle-yangping-scout',
|
||||||
thirtySixth: 'thirty-sixth-battle-dingjun-vanguard'
|
thirtySixth: 'thirty-sixth-battle-dingjun-vanguard',
|
||||||
|
thirtySeventh: 'thirty-seventh-battle-hanzhong-decisive'
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const requiredSortieUnitIds = new Set(['liu-bei']);
|
const requiredSortieUnitIds = new Set(['liu-bei']);
|
||||||
@@ -795,6 +798,19 @@ const sortieRulesByBattleId: Partial<Record<BattleScenarioId, SortieRuleDefiniti
|
|||||||
{ unitId: 'zhuge-liang', reason: '한중 본전으로 이어질 산악 전선과 왕평 설득을 설계합니다.' }
|
{ unitId: 'zhuge-liang', reason: '한중 본전으로 이어질 산악 전선과 왕평 설득을 설계합니다.' }
|
||||||
],
|
],
|
||||||
note: '정군산 전초전은 스물한 명 중 여섯 명만 출전합니다. 황충과 법정의 고지 압박, 마초·마대의 우회 기병, 제갈량의 큰 전선 설계를 모두 담을지 고민하게 됩니다.'
|
note: '정군산 전초전은 스물한 명 중 여섯 명만 출전합니다. 황충과 법정의 고지 압박, 마초·마대의 우회 기병, 제갈량의 큰 전선 설계를 모두 담을지 고민하게 됩니다.'
|
||||||
|
},
|
||||||
|
'thirty-seventh-battle-hanzhong-decisive': {
|
||||||
|
maxUnits: 7,
|
||||||
|
recommended: [
|
||||||
|
{ unitId: 'liu-bei', reason: '한중을 얻는 명분과 패배 조건의 중심입니다.' },
|
||||||
|
{ unitId: 'huang-zhong', reason: '정군산의 여세를 이어 고지 압박을 맡는 핵심 장수입니다.' },
|
||||||
|
{ unitId: 'fa-zheng', reason: '조조군 본진을 흔드는 유인책과 고지 운용의 핵심 참모입니다.' },
|
||||||
|
{ unitId: 'wang-ping', reason: '한중 산길과 보급로를 잇는 길잡이이며 생존 목표와 맞물립니다.' },
|
||||||
|
{ unitId: 'ma-chao', reason: '북쪽 기병대를 묶고 퇴로를 흔드는 기동 축입니다.' },
|
||||||
|
{ unitId: 'ma-dai', reason: '마초의 돌격을 회수하고 좁은 산길 기병 운용을 보조합니다.' },
|
||||||
|
{ unitId: 'zhuge-liang', reason: '한중 승리 이후 한중왕 즉위와 촉한 건국 흐름까지 설계합니다.' }
|
||||||
|
],
|
||||||
|
note: '한중 결전은 스물두 명 중 일곱 명만 출전합니다. 왕평까지 합류한 뒤 처음으로 출전 슬롯이 늘지만, 여전히 핵심 무장과 보조 참모를 모두 담기는 어렵습니다.'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3795,6 +3811,87 @@ const campDialogues: CampDialogue[] = [
|
|||||||
rewardExp: 12
|
rewardExp: 12
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'liu-wang-after-hanzhong-decisive',
|
||||||
|
title: '한중의 새 주인',
|
||||||
|
availableAfterBattleIds: [campBattleIds.thirtySeventh],
|
||||||
|
unitIds: ['liu-bei', 'wang-ping'],
|
||||||
|
bondId: 'liu-bei__wang-ping',
|
||||||
|
rewardExp: 40,
|
||||||
|
lines: [
|
||||||
|
'왕평: 한중의 병사들은 이긴 사람보다 오래 지켜 줄 사람을 기다립니다.',
|
||||||
|
'유비: 내가 이 땅을 얻었다면, 먼저 이 땅의 길과 사람을 배워야겠구려.',
|
||||||
|
'왕평: 그 말씀을 병사들에게 전하겠습니다. 길을 아는 자들이 먼저 마음을 열 것입니다.'
|
||||||
|
],
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
id: 'promise-hanzhong-stability',
|
||||||
|
label: '한중을 안정시키겠다',
|
||||||
|
response: '유비는 왕평에게 한중 병사들의 가족과 창고를 먼저 돌보라고 명했고, 왕평은 산길 병사들의 마음을 모으기 시작했습니다.',
|
||||||
|
rewardExp: 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'listen-local-soldiers',
|
||||||
|
label: '현지 병사의 말을 듣는다',
|
||||||
|
response: '왕평은 오래된 길잡이와 창고병을 불러 한중을 지키는 실제 고충을 유비에게 전했습니다.',
|
||||||
|
rewardExp: 14
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'fa-wang-after-hanzhong-decisive',
|
||||||
|
title: '산길 계책',
|
||||||
|
availableAfterBattleIds: [campBattleIds.thirtySeventh],
|
||||||
|
unitIds: ['fa-zheng', 'wang-ping'],
|
||||||
|
bondId: 'fa-zheng__wang-ping',
|
||||||
|
rewardExp: 38,
|
||||||
|
lines: [
|
||||||
|
'법정: 오늘의 승리는 적을 밀어낸 것보다 길을 끊은 순서가 좋았습니다.',
|
||||||
|
'왕평: 계책이 너무 빠르면 병사가 따라오지 못합니다. 길은 속도보다 끊기지 않는 것이 먼저입니다.',
|
||||||
|
'법정: 그 균형을 알았으니, 다음에는 더 멀리 움직일 수 있겠군요.'
|
||||||
|
],
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
id: 'plan-supply-chain',
|
||||||
|
label: '보급로를 다시 짠다',
|
||||||
|
response: '법정과 왕평은 전투에서 확인한 창고, 물길, 산길을 하나의 보급망으로 다시 정리했습니다.',
|
||||||
|
rewardExp: 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'mark-decoy-routes',
|
||||||
|
label: '유인로를 표시한다',
|
||||||
|
response: '왕평은 실제로 쓸 길과 적에게 보일 길을 구분했고, 법정은 그 차이를 다음 계책의 재료로 삼았습니다.',
|
||||||
|
rewardExp: 14
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'huang-fa-after-hanzhong-decisive',
|
||||||
|
title: '정군산의 여세',
|
||||||
|
availableAfterBattleIds: [campBattleIds.thirtySeventh],
|
||||||
|
unitIds: ['huang-zhong', 'fa-zheng'],
|
||||||
|
bondId: 'huang-zhong__fa-zheng',
|
||||||
|
rewardExp: 38,
|
||||||
|
lines: [
|
||||||
|
'황충: 오늘은 늙은 몸보다 군사의 눈이 먼저 적을 베었소.',
|
||||||
|
'법정: 장군의 칼이 움직일 때를 맞췄을 뿐입니다. 그 순간을 놓치지 않은 것은 장군입니다.',
|
||||||
|
'황충: 그렇다면 다음에도 나를 너무 아끼지 마시오. 좋은 때라면 늙은 말도 달릴 줄 아오.'
|
||||||
|
],
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
id: 'honor-veteran-charge',
|
||||||
|
label: '노장의 돌격을 기린다',
|
||||||
|
response: '법정은 황충의 돌격로를 병사들에게 설명했고, 노장의 결단은 한중 승리의 상징이 되었습니다.',
|
||||||
|
rewardExp: 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'temper-next-charge',
|
||||||
|
label: '다음 돌격을 아낀다',
|
||||||
|
response: '황충은 법정의 만류를 웃으며 받아들였고, 다음 큰 싸움을 위해 병사들의 숨을 고르게 했습니다.',
|
||||||
|
rewardExp: 13
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -5084,6 +5181,66 @@ const campVisits: CampVisitDefinition[] = [
|
|||||||
itemRewards: ['탁주 4']
|
itemRewards: ['탁주 4']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'hanzhong-king-audience',
|
||||||
|
title: '한중왕 즉위 논의',
|
||||||
|
location: '한중 본막',
|
||||||
|
availableAfterBattleIds: [campBattleIds.thirtySeventh],
|
||||||
|
bondId: 'liu-bei__wang-ping',
|
||||||
|
description: '유비, 제갈량, 왕평이 한중의 이름을 어떻게 세우고 백성에게 어떤 약속을 먼저 보일지 논의합니다.',
|
||||||
|
lines: [
|
||||||
|
'제갈량: 한중을 얻은 뒤에는 군사보다 이름이 먼저 움직입니다. 이름이 있어야 백성이 어디에 기대야 하는지 압니다.',
|
||||||
|
'왕평: 한중 병사들은 새 명령보다 새 약속을 더 기다립니다.',
|
||||||
|
'유비는 한중왕의 이름이 칼끝의 승리만이 아니라 백성의 질서가 되어야 함을 마음에 새겼습니다.'
|
||||||
|
],
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
id: 'prepare-king-edict',
|
||||||
|
label: '즉위 격문을 준비한다',
|
||||||
|
response: '제갈량은 유비의 뜻을 격문 초안으로 정리했고, 왕평은 한중 병사들이 이해할 말로 고쳐 적었습니다.',
|
||||||
|
bondExp: 34,
|
||||||
|
itemRewards: ['한중왕 격문 초안 1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'promise-local-relief',
|
||||||
|
label: '한중 구휼을 약속한다',
|
||||||
|
response: '유비는 창고를 먼저 백성과 병사 가족에게 열도록 명했고, 한중의 불안은 조금씩 잦아들었습니다.',
|
||||||
|
bondExp: 32,
|
||||||
|
gold: 720,
|
||||||
|
itemRewards: ['콩 12', '상처약 6']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'hanzhong-north-gate-supply',
|
||||||
|
title: '북문 보급 정비',
|
||||||
|
location: '한중 북쪽 창고',
|
||||||
|
availableAfterBattleIds: [campBattleIds.thirtySeventh],
|
||||||
|
bondId: 'fa-zheng__wang-ping',
|
||||||
|
description: '법정과 왕평이 조조군이 남긴 창고와 퇴로를 조사해 다음 국경 전선의 보급 기준을 세웁니다.',
|
||||||
|
lines: [
|
||||||
|
'법정: 이 창고가 비면 한중은 승리한 날부터 다시 흔들립니다.',
|
||||||
|
'왕평: 산길 창고는 큰 것 하나보다 작은 것 셋이 낫습니다. 막히는 길이 달마다 달라지기 때문입니다.',
|
||||||
|
'두 사람은 조조군이 남긴 표식과 한중 병사들의 기억을 맞춰 북문 보급망을 다시 그렸습니다.'
|
||||||
|
],
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
id: 'split-mountain-stores',
|
||||||
|
label: '산길 창고를 나눈다',
|
||||||
|
response: '왕평은 보급을 작은 창고로 나누었고, 법정은 적이 한 번에 끊기 어렵도록 운송 순서를 바꾸었습니다.',
|
||||||
|
bondExp: 34,
|
||||||
|
itemRewards: ['한중 보급표 1', '탁주 4']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'audit-cao-stores',
|
||||||
|
label: '조조군 창고를 조사한다',
|
||||||
|
response: '남겨진 장부에서 말먹이와 활시위가 발견되어, 다음 전선에서 기병과 궁병을 함께 운용할 여유가 생겼습니다.',
|
||||||
|
bondExp: 32,
|
||||||
|
gold: 760,
|
||||||
|
itemRewards: ['말먹이 2', '활시위 2']
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -5170,6 +5327,52 @@ export class CampScene extends Phaser.Scene {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (battleId === campBattleIds.thirtySeventh) {
|
||||||
|
this.campaign = ensureCampaignRosterUnits(
|
||||||
|
[
|
||||||
|
...xuzhouRecruitUnits,
|
||||||
|
...caoBreakRecruitUnits,
|
||||||
|
...liuBiaoRecruitUnits,
|
||||||
|
...zhugeRecruitUnits,
|
||||||
|
...jingzhouRecruitUnits,
|
||||||
|
...guiyangRecruitUnits,
|
||||||
|
...wulingRecruitUnits,
|
||||||
|
...changshaRecruitUnits,
|
||||||
|
...yizhouRecruitUnits,
|
||||||
|
...fuPassRecruitUnits,
|
||||||
|
...luoCastleRecruitUnits,
|
||||||
|
...luoCastleProperRecruitUnits,
|
||||||
|
...chengduPressureRecruitUnits,
|
||||||
|
...chengduSurrenderRecruitUnits,
|
||||||
|
...hanzhongOpeningRecruitUnits,
|
||||||
|
...hanzhongScoutRecruitUnits,
|
||||||
|
...hanzhongMainRecruitUnits
|
||||||
|
],
|
||||||
|
[
|
||||||
|
...xuzhouRecruitBonds,
|
||||||
|
...caoBreakRecruitBonds,
|
||||||
|
...liuBiaoRecruitBonds,
|
||||||
|
...zhugeRecruitBonds,
|
||||||
|
...jingzhouRecruitBonds,
|
||||||
|
...guiyangRecruitBonds,
|
||||||
|
...wulingRecruitBonds,
|
||||||
|
...changshaRecruitBonds,
|
||||||
|
...yizhouRecruitBonds,
|
||||||
|
...fuPassRecruitBonds,
|
||||||
|
...luoCastleRecruitBonds,
|
||||||
|
...luoCastleProperRecruitBonds,
|
||||||
|
...chengduPressureRecruitBonds,
|
||||||
|
...chengduSurrenderRecruitBonds,
|
||||||
|
...hanzhongOpeningRecruitBonds,
|
||||||
|
...hanzhongScoutRecruitBonds,
|
||||||
|
...hanzhongMainRecruitBonds,
|
||||||
|
...hanzhongDecisiveBonds
|
||||||
|
]
|
||||||
|
);
|
||||||
|
this.report = this.campaign.firstBattleReport ?? this.report;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (battleId === campBattleIds.thirtySixth) {
|
if (battleId === campBattleIds.thirtySixth) {
|
||||||
this.campaign = ensureCampaignRosterUnits(
|
this.campaign = ensureCampaignRosterUnits(
|
||||||
[
|
[
|
||||||
@@ -5651,6 +5854,9 @@ export class CampScene extends Phaser.Scene {
|
|||||||
|
|
||||||
private currentCampTitle() {
|
private currentCampTitle() {
|
||||||
const battleId = this.currentCampBattleId();
|
const battleId = this.currentCampBattleId();
|
||||||
|
if (battleId === campBattleIds.thirtySeventh) {
|
||||||
|
return '한중 결전 후 군영';
|
||||||
|
}
|
||||||
if (battleId === campBattleIds.thirtySixth) {
|
if (battleId === campBattleIds.thirtySixth) {
|
||||||
return '정군산 전초전 후 군영';
|
return '정군산 전초전 후 군영';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
thirtySecondBattleScenario,
|
thirtySecondBattleScenario,
|
||||||
thirtyThirdBattleScenario,
|
thirtyThirdBattleScenario,
|
||||||
thirtySixthBattleScenario,
|
thirtySixthBattleScenario,
|
||||||
|
thirtySeventhBattleScenario,
|
||||||
thirtiethBattleScenario,
|
thirtiethBattleScenario,
|
||||||
twentyEighthBattleScenario,
|
twentyEighthBattleScenario,
|
||||||
twentyFirstBattleScenario,
|
twentyFirstBattleScenario,
|
||||||
@@ -371,7 +372,8 @@ export class TitleScene extends Phaser.Scene {
|
|||||||
campaign.step === 'thirty-third-camp' ||
|
campaign.step === 'thirty-third-camp' ||
|
||||||
campaign.step === 'thirty-fourth-camp' ||
|
campaign.step === 'thirty-fourth-camp' ||
|
||||||
campaign.step === 'thirty-fifth-camp' ||
|
campaign.step === 'thirty-fifth-camp' ||
|
||||||
campaign.step === 'thirty-sixth-camp'
|
campaign.step === 'thirty-sixth-camp' ||
|
||||||
|
campaign.step === 'thirty-seventh-camp'
|
||||||
) {
|
) {
|
||||||
this.scene.start('CampScene');
|
this.scene.start('CampScene');
|
||||||
return;
|
return;
|
||||||
@@ -557,6 +559,11 @@ export class TitleScene extends Phaser.Scene {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (campaign.step === 'thirty-seventh-battle') {
|
||||||
|
this.scene.start('BattleScene', { battleId: thirtySeventhBattleScenario.id });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (campaign.step === 'first-victory-story') {
|
if (campaign.step === 'first-victory-story') {
|
||||||
this.scene.start('StoryScene', { pages: firstBattleVictoryPages, nextScene: 'TitleScene' });
|
this.scene.start('StoryScene', { pages: firstBattleVictoryPages, nextScene: 'TitleScene' });
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -113,7 +113,9 @@ export type CampaignStep =
|
|||||||
| 'thirty-fifth-battle'
|
| 'thirty-fifth-battle'
|
||||||
| 'thirty-fifth-camp'
|
| 'thirty-fifth-camp'
|
||||||
| 'thirty-sixth-battle'
|
| 'thirty-sixth-battle'
|
||||||
| 'thirty-sixth-camp';
|
| 'thirty-sixth-camp'
|
||||||
|
| 'thirty-seventh-battle'
|
||||||
|
| 'thirty-seventh-camp';
|
||||||
|
|
||||||
export type CampaignUnitProgressSnapshot = {
|
export type CampaignUnitProgressSnapshot = {
|
||||||
unitId: string;
|
unitId: string;
|
||||||
@@ -211,7 +213,8 @@ const campaignBattleSteps: Record<string, { victory: CampaignStep; retry: Campai
|
|||||||
'thirty-third-battle-chengdu-surrender': { victory: 'thirty-third-camp', retry: 'thirty-third-battle' },
|
'thirty-third-battle-chengdu-surrender': { victory: 'thirty-third-camp', retry: 'thirty-third-battle' },
|
||||||
'thirty-fourth-battle-jiameng-pass': { victory: 'thirty-fourth-camp', retry: 'thirty-fourth-battle' },
|
'thirty-fourth-battle-jiameng-pass': { victory: 'thirty-fourth-camp', retry: 'thirty-fourth-battle' },
|
||||||
'thirty-fifth-battle-yangping-scout': { victory: 'thirty-fifth-camp', retry: 'thirty-fifth-battle' },
|
'thirty-fifth-battle-yangping-scout': { victory: 'thirty-fifth-camp', retry: 'thirty-fifth-battle' },
|
||||||
'thirty-sixth-battle-dingjun-vanguard': { victory: 'thirty-sixth-camp', retry: 'thirty-sixth-battle' }
|
'thirty-sixth-battle-dingjun-vanguard': { victory: 'thirty-sixth-camp', retry: 'thirty-sixth-battle' },
|
||||||
|
'thirty-seventh-battle-hanzhong-decisive': { victory: 'thirty-seventh-camp', retry: 'thirty-seventh-battle' }
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CampaignSaveSlotSummary = {
|
export type CampaignSaveSlotSummary = {
|
||||||
|
|||||||
Reference in New Issue
Block a user