diff --git a/Assets/Data/UI/ui_theme.csv b/Assets/Data/UI/ui_theme.csv
index 4103d300..544d9f53 100644
--- a/Assets/Data/UI/ui_theme.csv
+++ b/Assets/Data/UI/ui_theme.csv
@@ -498,3 +498,16 @@ skin,btn_green,Button/Button01_s_Green.png,,1.22,,,,Secondary 녹 h100(광고
color,stage_pattern,,,,,,#FFFFFF0D,상자 탭 무대 문양(흰 5 % · 검수2 결함 4)
color,chest_select,,,,,,#FFFFFF,상자 행 선택 테두리(흰 · 금 틀과 구분 · 검수2 결함 5)
color,chest_dim,,,,,,#00000040,상자 행 비선택 어둡게(25 %)
+icon,cls_sym_infantry,Assets/UI/Symbols/cls_sym_infantry.png,,,,,,병과 단색 심볼 보병 검(PD 2026-11-09 · 납품 그림 형태 → Tools/class_symbols.py)
+icon,cls_sym_spear,Assets/UI/Symbols/cls_sym_spear.png,,,,,,병과 단색 심볼 창병 창(PD 2026-11-09 · 납품 그림 형태 → Tools/class_symbols.py)
+icon,cls_sym_cavalry,Assets/UI/Symbols/cls_sym_cavalry.png,,,,,,병과 단색 심볼 기병 말(PD 2026-11-09 · 납품 그림 형태 → Tools/class_symbols.py)
+icon,cls_sym_archer,Assets/UI/Symbols/cls_sym_archer.png,,,,,,병과 단색 심볼 궁병 활(PD 2026-11-09 · 납품 그림 형태 → Tools/class_symbols.py)
+icon,cls_sym_strategist,Assets/UI/Symbols/cls_sym_strategist.png,,,,,,병과 단색 심볼 책사 깃털부채(PD 2026-11-09 · 납품 그림 형태 → Tools/class_symbols.py)
+color,fbadge_shu,,,,,,#5DBB4E,진영 원 배지 촉 바깥(PD 2026-11-09 · 촉 녹 · 위 청 · 오 적 · 군 짙은 회색)
+color,fbadge_shu_in,,,,,,#2F8A3A,진영 원 배지 촉 안쪽
+color,fbadge_wei,,,,,,#4C8EF0,진영 원 배지 위 바깥(PD 2026-11-09 · 촉 녹 · 위 청 · 오 적 · 군 짙은 회색)
+color,fbadge_wei_in,,,,,,#2459B8,진영 원 배지 위 안쪽
+color,fbadge_wu,,,,,,#EE5A48,진영 원 배지 오 바깥(PD 2026-11-09 · 촉 녹 · 위 청 · 오 적 · 군 짙은 회색)
+color,fbadge_wu_in,,,,,,#B23324,진영 원 배지 오 안쪽
+color,fbadge_other,,,,,,#6E7280,진영 원 배지 군 바깥(PD 2026-11-09 · 촉 녹 · 위 청 · 오 적 · 군 짙은 회색)
+color,fbadge_other_in,,,,,,#3E414B,진영 원 배지 군 안쪽
diff --git a/Assets/Resources/UI/UITheme.asset b/Assets/Resources/UI/UITheme.asset
index 211c2298..198d10f6 100644
--- a/Assets/Resources/UI/UITheme.asset
+++ b/Assets/Resources/UI/UITheme.asset
@@ -577,6 +577,22 @@ MonoBehaviour:
color: {r: 1, g: 1, b: 1, a: 1}
- id: chest_dim
color: {r: 0, g: 0, b: 0, a: 0.2509804}
+ - id: fbadge_shu
+ color: {r: 0.3647059, g: 0.73333335, b: 0.30588236, a: 1}
+ - id: fbadge_shu_in
+ color: {r: 0.18431373, g: 0.5411765, b: 0.22745098, a: 1}
+ - id: fbadge_wei
+ color: {r: 0.29803923, g: 0.5568628, b: 0.9411765, a: 1}
+ - id: fbadge_wei_in
+ color: {r: 0.14117648, g: 0.34901962, b: 0.72156864, a: 1}
+ - id: fbadge_wu
+ color: {r: 0.93333334, g: 0.3529412, b: 0.28235295, a: 1}
+ - id: fbadge_wu_in
+ color: {r: 0.69803923, g: 0.2, b: 0.14117648, a: 1}
+ - id: fbadge_other
+ color: {r: 0.43137255, g: 0.44705883, b: 0.5019608, a: 1}
+ - id: fbadge_other_in
+ color: {r: 0.24313726, g: 0.25490198, b: 0.29411766, a: 1}
skins:
- id: card
pack: {fileID: 21300000, guid: 3070a6f23e6ca4273897acf1b7e8c5ce, type: 3}
@@ -1776,6 +1792,26 @@ MonoBehaviour:
pack: {fileID: 21300000, guid: 09135c198f8744fcd89493b169d11bd8, type: 3}
samguk: {fileID: 0}
tint: {r: 1, g: 1, b: 1, a: 1}
+ - id: cls_sym_infantry
+ pack: {fileID: 21300000, guid: 45255881d251469429f5a85c7d135441, type: 3}
+ samguk: {fileID: 0}
+ tint: {r: 1, g: 1, b: 1, a: 1}
+ - id: cls_sym_spear
+ pack: {fileID: 21300000, guid: 63a264aa26e829749a8114cd7e10a22f, type: 3}
+ samguk: {fileID: 0}
+ tint: {r: 1, g: 1, b: 1, a: 1}
+ - id: cls_sym_cavalry
+ pack: {fileID: 21300000, guid: 3ca6b69da9089eb4aabb4aa5fae10ecf, type: 3}
+ samguk: {fileID: 0}
+ tint: {r: 1, g: 1, b: 1, a: 1}
+ - id: cls_sym_archer
+ pack: {fileID: 21300000, guid: 9238470c5d76e8c499fd2ebf8a526054, type: 3}
+ samguk: {fileID: 0}
+ tint: {r: 1, g: 1, b: 1, a: 1}
+ - id: cls_sym_strategist
+ pack: {fileID: 21300000, guid: 63fd1be34f67f92488e14e322a34df12, type: 3}
+ samguk: {fileID: 0}
+ tint: {r: 1, g: 1, b: 1, a: 1}
- id: tile_bridge
pack: {fileID: 0}
samguk: {fileID: 21300000, guid: 8e5bf7eb1e300474785ff2781eeb5093, type: 3}
diff --git a/Assets/Scripts/Editor/UIThemeImporter.cs b/Assets/Scripts/Editor/UIThemeImporter.cs
index 406520b6..6250c9be 100644
--- a/Assets/Scripts/Editor/UIThemeImporter.cs
+++ b/Assets/Scripts/Editor/UIThemeImporter.cs
@@ -202,7 +202,7 @@ namespace TKS.EditorTools
static bool Ours(string path)
{
- return path.StartsWith(UIThemeImporter.SamgukRoot + "/") || path.StartsWith("Assets/UI/Lobby/");
+ return path.StartsWith(UIThemeImporter.SamgukRoot + "/") || path.StartsWith("Assets/UI/Lobby/") || path.StartsWith("Assets/UI/Symbols/"); // Symbols = 병과 단색 심볼(Tools/class_symbols.py · PD 2026-11-09)
}
void OnPreprocessTexture()
diff --git a/Assets/Scripts/OutGame/UI/HeroScreens.cs b/Assets/Scripts/OutGame/UI/HeroScreens.cs
index 35e85a10..c18c43c2 100644
--- a/Assets/Scripts/OutGame/UI/HeroScreens.cs
+++ b/Assets/Scripts/OutGame/UI/HeroScreens.cs
@@ -85,7 +85,7 @@ namespace TKS.OutGame
public static readonly Vector2 CellSize = new Vector2(320f, 431f);
public static readonly Vector2 Spacing = new Vector2(22f, 20f);
/// 크기 표 size_px(머리 크기 기준 표준 키)가 카드에서 차지할 px — 배율 = UnitPx ÷ size_px(모든 유닛 머리 크기 같음) · 머리 끝 위치(카드 위에서 px).
- const float UnitPx = 450f;
+ const float UnitPx = 360f; // 450 → 360 = 유닛 20 % 작게(PD 2026-11-09 「현재 비율보다 20 % 정도 작게」)
const float HeadTop = 50f;
public static Image Card(Transform content, OutGameSession s, HeroDb.Hero h, bool deployed, System.Action onTap)
@@ -122,7 +122,7 @@ namespace TKS.OutGame
}
else
{
- art = UiKit.Rect("Character", b, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -56f), new Vector2(470f, 460f)).gameObject.AddComponent();
+ art = UiKit.Rect("Character", b, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -56f), new Vector2(376f, 368f)).gameObject.AddComponent();
art.preserveAspect = true;
}
art.sprite = sp;
@@ -154,8 +154,8 @@ namespace TKS.OutGame
bt.horizontalOverflow = HorizontalWrapMode.Overflow;
}
// PD 커스터마이징(2026-11-09): 왼쪽 위 = 진영 깃발 · 그 오른쪽 = 이름(45 · 긴 이름 자동 축소) · 깃발 아래(왼쪽 가장자리) = 출전 · 오른쪽 위 = 병종 원(#35374E 58×60)
- var flag = UiKit.Icon(t, UISkin.Icon("flag_" + h.faction) != null ? "flag_" + h.faction : "flag_other", new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(44f, -42f), 66f);
- UiKit.DropShadow(flag, 3f);
+ // 진영 = 원 배지(위·촉·오·군 · PD 2026-11-09 · 구 세력 깃발 대체)
+ UiKit.DropShadow(UiKit.FactionBadge(t, h.faction, new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(44f, -42f), 62f), 3f);
var name = UiKit.Title(UiKit.Label(t, h.nameKo, 45, UiKit.White, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 0.5f), new Vector2(80f, -40.5f), new Vector2(172f, 66f)), true);
name.resizeTextForBestFit = true;
name.resizeTextMinSize = 26;
@@ -167,7 +167,7 @@ namespace TKS.OutGame
}
var role = UiKit.Skin(UiKit.Rect("Role", t, new Vector2(1f, 1f), new Vector2(0.5f, 0.5f), new Vector2(-42f, -42f), new Vector2(58f, 60f)), "dot", UiKit.Col("circle_inner", UiKit.Dark));
role.preserveAspect = true;
- if (UiKit.Icon(role.transform, UiKit.TypeIconId(h.type), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 40f) == null)
+ if (UiKit.Icon(role.transform, UiKit.TypeSymbolId(h.type), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 46f) == null) // 병과 심볼(PD 2026-11-09)
UiKit.Title(UiKit.FillLabel(role.transform, UnitTypeInfo.Mark(h.type), 28, UiKit.White), true);
if (s.CanGrowAny(h.id)) UiKit.Icon(t, "new_dot", new Vector2(0f, 0f), new Vector2(0.5f, 0.5f), new Vector2(64f, 70f), 30f); // 성장 가능 = 레벨 배지 오른쪽 위
return cell;
@@ -226,6 +226,7 @@ namespace TKS.OutGame
Text filterText;
Text countText;
int ownedCards;
+ UiAutoGrid autoGrid;
public bool ShowingSoldiers
{
@@ -255,9 +256,25 @@ namespace TKS.OutGame
var arrow = UiKit.Icon(pick, "arrow_down", new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-6f, 0f), 38f);
UiKit.DropShadow(arrow, 3f);
- var body = Body();
- float side = (OutGameRoot.Reference.x - CollectionCards.CellSize.x * 3f - CollectionCards.Spacing.x * 2f) / 2f;
- content = UiKit.ScrollGrid("List", body, side, side, 20f, 0f, CollectionCards.CellSize, CollectionCards.Spacing, 3, out scroll);
+ // 본문 = 화면 폭 전체(해상도 대응 · PD 2026-11-09) · 열 수·카드 배율 = UiAutoGrid(기준 1080 = 4열 · 좁으면 3 · 넓으면 5 이상)
+ var body = UiKit.Fill("ListBody", Rt, 0f, 0f, OutGameRoot.TopBarH + OutGameRoot.HeaderH, OutGameRoot.TabBarH);
+ content = UiKit.ScrollGrid("List", body, 24f, 24f, 20f, 0f, CollectionCards.CellSize, CollectionCards.Spacing, 4, out scroll);
+ autoGrid = content.gameObject.AddComponent();
+ autoGrid.design = CollectionCards.CellSize;
+ }
+
+ /// 열 수(해상도 대응 · 테스트·캡처).
+ public int Columns
+ {
+ get { return autoGrid != null ? autoGrid.Columns : 0; }
+ }
+
+ /// 격자 칸(holder) — 원래 크기 카드를 UiAutoGrid 배율로 넣는다.
+ Transform Slot()
+ {
+ var go = new GameObject("Slot", typeof(RectTransform));
+ go.transform.SetParent(content, false);
+ return go.transform;
}
public void SetFilter(bool soldier)
@@ -284,14 +301,15 @@ namespace TKS.OutGame
foreach (var h in owned)
{
var id = h.id;
- CollectionCards.Card(content, S, h, S.InActivePreset(id), () => Root.ShowHero(id));
+ CollectionCards.CardIn(Slot(), S, h, S.InActivePreset(id), () => Root.ShowHero(id), autoGrid.Scale);
ownedCards++;
}
int total = 0;
foreach (var h in S.Db.Heroes.heroes)
if (h.isSoldier == soldiers) total++;
- for (int i = owned.Count; i < total; i++) CollectionCards.Empty(content);
+ for (int i = owned.Count; i < total; i++) CollectionCards.EmptyIn(Slot(), autoGrid.Scale);
countText.text = owned.Count + "/" + total;
+ autoGrid.Apply();
}
/// 보유 카드 수(빈 카드 제외).
diff --git a/Assets/Scripts/OutGame/UI/UiAutoGrid.cs b/Assets/Scripts/OutGame/UI/UiAutoGrid.cs
new file mode 100644
index 00000000..bfe2a955
--- /dev/null
+++ b/Assets/Scripts/OutGame/UI/UiAutoGrid.cs
@@ -0,0 +1,58 @@
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace TKS.OutGame
+{
+ ///
+ /// 해상도 대응 카드 격자(PD 2026-11-09 「한 줄 최대 4명 · 가로가 길면 4명 이상 · 좁으면 3명 · 자동 리사이징」) —
+ /// 폭에 맞춰 열 수 = round((폭 + 간격) ÷ (목표 칸 폭 + 간격)) · 최소 minColumns · 칸 폭 = 폭을 열 수로 나눔(세로 = 원래 비율) ·
+ /// 각 칸(holder)의 첫 자식 = 원래 크기(design) 카드 → 배율 Scale 로 맞춤. 기준 1080 폭(좌우 24) = 4열.
+ ///
+ [RequireComponent(typeof(GridLayoutGroup))]
+ public class UiAutoGrid : MonoBehaviour
+ {
+ public Vector2 design = new Vector2(320f, 431f);
+ public float targetWidth = 246f;
+ public float gap = 16f;
+ public int minColumns = 3;
+
+ GridLayoutGroup grid;
+ bool busy;
+
+ public float Scale { get; private set; }
+ public int Columns { get; private set; }
+
+ void Awake()
+ {
+ grid = GetComponent();
+ if (Scale <= 0f) Scale = targetWidth / design.x;
+ }
+
+ void OnRectTransformDimensionsChange()
+ {
+ Apply();
+ }
+
+ /// 지금 폭으로 열 수·칸 크기·카드 배율을 다시 계산(칸을 새로 넣은 뒤에도 부른다).
+ public void Apply()
+ {
+ if (busy) return;
+ if (grid == null) Awake();
+ var rt = (RectTransform)transform;
+ float w = rt.rect.width - grid.padding.left - grid.padding.right;
+ if (w <= 1f) return;
+ busy = true;
+ int cols = Mathf.Max(minColumns, Mathf.RoundToInt((w + gap) / (targetWidth + gap)));
+ float cw = (w - (cols - 1) * gap) / cols;
+ Scale = cw / design.x;
+ Columns = cols;
+ var cell = new Vector2(cw, design.y * Scale);
+ if (grid.cellSize != cell) grid.cellSize = cell;
+ if (grid.spacing != new Vector2(gap, gap)) grid.spacing = new Vector2(gap, gap);
+ if (grid.constraintCount != cols) grid.constraintCount = cols;
+ foreach (Transform c in transform)
+ if (c.childCount > 0) c.GetChild(0).localScale = new Vector3(Scale, Scale, 1f);
+ busy = false;
+ }
+ }
+}
diff --git a/Assets/Scripts/OutGame/UI/UiAutoGrid.cs.meta b/Assets/Scripts/OutGame/UI/UiAutoGrid.cs.meta
new file mode 100644
index 00000000..393165c7
--- /dev/null
+++ b/Assets/Scripts/OutGame/UI/UiAutoGrid.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 489991b2f3bb99e4ba6e6bc028da049f
\ No newline at end of file
diff --git a/Assets/Scripts/OutGame/UI/UiKit.cs b/Assets/Scripts/OutGame/UI/UiKit.cs
index cfa2052c..86707ffe 100644
--- a/Assets/Scripts/OutGame/UI/UiKit.cs
+++ b/Assets/Scripts/OutGame/UI/UiKit.cs
@@ -411,6 +411,41 @@ namespace TKS.OutGame
return t;
}
+ /// 병과 단색 심볼 id(PD 2026-11-09 · 말 · 검 · 활 · 창 · 깃털부채) — 없으면 기존 병과 메달 아이콘.
+ public static string TypeSymbolId(UnitType t)
+ {
+ string id = "cls_sym_" + TypeKey(t);
+ return UISkin.Icon(id) != null ? id : TypeIconId(t);
+ }
+
+ /// 진영 글자(위 · 촉 · 오 · 군) · 키 = heroes.csv faction(shu · wei · wu · other).
+ public static string FactionKo(string f)
+ {
+ switch (f)
+ {
+ case "shu": return "촉";
+ case "wei": return "위";
+ case "wu": return "오";
+ }
+ return "군";
+ }
+
+ /// 진영 원 배지(PD 2026-11-09 「원형 프레임에 위·촉·오·군 · 촉 녹 · 위 청 · 오 적 · 군 짙은 회색」) = 원 틀(fbadge_*) + 안쪽 원(fbadge_*_in) + 흰 글자.
+ public static Image FactionBadge(Transform p, string faction, Vector2 anchor, Vector2 pivot, Vector2 pos, float d)
+ {
+ string f = faction == "shu" || faction == "wei" || faction == "wu" ? faction : "other";
+ var ring = Skin(Rect("Faction", p, anchor, pivot, pos, new Vector2(d, d)), "circle_frame", Col("fbadge_" + f, Dark));
+ ring.preserveAspect = true;
+ var inner = Rect("In", ring.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(d * 0.72f, d * 0.72f)).gameObject.AddComponent();
+ inner.sprite = Circle;
+ inner.color = Col("fbadge_" + f + "_in", Dark);
+ inner.raycastTarget = false;
+ var t = Title(FillLabel(ring.transform, FactionKo(f), Mathf.RoundToInt(d * 0.48f), White), true);
+ t.rectTransform.offsetMin = new Vector2(0f, d * 0.03f);
+ t.horizontalOverflow = HorizontalWrapMode.Overflow;
+ return ring;
+ }
+
/// 아이콘(테마 id · 없으면 null).
public static Image Icon(Transform parent, string id, Vector2 anchor, Vector2 pivot, Vector2 pos, float size)
{
diff --git a/Assets/Scripts/OutGame/UICaptureDriver.cs b/Assets/Scripts/OutGame/UICaptureDriver.cs
index e8706877..ef9d8625 100644
--- a/Assets/Scripts/OutGame/UICaptureDriver.cs
+++ b/Assets/Scripts/OutGame/UICaptureDriver.cs
@@ -78,8 +78,24 @@ namespace TKS.OutGame
if (sid == id || sh == null || shs == null || sh.gear.Count == 0) continue;
shs.grade = sh.gear[Mathf.Min(gi++, sh.gear.Count - 1)].grade;
}
+ // 진영 원 배지 확인용(메모리 세이브만 · PD 2026-11-09): 위 · 오 · 군 영웅 1명씩 보유 추가
+ foreach (var fac in new[] { "wei", "wu", "other" })
+ foreach (var fh in db.Heroes.heroes)
+ if (!fh.isSoldier && fh.faction == fac && !d.Owns(fh.id))
+ {
+ HeroRules.Grant(db, d, fh, HeroRules.GearSlotCount(db));
+ break;
+ }
root.Show(root.HeroList);
yield return Shot(cam, "hero_list", W, H);
+ Log("hero_list cols=" + root.HeroList.Columns);
+ // 해상도 대응(PD 2026-11-09): 넓은 화면(3:4) · 좁은 화면(9:20)
+ yield return Shot(cam, "hero_list_1536x2048", W2, H2);
+ Log("hero_list_1536x2048 cols=" + root.HeroList.Columns);
+ yield return Shot(cam, "hero_list_1080x2400", 1080, 2400);
+ Log("hero_list_1080x2400 cols=" + root.HeroList.Columns);
+ yield return Shot(cam, "hero_list_1080x2520", 1080, 2520);
+ Log("hero_list_1080x2520 cols=" + root.HeroList.Columns);
root.ShowHero(id);
yield return Shot(cam, "hero_detail", W, H);
// 영웅 상세 등급 변형(UI 상업용 재설계 ① · 목업 hero_detail_5등급 대조 · 메모리 세이브만) = 그 영웅 장비 세트의 등급 순서대로
diff --git a/Assets/UI/Symbols.meta b/Assets/UI/Symbols.meta
new file mode 100644
index 00000000..ea87d826
--- /dev/null
+++ b/Assets/UI/Symbols.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: abcec5e654e973d49a8e4be2b67eb6fe
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/UI/Symbols/cls_sym_archer.png b/Assets/UI/Symbols/cls_sym_archer.png
new file mode 100644
index 00000000..f5b6d71d
Binary files /dev/null and b/Assets/UI/Symbols/cls_sym_archer.png differ
diff --git a/Assets/UI/Symbols/cls_sym_archer.png.meta b/Assets/UI/Symbols/cls_sym_archer.png.meta
new file mode 100644
index 00000000..ddaf4ed6
--- /dev/null
+++ b/Assets/UI/Symbols/cls_sym_archer.png.meta
@@ -0,0 +1,168 @@
+fileFormatVersion: 2
+guid: 9238470c5d76e8c499fd2ebf8a526054
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 3906269742430731014
+ second: cls_sym_archer_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: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ 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: 1024
+ 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: 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
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: cls_sym_archer_0
+ rect:
+ serializedVersion: 2
+ x: 20
+ y: 13
+ width: 215
+ height: 230
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 60bb07a62abd53630800000000000000
+ internalID: 3906269742430731014
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/UI/Symbols/cls_sym_cavalry.png b/Assets/UI/Symbols/cls_sym_cavalry.png
new file mode 100644
index 00000000..4c96e8d0
Binary files /dev/null and b/Assets/UI/Symbols/cls_sym_cavalry.png differ
diff --git a/Assets/UI/Symbols/cls_sym_cavalry.png.meta b/Assets/UI/Symbols/cls_sym_cavalry.png.meta
new file mode 100644
index 00000000..0f30e18e
--- /dev/null
+++ b/Assets/UI/Symbols/cls_sym_cavalry.png.meta
@@ -0,0 +1,168 @@
+fileFormatVersion: 2
+guid: 3ca6b69da9089eb4aabb4aa5fae10ecf
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 9171839899375206819
+ second: cls_sym_cavalry_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: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ 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: 1024
+ 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: 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
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: cls_sym_cavalry_0
+ rect:
+ serializedVersion: 2
+ x: 13
+ y: 13
+ width: 230
+ height: 230
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 3a183034bcbe84f70800000000000000
+ internalID: 9171839899375206819
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/UI/Symbols/cls_sym_infantry.png b/Assets/UI/Symbols/cls_sym_infantry.png
new file mode 100644
index 00000000..02449bfe
Binary files /dev/null and b/Assets/UI/Symbols/cls_sym_infantry.png differ
diff --git a/Assets/UI/Symbols/cls_sym_infantry.png.meta b/Assets/UI/Symbols/cls_sym_infantry.png.meta
new file mode 100644
index 00000000..986c0e27
--- /dev/null
+++ b/Assets/UI/Symbols/cls_sym_infantry.png.meta
@@ -0,0 +1,168 @@
+fileFormatVersion: 2
+guid: 45255881d251469429f5a85c7d135441
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 7957124930109909397
+ second: cls_sym_infantry_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: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ 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: 1024
+ 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: 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
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: cls_sym_infantry_0
+ rect:
+ serializedVersion: 2
+ x: 28
+ y: 13
+ width: 199
+ height: 230
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 5992b9c17f26d6e60800000000000000
+ internalID: 7957124930109909397
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/UI/Symbols/cls_sym_spear.png b/Assets/UI/Symbols/cls_sym_spear.png
new file mode 100644
index 00000000..dc40b226
Binary files /dev/null and b/Assets/UI/Symbols/cls_sym_spear.png differ
diff --git a/Assets/UI/Symbols/cls_sym_spear.png.meta b/Assets/UI/Symbols/cls_sym_spear.png.meta
new file mode 100644
index 00000000..3c35fc7d
--- /dev/null
+++ b/Assets/UI/Symbols/cls_sym_spear.png.meta
@@ -0,0 +1,168 @@
+fileFormatVersion: 2
+guid: 63a264aa26e829749a8114cd7e10a22f
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: -4254521251010258662
+ second: cls_sym_spear_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: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ 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: 1024
+ 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: 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
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: cls_sym_spear_0
+ rect:
+ serializedVersion: 2
+ x: 32
+ y: 13
+ width: 192
+ height: 230
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: a19de20b677e4f4c0800000000000000
+ internalID: -4254521251010258662
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/UI/Symbols/cls_sym_strategist.png b/Assets/UI/Symbols/cls_sym_strategist.png
new file mode 100644
index 00000000..7eb659be
Binary files /dev/null and b/Assets/UI/Symbols/cls_sym_strategist.png differ
diff --git a/Assets/UI/Symbols/cls_sym_strategist.png.meta b/Assets/UI/Symbols/cls_sym_strategist.png.meta
new file mode 100644
index 00000000..9312b5c4
--- /dev/null
+++ b/Assets/UI/Symbols/cls_sym_strategist.png.meta
@@ -0,0 +1,168 @@
+fileFormatVersion: 2
+guid: 63fd1be34f67f92488e14e322a34df12
+TextureImporter:
+ internalIDToNameTable:
+ - first:
+ 213: 3818167502476526420
+ second: cls_sym_strategist_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: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ 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: 1024
+ 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: 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
+ spriteSheet:
+ serializedVersion: 2
+ sprites:
+ - serializedVersion: 2
+ name: cls_sym_strategist_0
+ rect:
+ serializedVersion: 2
+ x: 13
+ y: 13
+ width: 230
+ height: 230
+ alignment: 0
+ pivot: {x: 0, y: 0}
+ border: {x: 0, y: 0, z: 0, w: 0}
+ customData:
+ outline: []
+ physicsShape: []
+ tessellationDetail: -1
+ bones: []
+ spriteID: 453cd0e2d1bdcf430800000000000000
+ internalID: 3818167502476526420
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ outline: []
+ customData:
+ physicsShape: []
+ bones: []
+ spriteID: 5e97eb03825dee720800000000000000
+ internalID: 0
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ secondaryTextures: []
+ spriteCustomMetadata:
+ entries: []
+ nameFileIdTable: {}
+ mipmapLimitGroupName:
+ pSDRemoveMatte: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Tools/class_symbols.py b/Tools/class_symbols.py
new file mode 100644
index 00000000..c66b727d
--- /dev/null
+++ b/Tools/class_symbols.py
@@ -0,0 +1,84 @@
+"""병과 단색 심볼 만들기(PD 2026-11-09 「병과 표시 = 기병 말 · 보병 검 · 궁병 활 · 창병 창 · 책사 깃털부채 심볼 · 예시 = 어두운 원 위 베이지 말머리」).
+
+새로 그리지 않는다 — 확정 납품 메달 아이콘(Assets/UI/Samguk/class/cls_<병과>.png)을 만들 때 쓴 투명 바탕 사물 그림
+(아트 R&D `C:/ArtRnD/samguk_ui/_work/class_symbol/rgba/cls_<병과>_s21A_rgba.png` · picked_auto.json = seed 21)의 투명도 = 형태.
+형태를 채움색으로 칠하고, 원본의 진한 안쪽 선(눈 · 칼날 경계 등)만 선 색으로 남긴 뒤 바깥 테두리를 두른다.
+실행: -I -B Tools/class_symbols.py [--src ] [--fill #RRGGBB] [--line #RRGGBB] [--out Assets/UI/Symbols] [--preview ]
+출력 = /cls_sym_<병과>.png(256 정사각 · 투명) · --preview = 어두운 원 위 5종 확인 그림.
+"""
+import argparse
+import os
+
+import numpy as np
+from PIL import Image, ImageDraw, ImageFilter
+
+TYPES = ["infantry", "spear", "cavalry", "archer", "strategist"]
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+SRC = "C:/ArtRnD/samguk_ui/_work/class_symbol/rgba"
+
+
+def hexrgb(s):
+ s = s.lstrip("#")
+ return tuple(int(s[i:i + 2], 16) for i in (0, 2, 4))
+
+
+def symbol(path, fill, line, size=256, pad=14, stroke=8, inner_lum=45, erode_passes=6):
+ src = Image.open(path).convert("RGBA")
+ bb = src.getchannel("A").point(lambda v: 255 if v > 40 else 0).getbbox()
+ src = src.crop(bb)
+ # 안쪽 선 = 원본 해상도에서 형태 안쪽(바깥 외곽선 두께 ≈ 30 px 보다 깊이)의 진한 픽셀 — 눈 · 갈기 · 칼날 경계 등
+ core = src.getchannel("A").point(lambda v: 255 if v > 128 else 0)
+ for _ in range(erode_passes):
+ core = core.filter(ImageFilter.MinFilter(11))
+ rgb = np.asarray(src.convert("RGB")).astype(np.float32)
+ lum = rgb[:, :, 0] * 0.299 + rgb[:, :, 1] * 0.587 + rgb[:, :, 2] * 0.114
+ inner = Image.fromarray((((np.asarray(core) > 127) & (lum < inner_lum)) * 255).astype(np.uint8))
+ s = (size - 2 * pad - 2 * stroke) / max(src.size)
+ dim = (max(1, round(src.width * s)), max(1, round(src.height * s)))
+ alpha = src.getchannel("A").resize(dim, Image.LANCZOS)
+ inner = inner.resize(dim, Image.LANCZOS)
+ canvas = Image.new("L", (size, size), 0)
+ off = ((size - dim[0]) // 2, (size - dim[1]) // 2)
+ canvas.paste(alpha, off)
+ lines = Image.new("L", (size, size), 0)
+ lines.paste(inner, off)
+ out = Image.new("RGBA", (size, size), line + (0,))
+ out.putalpha(canvas.filter(ImageFilter.MaxFilter(stroke * 2 + 1))) # 바깥 테두리
+ body = Image.new("RGBA", (size, size), fill + (255,))
+ body.putalpha(canvas)
+ out.alpha_composite(body)
+ ink = Image.new("RGBA", (size, size), line + (255,))
+ ink.putalpha(lines)
+ out.alpha_composite(ink)
+ return out
+
+
+def main():
+ ap = argparse.ArgumentParser()
+ ap.add_argument("--src", default=SRC)
+ ap.add_argument("--seed", default="s21")
+ ap.add_argument("--fill", default="#F2D49B")
+ ap.add_argument("--line", default="#2A2230")
+ ap.add_argument("--out", default="Assets/UI/Symbols")
+ ap.add_argument("--preview", default="")
+ a = ap.parse_args()
+ out = os.path.join(ROOT, a.out)
+ os.makedirs(out, exist_ok=True)
+ tiles = []
+ for t in TYPES:
+ g = symbol(os.path.join(a.src, "cls_%s_%sA_rgba.png" % (t, a.seed)), hexrgb(a.fill), hexrgb(a.line))
+ g.save(os.path.join(out, "cls_sym_%s.png" % t))
+ tile = Image.new("RGBA", (300, 300), (0, 0, 0, 0))
+ ImageDraw.Draw(tile).ellipse((10, 10, 290, 290), fill=(53, 55, 78, 255), outline=(20, 20, 30, 255), width=8)
+ tile.alpha_composite(g.resize((200, 200), Image.LANCZOS), (50, 50))
+ tiles.append(tile)
+ if a.preview:
+ prev = Image.new("RGBA", (300 * len(tiles), 300), (40, 42, 60, 255))
+ for i, t in enumerate(tiles):
+ prev.alpha_composite(t, (i * 300, 0))
+ prev.save(a.preview)
+ print("ok ->", out)
+
+
+if __name__ == "__main__":
+ main()