diff --git a/Assets/Resources/Scenario.meta b/Assets/Resources/Scenario.meta
new file mode 100644
index 00000000..07c4ad97
--- /dev/null
+++ b/Assets/Resources/Scenario.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: bd122d65f778f914ba5fc24acda8456f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/boss_intro.csv b/Assets/Resources/Scenario/boss_intro.csv
new file mode 100644
index 00000000..25107488
--- /dev/null
+++ b/Assets/Resources/Scenario/boss_intro.csv
@@ -0,0 +1,34 @@
+n_chapter,n_stage,n_order,s_boss_id,s_title_ko,s_line_ko,Memo
+1,5,1,hgj_boss_chengyuanzhi,황건 대장,부장의 원수는 내가 직접 갚아 주마!,정원지 · 1-4 에서 부장 등무가 쓰러진 직후 · 연의 1회
+1,10,1,hgj_boss_zhangjiao,천공장군,창천이사 황천당립! 하늘은 우리 편이다!,장각 · 황건의 구호(蒼天已死 黃天當立) · 연의 1회
+2,5,1,dz_boss_huaxiong,서량의 맹장,또 목을 내놓으러 온 놈이 있느냐!,화웅 · 유섭·반봉을 벤 뒤 관우가 나서는 장면 · 연의 5회
+2,10,1,dz_boss_lvbu,천하무쌍,셋이 한꺼번에 덤벼도 상관없다!,여포 · 삼영전여포 · 연의 5회
+3,5,1,ys_boss_quyi,선등 노병 대장,노병들아 활을 들어라! 한 놈도 강을 못 건넌다!,국의 · 노병 일제 사격으로 엄강을 무너뜨림 · 연의 7회
+3,10,1,hgj_boss_guanhai,황건 잔당의 거한,북해성은 오늘 이 관해의 것이다!,관해 · 공융의 북해 포위 · 연의 11회
+3,15,1,cc_boss_yujin,조조군 선봉장,어디서 온 미친 놈들이냐!,우금 · 기획서 3-15 컨셉의 대사 그대로 · 연의 11회
+4,5,1,ysu_boss_jiling,원술군 대장,관우! 오늘은 승부를 내자!,기령 · 관우와 30합 · 연의 14회
+4,10,1,dz_boss_gaoshun,함진영 대장,함진영! 한 걸음도 물러서지 마라!,고순 · 함진영(陷陣營) 지휘 · 연의 18회
+4,15,1,dz_boss_lvbu,하비의 비장,이 여포는 아직 끝나지 않았다!,여포 · 배신당해 고립된 백문루 직전 · 연의 19회
+5,5,1,ysu_boss_jiling,중가의 대장,우이에서 못 낸 승부 여기서 내 주마!,기령 · 4-5 관우와 비긴 기억 · 이번엔 장비가 벰 · 연의 21회
+5,10,1,cc_boss_liudai,토벌군 대장,승상의 명이다! 유비를 사로잡아라!,유대 · 2인 보스 첫째 · 연의 22회
+5,10,2,cc_boss_wangzhong,토벌군 부장,공은 내가 먼저 세우겠다!,왕충 · 2인 보스 둘째 · 유대와 공을 다툼 · 연의 22회
+5,15,1,cc_boss_xuhuang,대부의 명장,운장 돌아갈 길은 이미 없소.,서황 · 관우와 옛 친분 · 토산 고립 · 연의 25회
+5,15,2,cc_boss_xuchu,호치,이 허저를 넘어 보아라!,허저 · 2인 보스 둘째 · 연의 25회
+6,5,1,ys_boss_yanliang,하북의 명장,목을 바치러 온 자가 또 있구나.,안량 · 송헌·위속을 벤 뒤의 오만 · 연의 25회
+6,10,1,ys_boss_wenchou,하북의 맹장,안량의 원수 오늘 갚아 주마!,문추 · 연의 26회
+6,15,1,cc_boss_bianxi,사수관 수장,들켰구나! 모두 나와 관우를 쳐라!,변희 · 오관참육장 · 진국사 매복이 드러난 순간(6-14 보정의 눈짓 뒤) · 연의 27회
+6,20,1,cc_boss_xiahoudun,외눈의 장군,내 부장을 베고 어디로 가느냐!,하후돈 · 6-19 진기를 잃은 직후 · 4-9 에서 눈을 잃음 · 연의 28회·각색
+7,5,1,cc_boss_caiyang,복수의 노장,진기의 원수 네 목으로 갚아라!,채양 · 생질 진기의 복수 · 연의 28회
+7,10,1,cc_boss_gaolan,하북 출신 맹장,유비! 이 산길이 네 무덤이다!,고람 · 양산 패전 · 연의 31회
+8,5,1,jz_boss_zhangwu,강하 반란군 대장,적로의 발굽 아래 짓밟혀라!,장무 · 명마 적로를 탄 반란군 대장 · 연의 34회
+8,10,1,cc_boss_caoren,팔문금쇄진의 주인,이 진을 깨뜨릴 자가 있다면 나와 보라!,조인 · 팔문금쇄진 · 연의 36회
+8,15,1,cc_boss_xiahoudun,남정군 도독,풋내기 군사 따위 단숨에 짓밟아 주마!,하후돈 · 제갈량의 첫 지휘를 얕봄 · 연의 39회
+9,5,1,jz_boss_wenpin,양양의 수문장,양양의 문은 결코 열리지 않는다!,문빙 · 유종의 거부 · 연의 41회
+9,10,1,cc_boss_zhanghe,오자양장,승상께서 산 채로 잡으라 하셨다!,장합 · 조조의 「산 채로 잡아라」 · 연의 41회
+9,15,1,cc_boss_caocao,한의 승상,또 제갈량의 계략인가...!,조조 · 기획서 9-15 컨셉의 대사 그대로 · 연의 42회·각색
+10,5,1,jz_boss_caimao,형주 수군 도독,물 위의 싸움은 우리가 한 수 위다!,채모 · 2인 보스 첫째 · 연의 45회
+10,5,2,jz_boss_zhangyun,형주 수군 부도독,배를 붙여라! 한 척도 놓치지 마라!,장윤 · 2인 보스 둘째 · 연의 45회
+10,10,1,cc_boss_yujin,연환선단 도독,사슬로 묶은 배는 땅과 같다!,우금 · 연환계 함대 · 연의 45회(배경)·각색
+10,10,2,cc_boss_maojie,연환선단 부도독,궁수대! 화살을 아끼지 마라!,모개 · 2인 보스 둘째(궁병) · 연의 45회(배경)·각색
+10,15,1,dz_boss_zhangliao,조조의 호위 장수,승상! 제 뒤로 오십시오!,장료 · 조조를 태우고 북안으로 · 연의 49회
+10,20,1,cc_boss_caocao,패주하는 승상,운장... 옛정을 잊지는 않았겠지?,조조 · 화용도 의석조조 · 연의 50회
diff --git a/Assets/Resources/Scenario/boss_intro.csv.meta b/Assets/Resources/Scenario/boss_intro.csv.meta
new file mode 100644
index 00000000..3111e8bb
--- /dev/null
+++ b/Assets/Resources/Scenario/boss_intro.csv.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 12ea679cb7e96644ea7a143210f60457
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/boss_intro_config.csv b/Assets/Resources/Scenario/boss_intro_config.csv
new file mode 100644
index 00000000..95f50409
--- /dev/null
+++ b/Assets/Resources/Scenario/boss_intro_config.csv
@@ -0,0 +1,33 @@
+s_key,f_value,Memo
+warn_sec,0.4,① 경고 예고 — 붉은 가장자리 깜빡임 + 위아래 검은 띠가 들어오는 시간(초)
+warn_blink_count,2,① 붉은 가장자리 깜빡임 횟수(정수)
+letterbox_ratio,0.08,① 위아래 검은 띠 높이(화면 높이 비율)
+focus_move_sec,0.8,② 카메라가 아군 쪽에서 보스로 이동·확대하는 시간(초 · 지금 FocusOn·ZoomTo 는 시간 인자가 없어 시간 지정 버전 필요)
+focus_view_ratio,0.6,② 보스 포커스 때 시야 높이(평소 시야 높이 대비 비율 · 작을수록 확대)
+dim_others,0.4,② 포커스 중 보스 외 유닛 어둡게(0 = 그대로 · 1 = 검정)
+focus_ring_scale,1.6,② 보스 발밑 붉은 원 지름(보스 지름 대비 배율)
+cutin_banner_in_sec,0.2,③ 「BOSS 등장!」 띠가 왼쪽 위 화면 밖에서 쓸고 들어오는 시간(초 · 컷인 맨 먼저)
+cutin_banner_pop_scale,1.35,③ 「BOSS 등장!」 글자가 크게 찍혔다 제자리로 줄어드는 시작 배율(→ 1.0)
+cutin_banner_text_width,0.6,③ 「BOSS 등장!」 글자 너비(화면 폭 비율)
+cutin_info_delay_sec,0.15,③ 위 띠가 자리 잡은 뒤 보스 그림·아래 이름 띠가 들어오기까지(초)
+cutin_in_sec,0.25,③ 보스 그림(오른쪽에서)·아래 이름 띠가 들어오는 시간(초)
+cutin_hold_sec,0.8,③ 다 들어온 뒤 멈춰 있는 시간(초) · 컷인 전체 = 위 띠 + 지연 + 들어옴 + 멈춤 + 빠짐 = 1.7초
+cutin_out_sec,0.3,③ 컷인이 빠지는 시간(초)
+cutin_bg_dark,0.55,③ 컷인 뒤 전장 어둡게(0~1)
+cutin_art_height,0.55,③ 보스 전신 그림 높이(화면 높이 비율 · 1인 보스)
+cutin_art_height_duo,0.45,③ 2인 보스일 때 그림 높이(각자 · 화면 높이 비율)
+cutin_band_angle,12,③ 위·아래 띠 기울기(도 · 오른쪽 위로)
+cutin_shake,0.25,③ 보스 그림이 멈출 때 화면 흔들림 세기(CameraController.Shake 의 magnitude)
+cutin_shake_sec,0.25,③ 그 흔들림 시간(초 · Shake 의 duration)
+bubble_pop_sec,0.15,④ 말풍선이 튀어나오는 시간(초)
+bubble_pop_from,0.6,④ 튀어나올 때 시작 크기(배)
+bubble_pop_peak,1.05,④ 튀어나올 때 가장 커지는 크기(배 · 그 뒤 1.0)
+bubble_char_per_sec,30,④ 대사 글자가 찍히는 속도(초당 글자)
+bubble_hold_sec,1.3,④ 대사가 다 찍힌 뒤 유지 시간(초)
+bubble_fade_sec,0.2,④ 말풍선이 사라지는 시간(초)
+bubble_max_chars,28,④ 대사 최대 글자 수(정수 · 공백 포함 · 넘으면 데이터 검사 실패)
+bubble_font_size,30,④ 말풍선 글자 크기(px · 1080×1920 기준)
+second_boss_move_sec,0.5,④ 2인 보스일 때 첫째 → 둘째 보스로 카메라 이동 시간(초)
+return_sec,0.7,⑤ 보스에서 아군 쪽 기본 시야로 돌아오는 시간(초)
+skip_show_after_sec,0.5,건너뛰기 버튼이 나타나는 시점(연출 시작 후 초)
+replay_mode,1,다시 출정(클리어 후) 때 연출 — 정수 코드 0 = 전체 · 1 = 축약(컷인 빼고 포커스 + 말풍선) · 2 = 없음
diff --git a/Assets/Resources/Scenario/boss_intro_config.csv.meta b/Assets/Resources/Scenario/boss_intro_config.csv.meta
new file mode 100644
index 00000000..d9bba645
--- /dev/null
+++ b/Assets/Resources/Scenario/boss_intro_config.csv.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 46eef39625c15414285dcd8bfd704b2e
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/bubble.png b/Assets/Resources/Scenario/bubble.png
new file mode 100644
index 00000000..489e0b6f
Binary files /dev/null and b/Assets/Resources/Scenario/bubble.png differ
diff --git a/Assets/Resources/Scenario/bubble.png.meta b/Assets/Resources/Scenario/bubble.png.meta
new file mode 100644
index 00000000..39230f00
--- /dev/null
+++ b/Assets/Resources/Scenario/bubble.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: 328bf19b8f9643439ee1526b359ab4bd
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.50000, y: 0.50000}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 40, y: 40, z: 40, w: 40}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 9468ef1440584c74be1e3cf42154a9e8
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 7279e003311444a7876fc9eb0264e504
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/bubble_tail.png b/Assets/Resources/Scenario/bubble_tail.png
new file mode 100644
index 00000000..96f74399
Binary files /dev/null and b/Assets/Resources/Scenario/bubble_tail.png differ
diff --git a/Assets/Resources/Scenario/bubble_tail.png.meta b/Assets/Resources/Scenario/bubble_tail.png.meta
new file mode 100644
index 00000000..c5ec2cf2
--- /dev/null
+++ b/Assets/Resources/Scenario/bubble_tail.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: 5637bdc2b7734583ac678e860f6d8ecf
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.50000, y: 1.00000}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 1ca605ff6a084a22bf2edcbf5e916908
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 4c5d156713dc4b0b971acc2893997a72
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/cutin_band_bottom.png b/Assets/Resources/Scenario/cutin_band_bottom.png
new file mode 100644
index 00000000..f376ace8
Binary files /dev/null and b/Assets/Resources/Scenario/cutin_band_bottom.png differ
diff --git a/Assets/Resources/Scenario/cutin_band_bottom.png.meta b/Assets/Resources/Scenario/cutin_band_bottom.png.meta
new file mode 100644
index 00000000..420e952d
--- /dev/null
+++ b/Assets/Resources/Scenario/cutin_band_bottom.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: edb834ba6e244c3d881d88d8c1d073e4
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.50000, y: 0.00000}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 7e4707c6d78a47c28ce02ce7f5b1357e
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 7ecd8f3bae8f45ffae13ee5c7714496b
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/cutin_band_top.png b/Assets/Resources/Scenario/cutin_band_top.png
new file mode 100644
index 00000000..dc094eef
Binary files /dev/null and b/Assets/Resources/Scenario/cutin_band_top.png differ
diff --git a/Assets/Resources/Scenario/cutin_band_top.png.meta b/Assets/Resources/Scenario/cutin_band_top.png.meta
new file mode 100644
index 00000000..43aa3dff
--- /dev/null
+++ b/Assets/Resources/Scenario/cutin_band_top.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: f4ce6406d2144225961c64c63dcd18b2
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.50000, y: 1.00000}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 4860da324e69449496ef6a4c34d8021e
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: d7a6472618374bbcbf70cf1382f8f968
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/cutin_title.png b/Assets/Resources/Scenario/cutin_title.png
new file mode 100644
index 00000000..cffe6c49
Binary files /dev/null and b/Assets/Resources/Scenario/cutin_title.png differ
diff --git a/Assets/Resources/Scenario/cutin_title.png.meta b/Assets/Resources/Scenario/cutin_title.png.meta
new file mode 100644
index 00000000..b1c3c58b
--- /dev/null
+++ b/Assets/Resources/Scenario/cutin_title.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: 7e9462d0b8ec44bbbfa2299dae7061a5
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.33333, y: 0.42418}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: cddc0dd883d74f15b522e51e7e145f1c
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 1717f543f2d048ea88d6ea0f79fecb60
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/cutin_warning.png b/Assets/Resources/Scenario/cutin_warning.png
new file mode 100644
index 00000000..0efb278e
Binary files /dev/null and b/Assets/Resources/Scenario/cutin_warning.png differ
diff --git a/Assets/Resources/Scenario/cutin_warning.png.meta b/Assets/Resources/Scenario/cutin_warning.png.meta
new file mode 100644
index 00000000..129716e6
--- /dev/null
+++ b/Assets/Resources/Scenario/cutin_warning.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: b0107069f04c42d2bd6ba681827f0b40
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.50000, y: 0.50000}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 610a690f68d34772b66ac2d0da50439e
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: c67a3ce1db5248e08766397fdca3ea5b
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/name_tag.png b/Assets/Resources/Scenario/name_tag.png
new file mode 100644
index 00000000..cfcc6330
Binary files /dev/null and b/Assets/Resources/Scenario/name_tag.png differ
diff --git a/Assets/Resources/Scenario/name_tag.png.meta b/Assets/Resources/Scenario/name_tag.png.meta
new file mode 100644
index 00000000..9635210a
--- /dev/null
+++ b/Assets/Resources/Scenario/name_tag.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: 67c93a2787224ffbb67e9169db9eb177
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.50000, y: 0.50000}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 24, y: 24, z: 24, w: 24}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: a60d1a2559ac4d4b9ab81ee9c0fb8f87
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 3a775a79c9b342c39def19b2752cc81e
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/stage_story.csv b/Assets/Resources/Scenario/stage_story.csv
new file mode 100644
index 00000000..7dad192e
--- /dev/null
+++ b/Assets/Resources/Scenario/stage_story.csv
@@ -0,0 +1,146 @@
+n_chapter,n_stage,s_desc_ko,Memo
+1,1,의용군 방이 붙은 탁현 저잣거리에서 장비가 황건 앞잡이 건달들에게 둘러싸였다.,탁현 저잣거리 — 장비 구출 · 튜토리얼(조작) · 근거 연의 1회 각색(방 앞 만남 → 장비 구출)
+1,2,탁현 외곽 고갯길에서 떠돌던 무사 관우가 황건 척후들에게 포위되었다.,탁현 고갯길 — 관우 구출 · 튜토리얼(아군 밀치기 · 3턴) · 근거 연의 1회 각색(주막 만남 → 관우 구출)
+1,3,셋이 함께 누상촌으로 돌아가던 길에 황건 무리가 사방에서 몰려왔다.,누상촌 어귀 — 포위 돌파 · 튜토리얼(장수 스킬) · 근거 연의 1회 각색 · 클리어 뒤 도원결의
+1,4,도원에서 의형제를 맺은 세 사람이 대흥산에 닿자 정원지의 부장 등무가 앞을 막았다.,대흥산 — 등무 · 엘리트 · 튜토리얼(상성) · 근거 연의 1회
+1,5,부장을 잃고 분노한 정원지가 황건 5만을 이끌고 산기슭으로 몰려왔다.,대흥산 전투 — 정원지 · 보스 · 튜토리얼(보스·바위) · 근거 연의 1회
+1,6,청주태수 공경의 구원 요청에 달려가니 성은 황건 포위망에 갇혀 있었다.,청주 포위망 · 일반 · 튜토리얼(보병 연쇄·목책) · 근거 연의 1회
+1,7,유비가 미끼가 되어 물러나는 사이 관우와 장비는 산 뒤에 숨어 적을 기다렸다.,청주 산골 매복 · 일반 · 튜토리얼(기병 관통·함정) · 근거 연의 1회
+1,8,스승 노식의 명으로 영천에 이르니 관군의 화공에 쫓긴 황건이 불길 속을 달아나고 있었다.,영천 — 불길 속 황건 · 엘리트 · 튜토리얼(창병 밀치기·불길) · 근거 연의 1회·각색(유비군 도착 전 승부가 남 · 장보의 요술은 2회 곡양 장면을 가져옴)
+1,9,모함으로 압송되는 스승 노식을 뒤로하고 광종에 이르자 장량의 황건 전위가 길을 막았다.,광종 — 황건 본진 전위 · 엘리트 · 튜토리얼(궁병 사선·자유 편성) · 근거 연의 1회·각색(장량 배치)
+1,10,패주하는 동탁을 구하려 세 형제는 천공장군 장각의 대군 한가운데로 뛰어들었다.,광종 결전 — 장각 · 보스 · 종합 · 근거 연의 1회·각색(연의 2회는 관군 도착 전 장각이 이미 죽은 것으로만 나옴 · 병사 = 정사 — 결말 텍스트)
+2,1,18로 제후가 모인 산조 진영 주변에 동탁군 척후 기병이 어른거렸다.,산조 진영 — 동탁군 척후 · 일반 · 근거 가상
+2,2,공손찬 군의 말석에 선 유비 일행은 사수관으로 향하는 산길에 올랐다.,사수관 가는 길 · 일반 · 근거 가상
+2,3,손견의 선봉이 사수관에 닿자 동탁군 장수 호진이 관문 앞에 진을 쳤다.,사수관 앞 — 호진 · 엘리트 · 근거 연의 5회·각색(연의는 정보가 호진을 벰 → 결말 텍스트)
+2,4,군량이 끊긴 손견의 진영에 화웅의 야습이 덮쳐 와 밤하늘이 불타올랐다.,손견 진영 야습 · 일반 · 근거 연의 5회·각색
+2,5,연합의 장수들이 잇달아 쓰러지자 마궁수 관우가 데운 술을 두고 관문 앞으로 나섰다.,사수관 — 화웅 · 보스 · 근거 연의 5회
+2,6,화웅을 잃은 사수관 수비대가 관문 안쪽에서 무너지기 시작했다.,사수관 함락 — 잔병 · 일반 · 근거 가상
+2,7,동탁이 친히 호로관으로 나서자 서량 기병대가 연합의 앞을 막아섰다.,호로관 가는 길 — 서량 기병 · 일반 · 근거 가상
+2,8,방열과 목순이 여포에게 단번에 쓰러진 호로관 앞에 다시 적이 몰려들었다.,호로관 앞 — 방열이 쓰러진 자리 · 일반 · 근거 연의 5회(배경) · 가상(전투)
+2,9,공손찬마저 쫓기게 만든 여포의 철기를 끊으려 유비 일행은 관문 측면으로 돌았다.,호로관 측면 — 적토마 돌격대 · 일반 · 근거 연의 5회·각색
+2,10,천하무쌍 여포가 적토마를 몰고 나오자 장비가 먼저 장팔사모를 겨눴다.,호로관 — 여포 · 보스 · 근거 연의 5회
+3,1,공손찬의 원군 요청을 받은 유비 일행은 평원을 떠나 반하로 향했다.,평원 출진 — 원소군 척후 · 일반 · 근거 가상
+3,2,반하에 이르자 원소군의 경계 기병과 보병이 강변 들판을 지키고 있었다.,반하 들판 · 일반 · 근거 가상
+3,3,쫓기는 공손찬 앞에 백마를 탄 젊은 장수 조운이 나타나 문추를 막아섰다.,반하 다리 — 문추의 추격 · 엘리트 · 근거 연의 7회·각색(조운 단독 장면에 유비군 동참)
+3,4,공손찬의 장수 엄강을 쓰러뜨린 원소군 노병이 강변에 화살비를 퍼부었다.,반하 — 엄강의 패전 · 일반 · 근거 연의 7회
+3,5,선등 노병을 이끄는 국의가 직접 활을 들고 강변 진영에 버티고 섰다.,반하 — 국의 · 보스 · 근거 연의 7회
+3,6,북해의 공융이 위태롭다는 소식에 길을 나서자 청주를 휩쓰는 황건 잔당이 앞을 막았다.,북해 가는 길 — 황건 잔당 · 일반 · 근거 가상
+3,7,관해의 수만 대군이 공융의 북해성을 겹겹이 에워싸고 있었다.,북해 포위망 바깥 · 일반 · 근거 연의 11회
+3,8,포위를 뚫고 나온 태사자와 함께 유비 일행은 성으로 가는 길을 열었다.,태사자의 돌파로 · 일반 · 근거 연의 11회
+3,9,성문을 두드리는 관해의 친위 무리를 몰아내야 북해를 구할 수 있었다.,북해 성문 — 관해 친위 · 일반 · 근거 가상
+3,10,황건 잔당의 거한 관해가 큰 칼을 들고 성문 앞에 버티고 섰다.,북해 — 관해 · 보스 · 근거 연의 11회
+3,11,부친의 원수를 갚겠다는 조조군이 서주의 마을들을 불태우고 있었다.,서주 가는 길 — 불타는 마을 · 일반 · 근거 연의 10회(배경)·가상
+3,12,공손찬에게 빌린 조운과 함께 유비 일행은 서주를 둘러싼 조조의 포위진에 닿았다.,서주 외곽 — 조조 포위진 · 일반 · 근거 연의 11회
+3,13,조조군 약탈대에 쫓기는 피난민 행렬이 서주 남쪽 들판을 메우고 있었다.,서주 남쪽 — 피난민 행렬 · 일반 · 근거 가상
+3,14,유비와 장비는 1천 군사로 조조 진영의 가장자리를 뚫고 들어갔다.,조조 진영 외곽 · 일반 · 근거 연의 11회
+3,15,조조 진영을 돌파하려는 유비 일행 앞에 조조의 장수 우금이 막아섰다.,서주 — 우금 · 보스 · 근거 연의 11회
+4,1,서주를 노리는 원술의 대군을 막으려 유비 일행은 회수 가의 우이로 나아갔다.,우이 들판 — 원술군 선봉 · 일반 · 근거 연의 14회(배경)·가상
+4,2,원술군의 군량선이 회음 강변을 따라 올라오고 있었다.,회음 강변 — 군량 수송대 · 일반 · 근거 가상
+4,3,기령의 부장 순정이 관우를 노리고 진 앞으로 뛰쳐나왔다.,우이 — 순정 · 엘리트 · 근거 연의 14회
+4,4,유비 일행은 밤을 틈타 기령의 진영을 덮치기로 했다.,우이 진영 야습 · 일반 · 근거 가상
+4,5,원술군 대장 기령이 삼첨도를 들고 관우와 맞서러 나왔다.,우이 — 기령 · 보스 · 근거 연의 14회
+4,6,장비에게 매를 맞은 조표가 성문을 열자 여포의 기병이 서주성으로 들이쳤다.,서주성의 밤 — 조표의 배신 · 일반 · 근거 연의 14회(정사는 하비)
+4,7,장비가 여포의 말을 빼앗은 일로 화가 난 여포가 소패로 군을 몰아왔다.,소패 — 빼앗긴 말 · 일반 · 근거 연의 16회
+4,8,소패를 잃은 유비 일행은 허도의 조조에게 몸을 맡기려 서쪽으로 달렸다.,소패 탈출 — 여포군 추격 · 일반 · 근거 연의 16회
+4,9,다시 소패를 치는 여포군 앞에서 원군 하후돈이 조성의 화살에 한쪽 눈을 잃었다.,소패 구원 — 조성 · 엘리트 · 근거 연의 18회
+4,10,함진영을 이끄는 고순이 소패 성문을 향해 총공격을 시작했다.,소패 — 고순 · 보스 · 근거 연의 18회 · 정사(함진영 = 『영웅기』)
+4,11,진규·진등 부자의 계책에 속은 여포는 서주성을 비우고 소관으로 나섰다.,서주성 — 진등의 계책 · 일반 · 근거 연의 19회
+4,12,계책이 번번이 무시당한 책사 진궁이 하비 외곽에 수비진을 쳤다.,하비 외곽 — 진궁 · 엘리트 · 근거 연의 19회
+4,13,조조군이 기수와 사수의 둑을 터뜨리자 하비성이 물에 잠기기 시작했다.,하비 수공 · 일반 · 근거 연의 19회
+4,14,후성·송헌·위속이 성문을 연 날 장료만은 끝까지 창을 놓지 않았다.,하비 성문 — 장료 · 엘리트 · 근거 연의 19회
+4,15,모든 것을 잃은 여포가 백문루 앞에서 마지막 화극을 들었다.,하비 — 여포 · 보스 · 근거 연의 19회·각색(연의는 부하가 결박)
+5,1,조조의 객장이 된 유비 일행은 허전 사냥 길목을 어지럽히는 도적을 쫓았다.,허도 근교 — 사냥터의 도적 · 일반 · 근거 연의 20회(배경)·가상
+5,2,원술이 원소에게 가려 북상하자 유비는 차단을 자청해 허도를 떠났다.,허도 출진 — 원술 차단 · 일반 · 근거 연의 21회
+5,3,옥새를 품고 원소에게 가는 원술 행렬의 선봉이 서주 남쪽에 나타났다.,서주 남쪽 — 원술군 선봉 · 일반 · 근거 연의 21회
+5,4,황제를 칭한 원술의 화려한 친위대가 행렬을 지키고 있었다.,원술 친위대 · 일반 · 근거 가상
+5,5,우이에서 관우와 비겼던 기령이 다시 길을 막자 장비가 앞으로 나섰다.,서주 남쪽 — 기령 · 보스 · 근거 연의 21회
+5,6,꿀물 한 그릇을 찾다 숨진 원술의 잔병들이 수춘 북쪽 황무지로 흩어졌다.,원술의 몰락 — 패잔병 · 일반 · 근거 연의 21회
+5,7,진등이 귀띔한 대로 서주성 앞에는 차주의 복병이 숨어 있었다.,서주성 앞 — 차주의 복병 · 일반 · 근거 연의 21회
+5,8,조조의 밀명을 받은 차주가 서주성 성문을 걸어 잠갔다.,서주성 — 차주 · 엘리트 · 근거 연의 21회
+5,9,서주를 되찾은 유비를 치려고 조조가 보낸 토벌군이 몰려왔다.,서주 외곽 — 조조 토벌군 · 일반 · 근거 연의 22회
+5,10,조조의 장수 유대와 왕충이 진을 펼치고 유비 일행을 기다렸다.,서주 — 유대·왕충 · 보스(2인) · 근거 연의 22회
+5,11,의대조가 드러나 조조가 친히 출병하자 장비는 소패에서 야습에 나섰다.,소패 야습 · 일반 · 근거 연의 24회
+5,12,야습을 간파당한 형제들은 조조군에 쫓겨 뿔뿔이 흩어졌다.,소패 패주로 · 일반 · 근거 연의 24회
+5,13,두 형수를 지키며 하비에 남은 관우 앞에 조조의 대군이 몰려왔다.,하비 — 고립된 관우 · 일반 · 근거 연의 25회
+5,14,하후돈이 싸움을 걸고 달아나며 관우를 성 밖으로 꾀어냈다.,하비 성 밖 — 하후돈의 유인 · 엘리트 · 근거 연의 25회
+5,15,하비로 돌아가는 길을 서황과 허저가 막아서자 관우는 토산에 고립되었다.,토산 — 서황·허저 · 보스(2인) · 근거 연의 25회·각색(결과)
+6,1,조조의 진영에 몸을 맡긴 관우는 원소군에 포위된 백마로 향했다.,백마 포위망 · 일반 · 근거 연의 25회
+6,2,안량의 칼에 송헌과 위속이 쓰러지고 서황마저 물러나 전선이 무너지고 있었다.,백마 — 쓰러진 송헌·위속 · 일반 · 근거 연의 25회
+6,3,깃발 아래 앉은 안량의 본진까지 가는 길이 관우 앞에 열렸다.,백마 들판 — 안량 본진 앞 · 일반 · 근거 가상
+6,4,관우의 단기 돌입을 막으려 원소군의 측면 기병이 몰려들었다.,백마 — 측면 기병 · 일반 · 근거 가상
+6,5,하북의 명장 안량이 깃발 아래에서 다가오는 관우를 내려다보았다.,백마 — 안량 · 보스 · 근거 연의 25회
+6,6,안량의 원수를 갚으려는 문추의 군이 황하를 건너 연진에 올랐다.,연진 — 원소군 도하 · 일반 · 근거 연의 26회
+6,7,조조가 일부러 흘린 군량과 말에 문추의 군이 흩어져 있었다.,연진 — 버려진 군량과 말 · 일반 · 근거 연의 26회
+6,8,장료와 서황이 문추에게 밀려난 자리에 관우가 말을 세웠다.,연진 — 장료·서황의 패퇴 · 일반 · 근거 연의 26회
+6,9,강을 등진 문추의 친위대가 마지막 진을 쳤다.,연진 강변 — 문추 친위 · 일반 · 근거 가상
+6,10,형제 같던 안량을 잃은 문추가 분노에 차 관우를 찾아 나섰다.,연진 — 문추 · 보스 · 근거 연의 26회
+6,11,유비의 소식에 두 형수를 모시고 떠난 관우를 첫 관문 동령관의 공수가 막았다.,동령관 — 공수 · 엘리트 · 근거 연의 27회
+6,12,낙양 태수 한복의 부장 맹탄이 싸우는 척 물러나며 관우를 끌어들였다.,낙양 외곽 — 맹탄 · 엘리트 · 근거 연의 27회
+6,13,성문 뒤에 숨은 한복이 관우를 향해 활시위를 당겼다.,낙양 성문 — 한복 · 엘리트 · 근거 연의 27회
+6,14,진국사의 스님 보정이 눈짓으로 절간에 숨은 칼잡이들을 알려 주었다.,사수관 — 진국사 매복 · 일반 · 근거 연의 27회
+6,15,매복이 드러나자 변희가 유성추를 휘두르며 절 마당으로 뛰쳐나왔다.,사수관 — 변희 · 보스 · 근거 연의 27회
+6,16,형양 태수 왕식이 친절한 얼굴로 객관을 내주었지만 밤은 고요하지 않았다.,형양 — 왕식의 연회 · 일반 · 근거 연의 27회
+6,17,호반의 귀띔대로 객관에 불길이 치솟자 관우는 성문을 향해 길을 뚫었다.,형양 — 불붙은 객관 · 일반 · 근거 연의 27회
+6,18,계략이 실패한 왕식이 군사를 이끌고 성문까지 관우를 쫓아왔다.,형양 성문 — 왕식 · 엘리트 · 근거 연의 27회
+6,19,황하를 건널 배가 있는 활주 나루를 하후돈의 부장 진기가 막아섰다.,활주 나루 — 진기 · 엘리트 · 근거 연의 27회
+6,20,다섯 관문을 지나 황하에 이른 관우를 하후돈이 끝까지 쫓아왔다.,황하 나루 — 하후돈 · 보스 · 근거 연의 28회·각색(연의는 승부 전 중단)
+7,1,황하를 건넌 관우는 손건이 전한 소식을 따라 여남 쪽으로 길을 재촉했다.,황하 남쪽 — 순찰대 · 일반 · 근거 가상
+7,2,관우를 흠모하던 주창이 따라나서자 남은 산적 무리가 칼을 들었다.,와우산 — 주창의 산채 · 일반 · 근거 연의 28회·가상(전투)
+7,3,고성의 장비가 형님을 의심해 창을 겨누는 사이 채양의 선봉이 들이닥쳤다.,고성 — 의심하는 장비 · 일반 · 근거 연의 28회
+7,4,생질 진기의 원수를 갚겠다는 채양의 본대가 고성 외곽을 메웠다.,고성 외곽 — 채양 본대 · 일반 · 근거 연의 28회
+7,5,장비의 북이 세 번 울리기 전에 관우는 채양을 베어야 했다.,고성 — 채양 · 보스 · 근거 연의 28회
+7,6,형주 유세를 핑계로 원소 진영을 빠져나온 유비를 원소군이 뒤쫓았다.,하북 경계 — 유비의 탈출 · 일반 · 근거 연의 28회·각색(추격전)
+7,7,관정장에서 관평을 얻은 유비 일행 앞에 원소군 추격대가 들이닥쳤다.,관정장 — 관평 · 일반 · 근거 연의 28회·각색(전투)
+7,8,와우산에서 배원소 무리를 쫓던 유비 일행은 그리던 조운과 다시 만났다.,와우산 — 배원소 · 엘리트 · 근거 연의 28회·각색(조운 단독 장면)
+7,9,관도에서 원소를 꺾은 조조가 돌아와 양산의 유비군을 앞뒤로 조여 왔다.,양산 — 조조의 추격 · 엘리트 · 근거 연의 31회
+7,10,유벽을 벤 고람이 산길을 막아서자 조운이 창을 고쳐 쥐었다.,양산 — 고람 · 보스 · 근거 연의 31회
+8,1,양산에서 패한 유비 일행은 형주의 유표에게 몸을 맡기러 남쪽으로 향했다.,형주 가는 길 — 추격 잔당 · 일반 · 근거 가상
+8,2,유표의 근심인 강하 반란을 진압하러 유비가 직접 군을 이끌었다.,강하 — 반란군 선봉 · 일반 · 근거 연의 34회(배경)·가상
+8,3,산채 위에 자리 잡은 반란군 궁병이 쉴 새 없이 화살을 쏘아 댔다.,강하 산채 — 반란군 궁병 · 일반 · 근거 가상
+8,4,빼앗긴 말을 되찾겠다며 진손이 유비 진영으로 달려들었다.,강하 — 진손 · 엘리트 · 근거 연의 34회·각색(순서)
+8,5,명마 적로를 탄 반란군 대장 장무가 강변 들판에 나타났다.,강하 — 장무 · 보스 · 근거 연의 34회
+8,6,이적의 귀띔에 술잔을 내려놓자 채모의 복병이 양양 연회장을 둘러싸고 있었다.,양양 연회 — 채모의 복병 · 엘리트 · 근거 연의 34회
+8,7,채모의 추격대에 쫓긴 유비는 단계의 개울가에서 적로의 고삐를 당겼다.,단계 — 적로의 도약 · 일반 · 근거 연의 34회
+8,8,조인이 보낸 여광이 신야로 쳐들어오자 군사 선복이 첫 계책을 내놓았다.,신야 — 여광 · 엘리트 · 근거 연의 35회
+8,9,형 여광을 잃은 여상이 분노해 신야로 돌격해 왔다.,신야 — 여상 · 엘리트 · 근거 연의 35회
+8,10,조인이 신야 앞에 펼친 팔문금쇄진을 선복이라 이름을 숨겼던 서서가 꿰뚫어 보았다.,신야 — 조인 · 팔문금쇄진 · 보스 · 근거 연의 36회
+8,11,조인이 야습에 나선 사이 관우는 비어 있는 번성으로 향했다.,번성 — 빈 성 · 일반 · 근거 연의 36회
+8,12,모친의 편지를 받은 서서가 떠나고 형제들은 반격해 온 조조군에게서 번성을 지켰다.,번성 방위 — 조조군 반격 · 일반 · 근거 가상
+8,13,와룡을 찾아 세 번째로 융중에 오르는 눈길에 산적 무리가 숨어 있었다.,융중 가는 길 — 눈보라 속 산적 · 일반 · 근거 연의 37~38회(배경)·가상
+8,14,제갈량의 지시대로 조운이 거짓으로 달아나며 하후돈의 선봉을 갈대숲 깊이 끌어들였다.,박망파 — 하후돈 선봉 · 일반 · 근거 연의 39회
+8,15,하후돈의 10만 대군이 박망파 갈대밭에 들어서자 제갈량이 불화살을 명했다.,박망파 — 하후돈 · 보스 · 근거 연의 39회
+9,1,백성을 모두 내보낸 신야에 조인과 조홍이 들어서자 성 곳곳에서 불길이 치솟았다.,신야 화공 — 조홍 · 엘리트 · 근거 연의 40회
+9,2,관우는 모래 자루로 막아 둔 백하 상류의 둑을 터뜨릴 때를 기다렸다.,백하 — 관우의 수공 · 일반 · 근거 연의 40회
+9,3,물에서 살아 나온 조인의 패잔병을 장비가 박릉 나루에서 기다렸다.,박릉 나루 — 장비 매복 · 일반 · 근거 연의 40회
+9,4,유비를 따르는 10만 백성의 행렬이 한수를 건너기 시작했다.,번성 철수 — 백성 행렬 · 일반 · 근거 연의 41회
+9,5,유종이 성문을 닫아 건 양양에서 위연이 문을 열려다 문빙과 맞붙었다.,양양 성문 — 문빙 · 보스 · 근거 연의 41회·각색
+9,6,백성과 함께 더디게 남하하던 유비군을 조조의 호표기가 밤낮없이 쫓아왔다.,당양 — 호표기의 추격 · 일반 · 근거 연의 41회·정사(조순의 호표기)
+9,7,흩어진 가족을 찾아 적진으로 돌아간 조운 앞에 미축을 묶어 가던 순우도가 나타났다.,장판 — 순우도 · 엘리트 · 근거 연의 41회
+9,8,조조의 보검 청강검을 찬 하후은이 조운의 앞을 가로막았다.,장판 — 하후은 · 엘리트 · 근거 연의 41회
+9,9,아두를 품에 안은 조운을 안명과 하북의 네 장수가 겹겹이 막아섰다.,장판 — 안명과 하북 4장 · 엘리트 · 근거 연의 41회·각색(순서)
+9,10,아두를 품은 조운이 구덩이에 빠지자 장합이 창을 들고 달려들었다.,장판파 — 장합 · 보스 · 근거 연의 41회
+9,11,장판교 위에 홀로 선 장비 앞에서 조조의 대군이 걸음을 멈췄다.,장판교 — 장비의 일갈 · 엘리트 · 근거 연의 42회
+9,12,장판교를 끊은 것이 들키자 조조의 대군이 다시 쫓아오기 시작했다.,부서진 장판교 · 일반 · 근거 연의 42회
+9,13,유비 일행은 한수의 나루 한진을 향해 마지막 달음질을 했다.,한진 가는 길 — 조조 철기 · 일반 · 근거 가상
+9,14,강하에서 온 관우와 유기의 배에 오를 때까지 나루를 지켜야 했다.,한진 — 관우·유기의 수군 · 일반 · 근거 연의 42회·각색
+9,15,나루 언덕까지 쫓아온 조조가 직접 군을 이끌고 모습을 드러냈다.,한진 나루 — 조조 · 보스 · 근거 연의 42회·각색(연의는 원군을 보고 물러남)
+10,1,강하에 모인 유비군을 엿보려 조조군 정찰 선단이 하구로 다가왔다.,하구 — 조조군 정찰선 · 일반 · 근거 가상
+10,2,손권과 동맹을 맺으러 가는 뱃길에 형주 수군의 경계선이 놓여 있었다.,장강 — 형주 수군 경계선 · 일반 · 근거 가상
+10,3,주유의 수군이 삼강구로 나아가자 형주 수군 장수 채훈의 배가 앞을 막았다.,삼강구 — 채훈 · 엘리트 · 근거 연의 45회
+10,4,물에 서툰 북방 병사와 형주 수군이 뒤섞인 선단이 삼강구를 메웠다.,삼강구 — 형주 수군 본대 · 일반 · 근거 연의 45회
+10,5,형주 수군 도독 채모와 장윤이 기함 위에서 수군을 지휘하고 있었다.,삼강구 — 채모·장윤 · 보스(2인) · 근거 연의 45회
+10,6,짙은 안개 속 짚단을 실은 배들이 조조의 수채를 향해 북을 울렸다.,초선차전 — 안개 속 화살비 · 일반 · 근거 연의 46회
+10,7,고육계로 피투성이가 된 황개의 밀서를 품고 감택이 북안에 올랐다.,장강 북안 — 감택의 밀서 · 일반 · 근거 연의 46~47회(배경)·가상
+10,8,방통의 권유로 사슬에 묶인 조조의 함대가 흔들림 없이 장강을 덮었다.,연환선 — 사슬로 묶인 함대 · 일반 · 근거 연의 47회(배경)·가상
+10,9,동남풍을 기다리는 밤 오림 수채 앞을 조조군 순찰 선단이 오갔다.,오림 수채 앞 — 순찰 선단 · 일반 · 근거 가상
+10,10,채모를 대신해 수군을 맡은 우금과 모개가 연환선단을 이끌고 나왔다.,연환선단 — 우금·모개 · 보스(2인) · 근거 연의 45회(배경)·각색
+10,11,칠성단에 동남풍이 불자 황개의 화선이 조조의 수채를 향해 돛을 올렸다.,동남풍 — 화선 출격 · 일반 · 근거 연의 49회
+10,12,사슬에 묶여 달아나지 못하는 조조의 함대가 붉은 불길에 휩싸였다.,적벽 — 불타는 연환선 · 일반 · 근거 연의 49회
+10,13,거짓 투항한 채중을 앞세운 감녕이 수채 안 깊숙이 불을 질렀다.,수채 — 감녕과 채중 · 엘리트 · 근거 연의 49~50회
+10,14,조조를 태울 작은 배를 지키려 친위대가 불길 속에 버티고 있었다.,수채 본진 — 불길 속 친위대 · 일반 · 근거 가상
+10,15,황개를 화살로 떨어뜨린 장료가 조조를 태우고 북안으로 달아나려 했다.,적벽 — 장료 · 보스 · 근거 연의 49회
+10,16,불타는 적벽을 뒤로하고 달아나는 조조 앞에 오림의 숲길에서 조운이 뛰쳐나왔다.,오림 — 조운의 매복 · 엘리트 · 근거 연의 50회
+10,17,호로구에서 밥을 짓던 조조의 패잔병 앞에 장비가 나타났다.,호로구 — 장비의 매복 · 엘리트 · 근거 연의 50회
+10,18,비에 젖은 화용도의 진흙길에 조조의 패잔병이 발이 묶였다.,화용도 — 진흙길 · 일반 · 근거 연의 50회
+10,19,3백여 기만 남은 조조의 친위대가 화용도를 필사적으로 지켰다.,화용도 — 마지막 호위대 · 일반 · 근거 가상
+10,20,화용도 길목을 지키던 관우 앞에 지친 조조가 모습을 드러냈다.,화용도 — 조조 · 보스 · 근거 연의 50회·각색(연의는 싸우지 않고 놓아줌)
diff --git a/Assets/Resources/Scenario/stage_story.csv.meta b/Assets/Resources/Scenario/stage_story.csv.meta
new file mode 100644
index 00000000..6c125f05
--- /dev/null
+++ b/Assets/Resources/Scenario/stage_story.csv.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 81d5f8b013b89eb448418254d45e4e12
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Scenario/warn_edge.png b/Assets/Resources/Scenario/warn_edge.png
new file mode 100644
index 00000000..aeb70051
Binary files /dev/null and b/Assets/Resources/Scenario/warn_edge.png differ
diff --git a/Assets/Resources/Scenario/warn_edge.png.meta b/Assets/Resources/Scenario/warn_edge.png.meta
new file mode 100644
index 00000000..b2210858
--- /dev/null
+++ b/Assets/Resources/Scenario/warn_edge.png.meta
@@ -0,0 +1,181 @@
+fileFormatVersion: 2
+guid: 719eef0753f14c288ed26f1ff3c58fbd
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -166343660977832731
+ second: f000_0
+ externalObjects: {}
+ serializedVersion: 13
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ flipGreenChannel: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ vTOnly: 0
+ ignoreMipmapLimit: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: 0
+ wrapU: 1
+ wrapV: 1
+ wrapW: 1
+ nPOTScale: 0
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 1
+ spriteExtrude: 1
+ spriteMeshType: 0
+ alignment: 9
+ spritePivot: {x: 0.50000, y: 0.50000}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 8
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ swizzle: 50462976
+ cookieLightType: 0
+ platformSettings:
+ - serializedVersion: 4
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: Android
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: WebGL
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ - serializedVersion: 4
+ buildTarget: iOS
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 0
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ ignorePlatformSupport: 0
+ androidETC2FallbackOverride: 0
+ forceMaximumCompressionQuality_BC6H_BC7: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: f000_0
+ rect:
+ serializedVersion: 2
+ x: 19
+ y: 19
+ width: 898
+ height: 820
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 77d9d37c867d4c55926fb7bb69c19fbc
+ internalID: -166343660977832731
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 81270df211b64dfbb081b1b0e483f8ce
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Editor/ScenarioCapture.cs b/Assets/Scripts/Editor/ScenarioCapture.cs
new file mode 100644
index 00000000..a9e75c52
--- /dev/null
+++ b/Assets/Scripts/Editor/ScenarioCapture.cs
@@ -0,0 +1,41 @@
+using System.IO;
+using TKS.OutGame;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine;
+
+namespace TKS.EditorTools
+{
+ ///
+ /// 시나리오 이벤트(전장 설명 · 보스 등장 연출) 검증 캡처 — 2026-11-12 개발 요청서 C1·C2.
+ /// Unity.exe -projectPath <proj> -force-d3d11 -executeMethod TKS.EditorTools.ScenarioCapture.Run -scDir <dir>
+ /// [-scPopups 1-1,1-10] [-scStages 1-10,5-10,10-20] [-scTimes 0.3,1.0,1.6,2.4,3.4,4.8]
+ /// 팝업 = 그 스테이지 팝업 1장 · 스테이지 = 보스 연출을 시각마다 1장 + 아군 차례 1장 · 끝나면 스스로 종료.
+ ///
+ public static class ScenarioCapture
+ {
+ public static void Run()
+ {
+ string dir = Arg("-scDir");
+ if (string.IsNullOrEmpty(dir)) dir = Path.Combine(Directory.GetCurrentDirectory(), "Logs", "scenario_capture");
+ DataImporter.ImportAll();
+ UIThemeImporter.Import();
+ EditorSceneManager.OpenScene(ProjectSetup.ScenePath, OpenSceneMode.Single);
+ SessionState.SetBool(SaveStore.MemoryFlagKey, true);
+ SessionState.SetString(ScenarioCaptureDriver.DirKey, dir);
+ SessionState.SetString(ScenarioCaptureDriver.PopupKey, Arg("-scPopups") ?? "1-1,1-10");
+ SessionState.SetString(ScenarioCaptureDriver.StagesKey, Arg("-scStages") ?? "1-10,5-10,10-20");
+ SessionState.SetString(ScenarioCaptureDriver.TimesKey, Arg("-scTimes") ?? "0.3,1.0,1.6,2.4,3.4,4.8");
+ Debug.Log("[TKS] 시나리오 캡처 시작 → " + dir);
+ EditorApplication.EnterPlaymode();
+ }
+
+ static string Arg(string name)
+ {
+ var args = System.Environment.GetCommandLineArgs();
+ for (int i = 0; i < args.Length - 1; i++)
+ if (args[i] == name) return args[i + 1];
+ return null;
+ }
+ }
+}
diff --git a/Assets/Scripts/Editor/ScenarioCapture.cs.meta b/Assets/Scripts/Editor/ScenarioCapture.cs.meta
new file mode 100644
index 00000000..d4fbdb63
--- /dev/null
+++ b/Assets/Scripts/Editor/ScenarioCapture.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f1bc9e1be21ee9644a9b0666e67de178
\ No newline at end of file
diff --git a/Assets/Scripts/OutGame/ScenarioCaptureDriver.cs b/Assets/Scripts/OutGame/ScenarioCaptureDriver.cs
new file mode 100644
index 00000000..460d2d41
--- /dev/null
+++ b/Assets/Scripts/OutGame/ScenarioCaptureDriver.cs
@@ -0,0 +1,136 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+
+namespace TKS.OutGame
+{
+ ///
+ /// 시나리오 이벤트 검증 캡처(2026-11-12 · 개발 요청서 C1·C2) — 에디터 `TKS.EditorTools.ScenarioCapture.Run` 이 SessionState 로 넘기면 생성.
+ /// ① 스테이지 팝업(전장 설명 칸) ② 보스 스테이지마다 등장 연출을 정해진 시각에 찍고 아군 차례가 되면 1장 더 · 세이브 = 메모리 전용 신규 유저.
+ ///
+ public class ScenarioCaptureDriver : MonoBehaviour
+ {
+ public const string DirKey = "TKS_SC_CAPTURE_DIR";
+ public const string PopupKey = "TKS_SC_CAPTURE_POPUPS";
+ public const string StagesKey = "TKS_SC_CAPTURE_STAGES";
+ public const string TimesKey = "TKS_SC_CAPTURE_TIMES";
+ const int W = 1080, H = 1920;
+
+ string dir;
+ string[] popups = new string[0], stages = new string[0];
+ float[] times = new float[0];
+ readonly List log = new List();
+
+#if UNITY_EDITOR
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
+ static void AutoSpawn()
+ {
+ string d = UnityEditor.SessionState.GetString(DirKey, "");
+ if (string.IsNullOrEmpty(d)) return;
+ UnityEditor.SessionState.EraseString(DirKey);
+ var drv = new GameObject("ScenarioCaptureDriver").AddComponent();
+ drv.dir = d;
+ drv.popups = Split(UnityEditor.SessionState.GetString(PopupKey, ""));
+ drv.stages = Split(UnityEditor.SessionState.GetString(StagesKey, ""));
+ var ts = new List();
+ foreach (var t in Split(UnityEditor.SessionState.GetString(TimesKey, "")))
+ {
+ float v;
+ if (float.TryParse(t, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out v)) ts.Add(v);
+ }
+ drv.times = ts.ToArray();
+ }
+#endif
+
+ static string[] Split(string s)
+ {
+ return s.Split(new[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
+ }
+
+ static int Index(BattleManager b, string cs)
+ {
+ var p = cs.Split('-');
+ int c, s;
+ if (p.Length != 2 || !int.TryParse(p[0], out c) || !int.TryParse(p[1], out s)) return -1;
+ for (int i = 0; i < b.Config.stages.Length; i++)
+ if (b.Config.stages[i].chapter == c && b.Config.stages[i].stage == s) return i;
+ return -1;
+ }
+
+ IEnumerator Start()
+ {
+ Directory.CreateDirectory(dir);
+ yield return null;
+ yield return null;
+ var root = OutGameRoot.Instance;
+ var cam = Camera.main;
+ if (root == null || cam == null)
+ {
+ Log("FAIL: OutGameRoot 또는 카메라 없음");
+ Finish(1);
+ yield break;
+ }
+ var bm = root.Battle;
+ foreach (var cs in popups)
+ {
+ int si = Index(bm, cs.Trim());
+ if (si < 0) { Log("FAIL: 스테이지 없음 " + cs); continue; }
+ root.OpenWorldMap();
+ yield return new WaitForSecondsRealtime(0.4f);
+ root.Map.Show(bm.Config.stages[si].chapter - 1);
+ yield return new WaitForSecondsRealtime(0.3f);
+ root.Map.OpenPopup(bm.Config.stages[si].stage - 1);
+ yield return new WaitForSecondsRealtime(0.4f);
+ yield return Shot(cam, "popup_" + cs.Trim());
+ }
+ foreach (var cs in stages)
+ {
+ int si = Index(bm, cs.Trim());
+ if (si < 0) { Log("FAIL: 스테이지 없음 " + cs); continue; }
+ root.Map.EnterStage(bm.Config.stages[si].chapter - 1, bm.Config.stages[si].stage - 1);
+ float t0 = Time.realtimeSinceStartup;
+ foreach (var t in times)
+ {
+ while (Time.realtimeSinceStartup - t0 < t) yield return null;
+ yield return Shot(cam, "intro_" + cs.Trim() + "_" + t.ToString("0.0", System.Globalization.CultureInfo.InvariantCulture) + "s");
+ }
+ while (bm.Phase != BattlePhase.PlayerTurn && Time.realtimeSinceStartup - t0 < 20f) yield return null;
+ Log("intro " + cs + " → 아군 차례까지 " + (Time.realtimeSinceStartup - t0).ToString("0.00") + "초 · phase=" + bm.Phase);
+ yield return new WaitForSecondsRealtime(0.8f);
+ yield return Shot(cam, "intro_" + cs.Trim() + "_end");
+ bm.GoIdle();
+ root.OpenWorldMap();
+ yield return new WaitForSecondsRealtime(0.5f);
+ }
+ Log("scenario errors=" + ScenarioData.Errors.Count);
+ foreach (var e in ScenarioData.Errors) Log(" " + e);
+ Finish(0);
+ }
+
+ IEnumerator Shot(Camera cam, string name)
+ {
+ string file = Path.Combine(dir, name + ".png");
+ yield return CaptureUtil.Capture(cam, W, H, file);
+ Log("shot " + file);
+ }
+
+ void Log(string s)
+ {
+ log.Add(s);
+ Debug.Log("[TKS-SC] " + s);
+ try { File.WriteAllLines(Path.Combine(dir, "scenario_capture_log.txt"), log.ToArray()); }
+ catch { }
+ }
+
+ void Finish(int code)
+ {
+ Log("finish code=" + code);
+#if UNITY_EDITOR
+ UnityEditor.EditorApplication.Exit(code);
+#else
+ Application.Quit(code);
+#endif
+ }
+ }
+}
diff --git a/Assets/Scripts/OutGame/ScenarioCaptureDriver.cs.meta b/Assets/Scripts/OutGame/ScenarioCaptureDriver.cs.meta
new file mode 100644
index 00000000..53971efe
--- /dev/null
+++ b/Assets/Scripts/OutGame/ScenarioCaptureDriver.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 6f660212e4e21244a91bef91ba5d8a19
\ No newline at end of file
diff --git a/Assets/Scripts/OutGame/UI/OutGameRoot.cs b/Assets/Scripts/OutGame/UI/OutGameRoot.cs
index 434ce1e3..a2bf6926 100644
--- a/Assets/Scripts/OutGame/UI/OutGameRoot.cs
+++ b/Assets/Scripts/OutGame/UI/OutGameRoot.cs
@@ -183,6 +183,11 @@ namespace TKS.OutGame
// 전투 연결: 출전 = 편성 프리셋 · 결과 = 보상
b.LineupProvider = Session.BuildLineup;
b.StageStarted += () => resultDone = false;
+ b.StageClearedProvider = (c, st) => // 보스 등장 연출 다시 출정 축약(2026-11-12 시나리오 이벤트 C2)
+ {
+ var rec = Session.Save.Stage(c, st, false);
+ return rec != null && rec.clears > 0;
+ };
b.PhaseChanged += OnPhase;
// 보물 crit·range·splash = 아군 진영 상시 효과(SkillMods) · 전투 이벤트 카운터(PD #1093 C)
b.SideEffectsProvider = f => f == Faction.Player ? TreasureRules.BattleEffects(Session.Db, Session.Save) : null;
@@ -799,8 +804,24 @@ namespace TKS.OutGame
if (!string.IsNullOrEmpty(s.place))
UiKit.Label(field, s.place + (string.IsNullOrEmpty(s.bgTheme) ? "" : " · " + s.bgTheme), 26, soft, TextAnchor.MiddleCenter, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(Pad, -76f), new Vector2(W - Pad * 2f, 34f), false);
- // 적 구성 = 병종 원(type 색 Circle78 68 + 병종 아이콘 40) + 「×n」 · 가운데 정렬
+ // 전장 설명(2026-11-12 시나리오 이벤트 C1 · Resources/Scenario/stage_story.csv) — 장소 줄 아래 · 짙은 칸 + 금색 테두리 · 2줄 이내 · 잠긴 판·다시 출정에도
float y = 124f;
+ string desc = ScenarioData.Desc(s.chapter, s.stage);
+ if (!string.IsNullOrEmpty(desc))
+ {
+ const float DescH = 84f;
+ var box = UiKit.Rect("Desc", field, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(Pad, -118f), new Vector2(W - Pad * 2f, DescH));
+ var bg = UiKit.Skin(box, "panel12", UiKit.Col("row_on_field", UiKit.Dark)); // 별 조건 행과 같은 짙은 칸
+ bg.raycastTarget = false;
+ var rim = box.gameObject.AddComponent();
+ rim.effectColor = UiKit.Col("gold", new Color(0.91f, 0.66f, 0.23f));
+ rim.effectDistance = new Vector2(2f, -2f);
+ var dt = UiKit.Label(box, desc, 26, UiKit.Col("text_cream", new Color(1f, 0.95f, 0.84f)), TextAnchor.MiddleCenter, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(18f, -4f), new Vector2(W - Pad * 2f - 36f, DescH - 8f), false);
+ dt.horizontalOverflow = HorizontalWrapMode.Wrap;
+ y += DescH + 8f;
+ }
+
+ // 적 구성 = 병종 원(type 색 Circle78 68 + 병종 아이콘 40) + 「×n」 · 가운데 정렬
UiKit.SubTitle(field, "적 구성", Pad, y, W - Pad * 2f);
var counts = new int[UnitTypeInfo.Count];
var lead = new List();
diff --git a/Assets/Scripts/Runtime/BattleManager.cs b/Assets/Scripts/Runtime/BattleManager.cs
index 83debf4d..25582dca 100644
--- a/Assets/Scripts/Runtime/BattleManager.cs
+++ b/Assets/Scripts/Runtime/BattleManager.cs
@@ -235,6 +235,7 @@ namespace TKS
void Begin(BalanceConfig.StageDef stage)
{
StopAllCoroutines();
+ BossIntro.Abort();
ClearUnits();
Phase = BattlePhase.Setup;
sideEffects[0] = SideEffectsProvider != null ? SideEffectsProvider(Faction.Player) : null;
@@ -274,9 +275,15 @@ namespace TKS
string tip = GimmickTables.Table != null ? GimmickTables.Table.TipFor(stage.chapter, stage.stage) : "";
if (tip.Length > 0) LastMessage += " · " + tip; // 1장 튜토리얼 문구(tutorial_tips.csv · PD #1098 §3)
if (StageStarted != null) StageStarted();
- SetPhase(BattlePhase.PlayerTurn);
+ // 보스 등장 연출(2026-11-12 시나리오 이벤트 C2 · boss_intro.csv) — 연출 동안 Setup(아군 조작 잠금) → 끝나면 아군 차례 · 연무장(Mode) 전투 제외
+ bool cleared = StageClearedProvider != null && StageClearedProvider(stage.chapter, stage.stage);
+ if (Mode == null && BossIntro.Wants(stage, cleared)) BossIntro.Begin(this, stage, cleared, () => SetPhase(BattlePhase.PlayerTurn));
+ else SetPhase(BattlePhase.PlayerTurn);
}
+ /// 이미 깬 스테이지인가(장, 번호) — 보스 등장 연출의 다시 출정 축약(replay_mode) 판정 · 아웃게임 세이브가 넣는다.
+ public Func StageClearedProvider;
+
/// 결과 화면 탭 처리기(true = 승리). 있으면 다음 전투로 넘기지 않고 이 처리기(월드맵 복귀)를 부른다.
public Action ResultHandler;
@@ -284,6 +291,7 @@ namespace TKS
public void GoIdle()
{
StopAllCoroutines();
+ BossIntro.Abort();
ClearUnits();
SetPhase(BattlePhase.Setup);
}
diff --git a/Assets/Scripts/Runtime/Scenario.meta b/Assets/Scripts/Runtime/Scenario.meta
new file mode 100644
index 00000000..1f7b0fb8
--- /dev/null
+++ b/Assets/Scripts/Runtime/Scenario.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c5e2283276bfdff45af132e9f978e8ca
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Runtime/Scenario/BossIntro.cs b/Assets/Scripts/Runtime/Scenario/BossIntro.cs
new file mode 100644
index 00000000..4711bfc3
--- /dev/null
+++ b/Assets/Scripts/Runtime/Scenario/BossIntro.cs
@@ -0,0 +1,488 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace TKS
+{
+ ///
+ /// 보스 스테이지 시작 연출(2026-11-12 PD 「보스는 등장할 때 포커스 + 짤막한 대사(말풍선)」 · 「예시처럼 보스 등장 연출」 · 개발 요청서 C2).
+ /// ① 경고(위아래 검은 띠 + 붉은 가장자리 깜빡임) → ② 보스 포커스(카메라 이동·확대 · 다른 유닛 어둡게 · 발밑 붉은 원) →
+ /// ③ 컷인(위 「BOSS 등장!」 붉은 줄무늬 띠 → 보스 전신 + 아래 이름 띠) → ④ 말풍선 대사(타자 효과 · 2인 보스는 n_order 순) → ⑤ 아군 시야로 복귀.
+ /// 값 = ScenarioData.Cfg(boss_intro_config.csv) · 대사 = boss_intro.csv · 그림 = Resources/Scenario/*.png(띠·글자·말풍선 · 없으면 색 면) + 보스 유닛 그림.
+ /// 연출 동안 전투 단계 = Setup(아군 조작 잠금) · 끝나면 onDone(아군 차례). Sim.Active(적 AI 가상 실행) 중에는 아무것도 하지 않는다.
+ ///
+ public class BossIntro : MonoBehaviour
+ {
+ static BossIntro current;
+
+ BattleManager battle;
+ CameraController cc;
+ Action onDone;
+ List bosses = new List();
+ List lines;
+ bool withCutin;
+ bool skip;
+ int taps;
+ Vector3 camStart;
+ float viewStart;
+ readonly Dictionary dimmed = new Dictionary();
+ readonly List rings = new List();
+
+ RectTransform root, fx;
+ Image dim, edge, barTop, barBottom;
+ Button skipBtn;
+
+ static float C(string k)
+ {
+ return ScenarioData.Cfg(k);
+ }
+
+ /// 이 스테이지에 연출을 틀지(보스 행 있음 · 가상 실행 아님 · 다시 출정 = replay_mode 2 면 안 틂).
+ public static bool Wants(BalanceConfig.StageDef stage, bool cleared)
+ {
+ if (Sim.Active || stage == null || stage.kind != StageKind.Boss) return false;
+ if (ScenarioData.Bosses(stage.chapter, stage.stage).Count == 0) return false;
+ return !(cleared && Mathf.RoundToInt(C("replay_mode")) == 2);
+ }
+
+ /// 연출 시작 — cleared = 이미 깬 스테이지(replay_mode 1 = 컷인 빼고 ②④⑤).
+ public static void Begin(BattleManager battle, BalanceConfig.StageDef stage, bool cleared, Action onDone)
+ {
+ Abort();
+ var cc = FindFirstObjectByType();
+ if (cc == null || cc.Cam == null)
+ {
+ onDone?.Invoke();
+ return;
+ }
+ var go = new GameObject("BossIntroUI");
+ var bi = go.AddComponent();
+ current = bi;
+ bi.battle = battle;
+ bi.cc = cc;
+ bi.onDone = onDone;
+ bi.lines = ScenarioData.Bosses(stage.chapter, stage.stage);
+ bi.withCutin = !(cleared && Mathf.RoundToInt(C("replay_mode")) == 1);
+ foreach (var l in bi.lines)
+ {
+ Unit hit = null;
+ foreach (var u in battle.AliveUnits(Faction.Enemy))
+ if (u.IsBoss && u.ArtId == l.id) { hit = u; break; }
+ if (hit == null)
+ foreach (var u in battle.AliveUnits(Faction.Enemy))
+ if (u.IsBoss && !bi.bosses.Contains(u)) { hit = u; break; }
+ bi.bosses.Add(hit);
+ }
+ bi.Build();
+ bi.StartCoroutine(bi.Run());
+ }
+
+ /// 진행 중 연출을 바로 치움(전투 재시작 · 월드맵 복귀) — 어둡게·원·카메라 상태를 되돌린다.
+ public static void Abort()
+ {
+ if (current == null) return;
+ current.Restore();
+ Destroy(current.gameObject);
+ current = null;
+ }
+
+ // ---------- 화면 ----------
+
+ static Sprite Spr(string name)
+ {
+ return Resources.Load(ScenarioData.Root + name);
+ }
+
+ static RectTransform Rt(string name, Transform parent, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 pos, Vector2 size)
+ {
+ var go = new GameObject(name, typeof(RectTransform));
+ go.transform.SetParent(parent, false);
+ var rt = (RectTransform)go.transform;
+ rt.anchorMin = aMin;
+ rt.anchorMax = aMax;
+ rt.pivot = pivot;
+ rt.anchoredPosition = pos;
+ rt.sizeDelta = size;
+ return rt;
+ }
+
+ static Image Img(string name, Transform parent, Sprite sp, Color col, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 pos, Vector2 size)
+ {
+ var img = Rt(name, parent, aMin, aMax, pivot, pos, size).gameObject.AddComponent();
+ img.sprite = sp;
+ img.color = col;
+ img.raycastTarget = false;
+ return img;
+ }
+
+ static Image Full(string name, Transform parent, Sprite sp, Color col)
+ {
+ return Img(name, parent, sp, col, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero);
+ }
+
+ static Text Txt(Transform parent, string s, int size, Color col, TextAnchor anchor, Vector2 pos, Vector2 box, Font font)
+ {
+ var t = Rt("Text", parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), pos, box).gameObject.AddComponent();
+ t.font = font;
+ t.fontSize = size;
+ t.color = col;
+ t.alignment = anchor;
+ t.text = s;
+ t.supportRichText = false;
+ t.raycastTarget = false;
+ t.horizontalOverflow = HorizontalWrapMode.Wrap;
+ t.verticalOverflow = VerticalWrapMode.Overflow;
+ return t;
+ }
+
+ static void Stroke(Text t, Color col, float d)
+ {
+ var o = t.gameObject.AddComponent();
+ o.effectColor = col;
+ o.effectDistance = new Vector2(d, -d);
+ var o2 = t.gameObject.AddComponent();
+ o2.effectColor = col;
+ o2.effectDistance = new Vector2(-d, d);
+ }
+
+ void Build()
+ {
+ UiLayer.Root(gameObject, cc.Cam, 460, 0.38f, UiLayer.Reference, UiRate.Event); // 아웃게임 위 덮개(재화 바 · 450)보다 위 · 연출 동안 화면 전체를 덮음
+ root = (RectTransform)transform;
+ // 누름 받이(탭 1 = 대사 전부 · 탭 2 = 닫기) — 전체 화면 · 투명
+ var catcher = Full("Tap", root, null, new Color(0f, 0f, 0f, 0f));
+ catcher.raycastTarget = true;
+ catcher.gameObject.AddComponent