보물 · 연무장 · 내정(순찰) · 전투 HUD 비주얼 개선 = Fable 제안서 §4-5~§4-8 구현(#1104 · PD 2026-11-09)
- 보물: 목록 바탕 · 서브탭 · 보유 칸 = 보물 아이콘(납품 tre_* 없으면 기본 스탯별 팩 임시 tre_stat_* · 미보유 흰 25 % 실루엣) + 이름 띠 CardFrame01_Bottom · 등급 범례 칩 Round10 · 효과 줄 칩 상자 탭 = 포인트 띠 BannerFrame05 + 가는 주황 바 + 보상 상자 · 상자 카드 CardFrame03(상자 색 + 안쪽 + 광택) + 상자 300 + 뒤 금빛 · 등급 칩 + % 한 줄 · 화살표 아이콘 · 열기 Primary 노랑 + 보유 칩(없으면 회색) · 상자 행 ItemFrame 150 + 수량 칩 + 선택 FocusLine 깜빡 상자 색 = 코드 상수(ChestColor) → 테마 chest_<id> · 칸 색 chest_<id>_bg/deco/light/glow(C45) - 연무장: 목록 바탕 · 카드 = 일러 자리(픽토그램 256 흰 25 % · 임시) + 요약 한 줄 + 어두운 판 칩 2줄(입장 아이콘 + 값 · 보상 칸 76) + 상태 칩 · 규칙 문장 → ⓘ 팝업 · 적장 토벌 「이벤트」 뱃지 - 내정 순찰: 목록 바탕 · 서브탭 · 섹션 「순찰」(레벨형 게이지 군량색 + 배지 「7h」) · 「시간당 수확」 스탯 칸 4(아이콘 64 · 값 44 Sen) · 「쌓인 보상」 타일 4 + 수량 칩 · 수확 Primary 녹 · 광고 2배 Secondary 하늘 + 횟수 · 즉시 Secondary 보라 + 보옥 비용 - 전투 HUD: 유닛 판(초상 원 마스크 + 이름 · 병종 원 · 체력 바 색 단계 · 공/방 칩 · 슬링/사거리 칩 · 상태) · 수 칩 = 아군/적 아이콘 + 숫자 · 스킬 사용 가능 = 뒤 금빛 호흡 · 기본 조작 문장 삭제(상황 안내 유지) - 공통: Sen 에 「×」 글리프가 없어 수량은 「x」 · 회색 버튼 글자 흰 외곽선 · 금빛 틴트 α 1(Glow_Circle01 가운데 α 0.5 실측) - 테스트 117/117 · console error 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ca8b4cc5e0
commit
4f22c4e091
|
|
@ -429,7 +429,7 @@ skin,btn_s_gray,Button/Button01_s_Gray.png,,2.1,,,,Secondary 회색 h56(비활
|
||||||
color,row_label_strip,,,,,,#FFFFFF0A,편성 라벨 칸 세로 띠(흰 4 %)
|
color,row_label_strip,,,,,,#FFFFFF0A,편성 라벨 칸 세로 띠(흰 4 %)
|
||||||
font,title,Assets/UI/GUIPro/ResourcesData/Fonts/Sen-ExtraBold.ttf,,,,,,제목·숫자(라틴 Sen · 한글 = 폴백 Malgun Gothic · PD 결정 전)
|
font,title,Assets/UI/GUIPro/ResourcesData/Fonts/Sen-ExtraBold.ttf,,,,,,제목·숫자(라틴 Sen · 한글 = 폴백 Malgun Gothic · PD 결정 전)
|
||||||
color,text_on_yellow,,,,,,#1E1E2A,노랑 Primary 위 글자(Fable §5-8)
|
color,text_on_yellow,,,,,,#1E1E2A,노랑 Primary 위 글자(Fable §5-8)
|
||||||
color,ribbon_glow,,,,,,#F3B72EB3,결과 리본 뒤 금빛(α 0.7 · Fable §4-2 α 0.35 는 어두운 덮개 위에서 안 보여 올림)
|
color,ribbon_glow,,,,,,#FFD24AFF,결과 리본 뒤 금빛(그림 자체가 가운데 α 0.5 라 틴트 α 1 · Fable §4-2 α 0.35 는 안 보임 실측)
|
||||||
color,row_on_field,,,,,,#3F4262,필드 위 행 판(필드보다 밝게 · 팝업 교환 행)
|
color,row_on_field,,,,,,#3F4262,필드 위 행 판(필드보다 밝게 · 팝업 교환 행)
|
||||||
skin,btn_l_yellow,Button/Button01_l_Yellow.png,,1.3,,,,Primary 노랑 h110(확인·10연·열기 · Fable §5-5)
|
skin,btn_l_yellow,Button/Button01_l_Yellow.png,,1.3,,,,Primary 노랑 h110(확인·10연·열기 · Fable §5-5)
|
||||||
skin,btn_l_red,Button/Button01_l_White_Bg.png,Button/Button01_l_White_Light1.png,1.35,5;5;5;18,0.35,,Primary 붉은 h104(출정 · 틴트 red)
|
skin,btn_l_red,Button/Button01_l_White_Bg.png,Button/Button01_l_White_Light1.png,1.35,5;5;5;18,0.35,,Primary 붉은 h104(출정 · 틴트 red)
|
||||||
|
|
@ -473,9 +473,9 @@ skin,card3_inner,Frame/CardFrame03_n_InnerBg.png,,1,,,,상자 카드 안쪽
|
||||||
skin,card3_light,Frame/CardFrame03_n_Light.png,,1,,,,상자 카드 광택
|
skin,card3_light,Frame/CardFrame03_n_Light.png,,1,,,,상자 카드 광택
|
||||||
color,card3_inner,,,,,,#00000040,상자 카드 안쪽(검정 25 %)
|
color,card3_inner,,,,,,#00000040,상자 카드 안쪽(검정 25 %)
|
||||||
color,card3_light,,,,,,#FFFFFF80,상자 카드 광택(흰 50 %)
|
color,card3_light,,,,,,#FFFFFF80,상자 카드 광택(흰 50 %)
|
||||||
color,chest_glow,,,,,,#F3B72E73,상자 뒤 빛(α 0.45)
|
color,chest_glow,,,,,,#FFD24AE6,상자 뒤 빛(그림 가운데 α 0.5 × 0.9)
|
||||||
skin,banner_point,Frame/BannerFrame05_Single.png,,3,,,,상자 포인트 띠(h90 · 장식 비율 유지)
|
skin,banner_point,Frame/BannerFrame05_Single.png,,3,,,,상자 포인트 띠(h90 · 장식 비율 유지)
|
||||||
color,banner_point,,,,,,#2C2F4A,상자 포인트 띠 틴트
|
color,banner_point,,,,,,#FFFFFF,상자 포인트 띠(그림 원색 · 왼쪽 어두운 칸 + 사선)
|
||||||
skin,bar4_bg,Slider/Slider_Basic04_Bg.png,,1.5,,,,가는 진행 바 바탕
|
skin,bar4_bg,Slider/Slider_Basic04_Bg.png,,1.5,,,,가는 진행 바 바탕
|
||||||
skin,bar4_fill,Slider/Slider_Basic04_Fill_Orange.png,,1.5,,,,가는 진행 바 채움
|
skin,bar4_fill,Slider/Slider_Basic04_Fill_Orange.png,,1.5,,,,가는 진행 바 채움
|
||||||
icon,tre_stat_hp,Icon_ItemIcons/128/ItemIcon_Heart_Red.Png,,,,,,보물 임시 아이콘 체력(최종 = 보물 그림 N3)
|
icon,tre_stat_hp,Icon_ItemIcons/128/ItemIcon_Heart_Red.Png,,,,,,보물 임시 아이콘 체력(최종 = 보물 그림 N3)
|
||||||
|
|
@ -484,3 +484,12 @@ icon,tre_stat_def,Icon_ItemIcons/128/ItemIcon_Gear_Armor_Top.Png,,,,,,보물 임
|
||||||
icon,tre_stat_crit,Icon_ItemIcons/128/ItemIcon_Damage.Png,,,,,,보물 임시 아이콘 치명
|
icon,tre_stat_crit,Icon_ItemIcons/128/ItemIcon_Damage.Png,,,,,,보물 임시 아이콘 치명
|
||||||
icon,tre_stat_range,Icon_ItemIcons/128/ItemIcon_Gear_Boots.Png,,,,,,보물 임시 아이콘 사거리
|
icon,tre_stat_range,Icon_ItemIcons/128/ItemIcon_Gear_Boots.Png,,,,,,보물 임시 아이콘 사거리
|
||||||
icon,tre_stat_splash,Icon_ItemIcons/128/ItemIcon_Battle.Png,,,,,,보물 임시 아이콘 광역
|
icon,tre_stat_splash,Icon_ItemIcons/128/ItemIcon_Battle.Png,,,,,,보물 임시 아이콘 광역
|
||||||
|
icon,arena_art_0,Icon_PictoIcons/256/PictoIcon_Castle.Png,,,,,,연무장 카드 일러 자리 탑(임시 · 일러 N4)
|
||||||
|
icon,arena_art_1,Icon_PictoIcons/256/PictoIcon_Chest.Png,,,,,,연무장 카드 일러 자리 던전(임시)
|
||||||
|
icon,arena_art_2,Icon_PictoIcons/256/PictoIcon_Battle.Png,,,,,,연무장 카드 일러 자리 투기장(임시)
|
||||||
|
icon,arena_art_3,Icon_PictoIcons/256/PictoIcon_Boss.Png,,,,,,연무장 카드 일러 자리 적장 토벌(임시)
|
||||||
|
color,arena_art,,,,,,#FFFFFF40,연무장 카드 일러 자리 픽토그램(흰 25 %)
|
||||||
|
icon,hud_ally,Icon_PictoIcons/128/PictoIcon_Helmet_1.Png,,,,,,전투 HUD 아군 수 아이콘(Fable §4-8)
|
||||||
|
icon,hud_enemy,Icon_PictoIcons/128/PictoIcon_Boss.Png,,,,,,전투 HUD 적 수 아이콘
|
||||||
|
color,skill_glow,,,,,,#FFD24AFF,스킬 버튼 뒤 빛(사용 가능 · 금빛 · 붉은 버튼·모래 바탕과 대비)
|
||||||
|
icon,shield,IconMisc/Icon_Shield.png,,,,,,방어 스탯(Fable §5-8)
|
||||||
|
|
|
||||||
|
|
|
@ -502,7 +502,7 @@ MonoBehaviour:
|
||||||
- id: text_on_yellow
|
- id: text_on_yellow
|
||||||
color: {r: 0.11764706, g: 0.11764706, b: 0.16470589, a: 1}
|
color: {r: 0.11764706, g: 0.11764706, b: 0.16470589, a: 1}
|
||||||
- id: ribbon_glow
|
- id: ribbon_glow
|
||||||
color: {r: 0.9529412, g: 0.7176471, b: 0.18039216, a: 0.7019608}
|
color: {r: 1, g: 0.8235294, b: 0.2901961, a: 1}
|
||||||
- id: row_on_field
|
- id: row_on_field
|
||||||
color: {r: 0.24705882, g: 0.25882354, b: 0.38431373, a: 1}
|
color: {r: 0.24705882, g: 0.25882354, b: 0.38431373, a: 1}
|
||||||
- id: banner_pattern
|
- id: banner_pattern
|
||||||
|
|
@ -562,9 +562,13 @@ MonoBehaviour:
|
||||||
- id: card3_light
|
- id: card3_light
|
||||||
color: {r: 1, g: 1, b: 1, a: 0.5019608}
|
color: {r: 1, g: 1, b: 1, a: 0.5019608}
|
||||||
- id: chest_glow
|
- id: chest_glow
|
||||||
color: {r: 0.9529412, g: 0.7176471, b: 0.18039216, a: 0.4509804}
|
color: {r: 1, g: 0.8235294, b: 0.2901961, a: 0.9019608}
|
||||||
- id: banner_point
|
- id: banner_point
|
||||||
color: {r: 0.17254902, g: 0.18431373, b: 0.2901961, a: 1}
|
color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: arena_art
|
||||||
|
color: {r: 1, g: 1, b: 1, a: 0.2509804}
|
||||||
|
- id: skill_glow
|
||||||
|
color: {r: 1, g: 0.8235294, b: 0.2901961, a: 1}
|
||||||
skins:
|
skins:
|
||||||
- id: card
|
- id: card
|
||||||
pack: {fileID: 21300000, guid: 3070a6f23e6ca4273897acf1b7e8c5ce, type: 3}
|
pack: {fileID: 21300000, guid: 3070a6f23e6ca4273897acf1b7e8c5ce, type: 3}
|
||||||
|
|
@ -1729,6 +1733,34 @@ MonoBehaviour:
|
||||||
pack: {fileID: 21300000, guid: d031f4b21493c4841914d4257119a4e3, type: 3}
|
pack: {fileID: 21300000, guid: d031f4b21493c4841914d4257119a4e3, type: 3}
|
||||||
samguk: {fileID: 0}
|
samguk: {fileID: 0}
|
||||||
tint: {r: 1, g: 1, b: 1, a: 1}
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: arena_art_0
|
||||||
|
pack: {fileID: 21300000, guid: e63f49ada5fda4cc59b8b5080feeb0b7, type: 3}
|
||||||
|
samguk: {fileID: 0}
|
||||||
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: arena_art_1
|
||||||
|
pack: {fileID: 21300000, guid: 304fa5e62cade424d9ae15c73cd20a12, type: 3}
|
||||||
|
samguk: {fileID: 0}
|
||||||
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: arena_art_2
|
||||||
|
pack: {fileID: 21300000, guid: e0df45813c53b41d386a33c49657561d, type: 3}
|
||||||
|
samguk: {fileID: 0}
|
||||||
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: arena_art_3
|
||||||
|
pack: {fileID: 21300000, guid: cd6dc5dd342ab486b96c3d3e666c6bb9, type: 3}
|
||||||
|
samguk: {fileID: 0}
|
||||||
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: hud_ally
|
||||||
|
pack: {fileID: 21300000, guid: 6fcf7bcb2b29e4b589e82ab74f31c79e, type: 3}
|
||||||
|
samguk: {fileID: 0}
|
||||||
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: hud_enemy
|
||||||
|
pack: {fileID: 21300000, guid: 0127e486ba6e6408ba9139509d699e4f, type: 3}
|
||||||
|
samguk: {fileID: 0}
|
||||||
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- id: shield
|
||||||
|
pack: {fileID: 21300000, guid: 09135c198f8744fcd89493b169d11bd8, type: 3}
|
||||||
|
samguk: {fileID: 0}
|
||||||
|
tint: {r: 1, g: 1, b: 1, a: 1}
|
||||||
- id: tile_bridge
|
- id: tile_bridge
|
||||||
pack: {fileID: 0}
|
pack: {fileID: 0}
|
||||||
samguk: {fileID: 21300000, guid: 8e5bf7eb1e300474785ff2781eeb5093, type: 3}
|
samguk: {fileID: 21300000, guid: 8e5bf7eb1e300474785ff2781eeb5093, type: 3}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ namespace TKS.OutGame
|
||||||
|
|
||||||
public override void Build()
|
public override void Build()
|
||||||
{
|
{
|
||||||
|
if (UISkin.On) UiKit.Paint(UiKit.Fill("ListBg", Rt), UiKit.Col("list_bg", UiKit.Bg), false); // 목록형 바탕(Fable §5-3)
|
||||||
Header("연무장", "탑 · 일일 던전 · 투기장 · 적장 토벌", true);
|
Header("연무장", "탑 · 일일 던전 · 투기장 · 적장 토벌", true);
|
||||||
root = Body();
|
root = Body();
|
||||||
}
|
}
|
||||||
|
|
@ -83,6 +84,11 @@ namespace TKS.OutGame
|
||||||
{ "주간 보스(여포·조조 …) · 누적 피해", "보물 명장 상자", "하루 " + e.RaidDaily, "이번 주 " + boss + " · 누적 " + d.arena.raidDamage.ToString("N0") },
|
{ "주간 보스(여포·조조 …) · 누적 피해", "보물 명장 상자", "하루 " + e.RaidDaily, "이번 주 " + boss + " · 누적 " + d.arena.raidDamage.ToString("N0") },
|
||||||
};
|
};
|
||||||
float w = 508f, h = 700f;
|
float w = 508f, h = 700f;
|
||||||
|
if (UISkin.Has("card4_bg") && UISkin.Has("btn_l_yellow"))
|
||||||
|
{
|
||||||
|
CardsKit(text, w, h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
int k = i;
|
int k = i;
|
||||||
|
|
@ -124,6 +130,81 @@ namespace TKS.OutGame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 카드 그림 · 요약 · 보상 아이콘(테마 id · Fable §4-6 · 일러 N4 전까지 픽토그램 임시)
|
||||||
|
static readonly string[] Arts = { "arena_art_0", "arena_art_1", "arena_art_2", "arena_art_3" };
|
||||||
|
static readonly string[] Briefs = { "층마다 고정 편성 · 10층마다 보스", "요일 순환 재화 던전", "비동기 5v5 · 주간 랭킹", "주간 보스 · 누적 피해" };
|
||||||
|
static readonly string[][] RewardIcons =
|
||||||
|
{
|
||||||
|
new[] { "cur_gem", "cur_blueprint", "chest_gold" },
|
||||||
|
new[] { "cur_gold", "cur_iron", "cur_skillbook" },
|
||||||
|
new[] { "gear_flag", "cur_shard" },
|
||||||
|
new[] { "chest_general" },
|
||||||
|
};
|
||||||
|
static readonly string[] EntryIcons = { "cur_ticket", null, "sword", "fire" };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 모드 카드(Fable 제안서 §4-6 · #1104) = CardFrame04 카드색 + 리본 제목(유지) · 위 일러 자리(픽토그램 220 흰 25 %) + 요약 한 줄 ·
|
||||||
|
/// 아래 어두운 판에 칩 2줄(입장 = 아이콘 + 값 · 보상 = 아이템 칸 72) · 상태 칩 · 규칙 문장 → ⓘ 팝업 · 이벤트 = 오른쪽 위 뱃지.
|
||||||
|
/// </summary>
|
||||||
|
void CardsKit(string[,] text, float w, float h)
|
||||||
|
{
|
||||||
|
var d = S.Save;
|
||||||
|
var db = S.Db;
|
||||||
|
var now = S.Now;
|
||||||
|
string[] entry =
|
||||||
|
{
|
||||||
|
"입장권 " + d.arena.towerTickets + " / " + db.Economy.TowerTicketsDaily,
|
||||||
|
"오늘 " + OpenCount(now) + "곳 · 각 " + (db.Dungeons.dungeons.Count > 0 ? db.Dungeons.dungeons[0].entriesPerDay : 0) + "회",
|
||||||
|
"남은 " + ArenaRules.ArenaLeft(db, d, now) + " / " + db.Arena.EntriesPerDay,
|
||||||
|
"하루 " + db.Economy.RaidDaily + "회",
|
||||||
|
};
|
||||||
|
var soft = UiKit.Col("text_soft", UiKit.InkSoft);
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
int k = i;
|
||||||
|
float x = 24f + (i % 2) * (w + 16f);
|
||||||
|
float y = 18f + (i / 2) * (h + 20f);
|
||||||
|
var ci = UiKit.Skin(UiKit.At(root, "Card" + i, x, y, w, h), "card4_bg", UiKit.Col("arena_" + i, UiKit.Paper), true);
|
||||||
|
var card = ci.transform;
|
||||||
|
card.gameObject.AddComponent<Button>().onClick.AddListener(() => SetPage(k + 1));
|
||||||
|
UiKit.Layer(card, "Glow", "card4_glow", UiKit.Col("arena_glow", UiKit.White), 0f, 0f, 0f, h * 0.5f);
|
||||||
|
// 일러 자리 = 픽토그램(흰 25 %)
|
||||||
|
var art = UiKit.Icon(card, Arts[i], new Vector2(0.5f, 1f), new Vector2(0.5f, 0.5f), new Vector2(0f, -232f), 220f);
|
||||||
|
if (art != null) art.color = UiKit.Col("arena_art", new Color(1f, 1f, 1f, 0.25f));
|
||||||
|
var brief = UiKit.Title(UiKit.Label(card, Briefs[i], 28, UiKit.White, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -356f), new Vector2(w - 40f, 44f)), true);
|
||||||
|
brief.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
// 칩 2줄 판
|
||||||
|
var board = UiKit.Skin(UiKit.At(card, "Inner", 14f, 414f, w - 28f, 182f), "panel12", UiKit.Col("arena_inner", UiKit.Paper)).transform;
|
||||||
|
UiKit.Label(board, "입장", 26, soft, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(20f, -14f), new Vector2(80f, 56f));
|
||||||
|
UiKit.InfoChip(board, "Entry", 96f, 16f, w - 28f - 96f - 18f, 52f, EntryIcons[i], entry[i], 26);
|
||||||
|
UiKit.Label(board, "보상", 26, soft, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(20f, -98f), new Vector2(80f, 72f));
|
||||||
|
for (int r = 0; r < RewardIcons[i].Length; r++)
|
||||||
|
UiKit.RewardTile(board, "Rw" + r, 96f + r * 86f, 92f, 76f, "gear_white_", RewardIcons[i][r], null, false);
|
||||||
|
// 상태 칩
|
||||||
|
var st = UiKit.Skin(UiKit.At(card, "Status", 16f, h - 86f, w - 32f, 66f), "chip", UiKit.Col("chip_dark", UiKit.Dark));
|
||||||
|
var stt = UiKit.Title(UiKit.FillLabel(st.transform, text[i, 3], 26, UiKit.Col("lv_fill", UiKit.Coin), TextAnchor.MiddleCenter, true, 16f), true);
|
||||||
|
stt.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
// 리본 제목(맨 위) · 이벤트 뱃지 · ⓘ
|
||||||
|
var rib = UiKit.Skin(UiKit.Rect("Ribbon", card, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, 4f), new Vector2(w - 40f, 96f)), Ribbons[i], UiKit.White);
|
||||||
|
var rt = UiKit.Title(UiKit.FillLabel(rib.transform, ModeNames[i], 42, UiKit.White, TextAnchor.MiddleCenter, true, 40f), true);
|
||||||
|
rt.rectTransform.offsetMin = new Vector2(rt.rectTransform.offsetMin.x, 16f);
|
||||||
|
if (i == 3)
|
||||||
|
{
|
||||||
|
var ev = UiKit.Icon(card, "badge_hot", new Vector2(1f, 1f), new Vector2(0.5f, 0.5f), new Vector2(-30f, -118f), 96f);
|
||||||
|
if (ev != null)
|
||||||
|
{
|
||||||
|
UiKit.DropShadow(ev, 3f);
|
||||||
|
UiKit.Title(UiKit.FillLabel(ev.transform, "이벤트", 22, UiKit.White), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var info = UiKit.Rect("Info", card, new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(46f, -122f), new Vector2(60f, 60f));
|
||||||
|
UiKit.Skin(info, "badge_circle", UiKit.Col("chip_dark", UiKit.Dark), true);
|
||||||
|
if (UiKit.Icon(info, "info", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 32f) == null) UiKit.Title(UiKit.FillLabel(info, "i", 30, UiKit.White), true);
|
||||||
|
string rules = "<b>규칙</b> " + text[i, 0] + "\n\n<b>보상</b> " + text[i, 1] + "\n\n<b>입장</b> " + text[i, 2];
|
||||||
|
info.gameObject.AddComponent<Button>().onClick.AddListener(() => Root.Modal(ModeNames[k], rules, new OutGameRoot.ModalButton("확인", UiKit.Dark, null)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int OpenCount(System.DateTime now)
|
int OpenCount(System.DateTime now)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,15 @@ namespace TKS.OutGame
|
||||||
public override void Build()
|
public override void Build()
|
||||||
{
|
{
|
||||||
Tab = 2;
|
Tab = 2;
|
||||||
|
if (UISkin.On) UiKit.Paint(UiKit.Fill("ListBg", Rt), UiKit.Col("list_bg", UiKit.Bg), false); // 목록형 바탕(Fable §5-3)
|
||||||
Header("내정", "훈련 · 순찰 · 개발", true);
|
Header("내정", "훈련 · 순찰 · 개발", true);
|
||||||
var body = Body();
|
var body = Body();
|
||||||
for (int i = 0; i < PageNames.Length; i++)
|
for (int i = 0; i < PageNames.Length; i++)
|
||||||
{
|
{
|
||||||
int k = i;
|
int k = i;
|
||||||
tabs.Add(UiKit.Btn("Tab" + i, body, PageNames[i], 36, UiKit.Paper, UiKit.Ink, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f + i * 348f, -18f), new Vector2(332f, 84f), () => SetPage(k)));
|
tabs.Add(UISkin.On
|
||||||
|
? UiKit.SubTab(body, "Tab" + i, PageNames[i], 24f + i * 348f, 18f, 332f, 84f, () => SetPage(k))
|
||||||
|
: UiKit.Btn("Tab" + i, body, PageNames[i], 36, UiKit.Paper, UiKit.Ink, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f + i * 348f, -18f), new Vector2(332f, 84f), () => SetPage(k)));
|
||||||
pages.Add(UiKit.Fill("Page" + i, body, 0f, 0f, 118f, 0f));
|
pages.Add(UiKit.Fill("Page" + i, body, 0f, 0f, 118f, 0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,13 +98,21 @@ namespace TKS.OutGame
|
||||||
for (int i = 0; i < tabs.Count; i++)
|
for (int i = 0; i < tabs.Count; i++)
|
||||||
{
|
{
|
||||||
bool on = i == page;
|
bool on = i == page;
|
||||||
tabs[i].GetComponent<Image>().color = on ? UiKit.Red : UiKit.Paper; // 선택 = 붉은 옻칠(다른 화면 탭과 같음)
|
if (UISkin.On) UiKit.SetSubTab(tabs[i], on);
|
||||||
UiKit.LabelOf(tabs[i]).color = on ? UiKit.White : UiKit.Ink;
|
else
|
||||||
|
{
|
||||||
|
tabs[i].GetComponent<Image>().color = on ? UiKit.Red : UiKit.Paper; // 선택 = 붉은 옻칠(다른 화면 탭과 같음)
|
||||||
|
UiKit.LabelOf(tabs[i]).color = on ? UiKit.White : UiKit.Ink;
|
||||||
|
}
|
||||||
pages[i].gameObject.SetActive(on);
|
pages[i].gameObject.SetActive(on);
|
||||||
}
|
}
|
||||||
UiKit.Clear(pages[page]);
|
UiKit.Clear(pages[page]);
|
||||||
if (page == 0) BuildTraining(pages[0]);
|
if (page == 0) BuildTraining(pages[0]);
|
||||||
else if (page == 1) BuildPatrol(pages[1]);
|
else if (page == 1)
|
||||||
|
{
|
||||||
|
if (UISkin.Has("panel_field") && UISkin.Has("btn_l_green")) BuildPatrolKit(pages[1]);
|
||||||
|
else BuildPatrol(pages[1]);
|
||||||
|
}
|
||||||
else BuildDev(pages[2]);
|
else BuildDev(pages[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,6 +282,91 @@ namespace TKS.OutGame
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 순찰(Fable 제안서 §4-7 · #1104) — 섹션 「순찰」(기준 줄 + 레벨형 게이지 군량색 + 배지 「7h」) → 「시간당 수확」 스탯 칸 4(아이콘 64 · 라벨 · 값 Sen) →
|
||||||
|
/// 「쌓인 보상」 타일 4(ItemFrame 132 + 수량 칩) → 수확 Primary 녹 · 광고 2배 Secondary 하늘 + 광고 글리프 · 즉시 Secondary 보라 + 보옥 비용.
|
||||||
|
/// </summary>
|
||||||
|
void BuildPatrolKit(RectTransform p)
|
||||||
|
{
|
||||||
|
var db = S.Db;
|
||||||
|
var d = S.Save;
|
||||||
|
var e = db.Economy;
|
||||||
|
var row = PatrolRules.Row(db, d);
|
||||||
|
float cap = PatrolRules.CapHours(db, d);
|
||||||
|
float h = PatrolRules.Hours(db, d, S.Now);
|
||||||
|
var soft = UiKit.Col("text_soft", UiKit.InkSoft);
|
||||||
|
const float W = 1032f, Fw = W - 12f, GaugeBar = 640f;
|
||||||
|
|
||||||
|
// ① 순찰
|
||||||
|
RectTransform ar;
|
||||||
|
var a = UiKit.SectionPanel(p, "Patrol", 24f, 6f, W, 236f, false, false, out ar);
|
||||||
|
UiKit.SectionTitle(ar, "순찰");
|
||||||
|
var basis = UiKit.Label(ar, "기준 = 마지막 클리어 " + (row != null ? row.chapter : 0) + "장 · 오프라인 누적", 26, soft, TextAnchor.MiddleRight, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-24f, -12f), new Vector2(620f, 48f), false);
|
||||||
|
basis.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
Text badge;
|
||||||
|
var fill = UiKit.Gauge(a, "Gauge", 16f, 66f, GaugeBar, "lv_badge", "grain", out badge);
|
||||||
|
UiKit.SetGauge(fill, cap > 0f ? h / cap : 0f, GaugeBar);
|
||||||
|
badge.text = Mathf.FloorToInt(h) + "h";
|
||||||
|
badge.fontSize = 30;
|
||||||
|
var cur = UiKit.Title(UiKit.Label(a, FormatHours(h) + " / " + FormatHours(cap), 30, UiKit.White, TextAnchor.MiddleRight, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-24f, -84f), new Vector2(220f, 60f)), true);
|
||||||
|
cur.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
UiKit.Label(a, "최대 " + FormatHours(cap) + " · 성장 패스 24시간(준비 중) · 농업 개발 +" + Mathf.RoundToInt(DevRules.Mod(db, d, DevRules.PatrolCap)) + "분", 24, soft, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f, -168f), new Vector2(Fw - 48f, 44f), false);
|
||||||
|
|
||||||
|
// ② 시간당 수확
|
||||||
|
RectTransform br;
|
||||||
|
var b = UiKit.SectionPanel(p, "Rate", 24f, 258f, W, 448f, false, false, out br);
|
||||||
|
UiKit.SectionTitle(br, "시간당 수확");
|
||||||
|
string[] rn = { "골드", "병사 경험", "승급 장비", "보물 청동 상자" };
|
||||||
|
string[] rv =
|
||||||
|
{
|
||||||
|
PatrolRules.GoldPerHour(db, d).ToString("N0"),
|
||||||
|
PatrolRules.ExpPerHour(db, d).ToString("N0"),
|
||||||
|
PatrolRules.GearPerHour(db, d).ToString("0.##"),
|
||||||
|
PatrolRules.ChestPerHour(db, d).ToString("0.##"),
|
||||||
|
};
|
||||||
|
string[] rs = { "/ 시간", "/ 시간 · 출전 편성", "/ 시간 · " + UiKit.GradeKo(PatrolRules.GearGrade(db, d)) + " 등급", "/ 시간" };
|
||||||
|
string[] rIcon = { "cur_gold", "cur_exp", "cur_gear", "chest_bronze" };
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
var cell = UiKit.Skin(UiKit.At(b, "Row" + i, 14f, 76f + i * 90f, Fw - 28f, 82f), "panel12", UiKit.Col("row_on_field", UiKit.Paper)).transform;
|
||||||
|
var ic = UiKit.Icon(cell, rIcon[i], new Vector2(0f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(50f, 0f), 64f);
|
||||||
|
if (ic != null) UiKit.DropShadow(ic, 3f);
|
||||||
|
UiKit.Label(cell, rn[i], 30, soft, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(98f, 0f), new Vector2(300f, 60f), false);
|
||||||
|
var sub = UiKit.Label(cell, rs[i], 24, soft, TextAnchor.MiddleRight, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-24f, -2f), new Vector2(300f, 50f), false);
|
||||||
|
sub.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
var val = UiKit.Title(UiKit.Label(cell, rv[i], 44, UiKit.White, TextAnchor.MiddleRight, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-24f - Mathf.Ceil(sub.preferredWidth) - 14f, 2f), new Vector2(260f, 70f)), true);
|
||||||
|
val.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ③ 쌓인 보상
|
||||||
|
var y = PatrolRules.Preview(db, d, h, 1f);
|
||||||
|
RectTransform cr;
|
||||||
|
var c = UiKit.SectionPanel(p, "Stored", 24f, 722f, W, 262f, false, false, out cr);
|
||||||
|
UiKit.SectionTitle(cr, "쌓인 보상");
|
||||||
|
string[] sn = { y.gold.ToString("N0"), y.exp.ToString("N0"), y.gear.ToString(), y.chests.ToString() };
|
||||||
|
const float Tile = 132f, Gap = 64f;
|
||||||
|
float tx0 = (Fw - 4f * Tile - 3f * Gap) * 0.5f;
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
UiKit.RewardTile(c, "Tile" + i, tx0 + i * (Tile + Gap), 90f, Tile, i == 2 ? "gear_" + PatrolRules.GearGrade(db, d) + "_" : "gear_white_", rIcon[i], sn[i], i == 2);
|
||||||
|
|
||||||
|
// ④ 버튼
|
||||||
|
EconomyRules.RollDaily(d, S.Now);
|
||||||
|
var hb = UiKit.SkinBtn(p, "Harvest", h > 0f ? "btn_l_green" : "btn_gray", UiKit.White, "수확", 52, UiKit.Col("text_on_green", UiKit.White), (1080f - 600f) * 0.5f, 1004f, 600f, 128f, () => DoHarvest(false));
|
||||||
|
hb.interactable = h > 0f;
|
||||||
|
bool adOk = h > 0f && d.adsUsed.patrol < e.PatrolAdDaily;
|
||||||
|
var ad = UiKit.SkinBtn(p, "Ad", adOk ? "btn_sky" : "btn_gray", UiKit.White, "광고 2배", 38, UiKit.White, 24f, 1152f, 505f, 112f, () => DoHarvest(true));
|
||||||
|
ad.interactable = adOk;
|
||||||
|
UiKit.BtnCost(ad, "ad", d.adsUsed.patrol + "/" + e.PatrolAdDaily, 34f, 28);
|
||||||
|
var ins = UiKit.SkinBtn(p, "Instant", "btn_purple", UiKit.White, "즉시 " + FormatHours(e.PatrolInstantHours), 38, UiKit.White, 1056f - 505f, 1152f, 505f, 112f, () =>
|
||||||
|
{
|
||||||
|
string why;
|
||||||
|
var r = S.InstantHarvest(out why);
|
||||||
|
if (r == null) Root.Toast(why);
|
||||||
|
else ShowYield("즉시 수확", r);
|
||||||
|
});
|
||||||
|
UiKit.BtnCost(ins, "cur_gem", e.PatrolInstantGem.ToString(), 40f, 32);
|
||||||
|
}
|
||||||
|
|
||||||
void DoHarvest(bool ad)
|
void DoHarvest(bool ad)
|
||||||
{
|
{
|
||||||
string why;
|
string why;
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,32 @@ namespace TKS.OutGame
|
||||||
public override void Build()
|
public override void Build()
|
||||||
{
|
{
|
||||||
Tab = 1;
|
Tab = 1;
|
||||||
|
if (UISkin.On) UiKit.Paint(UiKit.Fill("ListBg", Rt), UiKit.Col("list_bg", UiKit.Bg), false); // 목록형 바탕(Fable §5-3)
|
||||||
Header("보물", "", true); // 부제 삭제(설계서 §2-5)
|
Header("보물", "", true); // 부제 삭제(설계서 §2-5)
|
||||||
var body = Body();
|
var body = Body();
|
||||||
for (int i = 0; i < PageNames.Length; i++)
|
for (int i = 0; i < PageNames.Length; i++)
|
||||||
{
|
{
|
||||||
int k = i;
|
int k = i;
|
||||||
tabs.Add(UiKit.Btn("Tab" + i, body, PageNames[i], 36, UiKit.Paper, UiKit.Ink, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f + i * 348f, -18f), new Vector2(332f, 84f), () => SetPage(k)));
|
tabs.Add(UISkin.On
|
||||||
|
? UiKit.SubTab(body, "Tab" + i, PageNames[i], 24f + i * 348f, 18f, 332f, 84f, () => SetPage(k))
|
||||||
|
: UiKit.Btn("Tab" + i, body, PageNames[i], 36, UiKit.Paper, UiKit.Ink, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f + i * 348f, -18f), new Vector2(332f, 84f), () => SetPage(k)));
|
||||||
pages.Add(UiKit.Fill("Page" + i, body, 0f, 0f, 118f, 0f));
|
pages.Add(UiKit.Fill("Page" + i, body, 0f, 0f, 118f, 0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>새 상자 화면 부품(Fable §4-5)이 테마에 있는가.</summary>
|
||||||
|
static bool Kit
|
||||||
|
{
|
||||||
|
get { return UISkin.Has("card3_bg") && UISkin.Has("banner_point") && UISkin.Has("btn_l_yellow"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>보물 아이콘 id — 납품 그림(tre_<id>)이 있으면 그것 · 없으면 기본 스탯별 팩 임시 아이콘(tre_stat_* · Fable §6 N3 전까지).</summary>
|
||||||
|
static string IconId(TreasureDb.Item it)
|
||||||
|
{
|
||||||
|
if (UiKit.HasFinalIcon("tre_" + it.id)) return "tre_" + it.id;
|
||||||
|
return UISkin.Icon("tre_stat_" + it.baseStat) != null ? "tre_stat_" + it.baseStat : null;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetPage(int p)
|
public void SetPage(int p)
|
||||||
{
|
{
|
||||||
page = Mathf.Clamp(p, 0, pages.Count - 1);
|
page = Mathf.Clamp(p, 0, pages.Count - 1);
|
||||||
|
|
@ -67,13 +83,18 @@ namespace TKS.OutGame
|
||||||
for (int i = 0; i < tabs.Count; i++)
|
for (int i = 0; i < tabs.Count; i++)
|
||||||
{
|
{
|
||||||
bool on = i == page;
|
bool on = i == page;
|
||||||
tabs[i].GetComponent<Image>().color = on ? UiKit.Red : UiKit.Paper; // 선택 = 붉은 옻칠(다른 화면 탭과 같음)
|
if (UISkin.On) UiKit.SetSubTab(tabs[i], on);
|
||||||
UiKit.LabelOf(tabs[i]).color = on ? UiKit.White : UiKit.Ink;
|
else
|
||||||
|
{
|
||||||
|
tabs[i].GetComponent<Image>().color = on ? UiKit.Red : UiKit.Paper; // 선택 = 붉은 옻칠(다른 화면 탭과 같음)
|
||||||
|
UiKit.LabelOf(tabs[i]).color = on ? UiKit.White : UiKit.Ink;
|
||||||
|
}
|
||||||
pages[i].gameObject.SetActive(on);
|
pages[i].gameObject.SetActive(on);
|
||||||
}
|
}
|
||||||
UiKit.Clear(pages[page]);
|
UiKit.Clear(pages[page]);
|
||||||
if (page == 0) BuildOwned(pages[0]);
|
if (page == 0) BuildOwned(pages[0]);
|
||||||
else if (page == 1) BuildSets(pages[1]);
|
else if (page == 1) BuildSets(pages[1]);
|
||||||
|
else if (Kit) BuildChestsKit(pages[2]);
|
||||||
else BuildChests(pages[2]);
|
else BuildChests(pages[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,10 +116,12 @@ namespace TKS.OutGame
|
||||||
cell.sprite = null; // 바닥 = 클릭 판(투명)
|
cell.sprite = null; // 바닥 = 클릭 판(투명)
|
||||||
var t = cell.transform;
|
var t = cell.transform;
|
||||||
UiKit.ItemSlot(t, owned ? "tre_" + it.grade + "_" : "tre_none_", owned);
|
UiKit.ItemSlot(t, owned ? "tre_" + it.grade + "_" : "tre_none_", owned);
|
||||||
var art = UiKit.Rect("Art", t, new Vector2(0.5f, 1f), new Vector2(0.5f, 0.5f), new Vector2(0f, -96f), new Vector2(140f, 140f));
|
var art = UiKit.Rect("Art", t, new Vector2(0.5f, 1f), new Vector2(0.5f, 0.5f), new Vector2(0f, -100f), new Vector2(140f, 140f));
|
||||||
if (UiKit.HasFinalIcon("tre_" + it.id))
|
string icon = IconId(it);
|
||||||
|
if (icon != null)
|
||||||
{
|
{
|
||||||
var ic = UiKit.Icon(art, "tre_" + it.id, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 140f);
|
// 아이콘 = 납품 그림 또는 기본 스탯별 임시(Fable §4-5 「글자 → 보물 아이콘」) · 미보유 = 흰 25 % 실루엣
|
||||||
|
var ic = UiKit.Icon(art, icon, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, icon.StartsWith("tre_stat_") ? 120f : 140f);
|
||||||
if (owned) UiKit.DropShadow(ic, 5f);
|
if (owned) UiKit.DropShadow(ic, 5f);
|
||||||
else ic.color = UiKit.Col("tre_none_icon", UiKit.InkSoft);
|
else ic.color = UiKit.Col("tre_none_icon", UiKit.InkSoft);
|
||||||
}
|
}
|
||||||
|
|
@ -115,8 +138,16 @@ namespace TKS.OutGame
|
||||||
}
|
}
|
||||||
else if (st.star > 0) UiKit.StarRow(t, st.star, st.star, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 72f), 30f);
|
else if (st.star > 0) UiKit.StarRow(t, st.star, st.star, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 72f), 30f);
|
||||||
}
|
}
|
||||||
var band = UiKit.Skin(UiKit.Rect("Name", t, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 12f), new Vector2(206f, 52f)), "plate12", UiKit.Col("gear_plate", UiKit.Dark));
|
// 이름 띠 = 칸 아래에 붙은 카드 띠(CardFrame01_Bottom · Fable §4-5) · 테마가 없으면 둥근 판
|
||||||
var nt = UiKit.FillLabel(band.transform, owned ? it.nameKo : "미보유", 26, owned ? UiKit.White : UiKit.InkSoft);
|
var band = UISkin.Has("card_bottom")
|
||||||
|
? UiKit.Layer(t, "Name", "card_bottom", UiKit.Col("card_bottom", UiKit.Dark), 6f, 0f, 6f, 6f)
|
||||||
|
: UiKit.Skin(UiKit.Rect("Name", t, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 12f), new Vector2(206f, 52f)), "plate12", UiKit.Col("gear_plate", UiKit.Dark));
|
||||||
|
if (UISkin.Has("card_bottom"))
|
||||||
|
{
|
||||||
|
band.rectTransform.anchorMax = new Vector2(1f, 0f);
|
||||||
|
band.rectTransform.offsetMax = new Vector2(-6f, 62f);
|
||||||
|
}
|
||||||
|
var nt = UiKit.FillLabel(band.transform, owned ? it.nameKo : "미보유", 26, owned ? UiKit.White : UiKit.Col("text_soft", UiKit.InkSoft));
|
||||||
nt.horizontalOverflow = HorizontalWrapMode.Overflow;
|
nt.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,12 +159,17 @@ namespace TKS.OutGame
|
||||||
int owned = 0;
|
int owned = 0;
|
||||||
foreach (var it in db.Treasures.items)
|
foreach (var it in db.Treasures.items)
|
||||||
if (S.Save.inv.Treasure(it.id) != null) owned++;
|
if (S.Save.inv.Treasure(it.id) != null) owned++;
|
||||||
UiKit.Label(p, "보유 " + owned + " / " + db.Treasures.items.Count, 36, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -8f), new Vector2(360f, 56f));
|
var cnt = UiKit.Title(UiKit.Label(p, "보유 " + owned + " / " + db.Treasures.items.Count, 36, UiKit.Ink, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -8f), new Vector2(360f, 56f)), UISkin.On);
|
||||||
|
cnt.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
var grades = db.Economy.TreasureGrades;
|
var grades = db.Economy.TreasureGrades;
|
||||||
for (int i = 0; i < grades.Count; i++)
|
for (int i = 0; i < grades.Count; i++)
|
||||||
{
|
{
|
||||||
var chip = UiKit.Box("G" + i, p, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-24f - (grades.Count - 1 - i) * 118f, -12f), new Vector2(110f, 48f), GradeColor(grades[i].Key));
|
// 등급 범례 칩 = 서브탭 틀 소형(Round10 · Fable §4-5 「120×56 통일」) · 등급 대표 색
|
||||||
UiKit.FillLabel(chip.transform, TreasureRules.GradeKo(grades[i].Key), 24, UiKit.White);
|
var pos = new Vector2(-24f - (grades.Count - 1 - i) * 126f, -8f);
|
||||||
|
var chip = UISkin.Has("subtab")
|
||||||
|
? UiKit.Skin(UiKit.Rect("G" + i, p, new Vector2(1f, 1f), new Vector2(1f, 1f), pos, new Vector2(118f, 56f)), "subtab", GradeColor(grades[i].Key))
|
||||||
|
: UiKit.Box("G" + i, p, new Vector2(1f, 1f), new Vector2(1f, 1f), pos, new Vector2(110f, 48f), GradeColor(grades[i].Key));
|
||||||
|
UiKit.Title(UiKit.FillLabel(chip.transform, TreasureRules.GradeKo(grades[i].Key), 26, UiKit.White), UISkin.On);
|
||||||
}
|
}
|
||||||
ScrollRect sr;
|
ScrollRect sr;
|
||||||
var grid = UiKit.ScrollGrid("Grid", p, 24f, 24f, 76f, 64f, new Vector2(240f, 290f), new Vector2(16f, 16f), 4, out sr);
|
var grid = UiKit.ScrollGrid("Grid", p, 24f, 24f, 76f, 64f, new Vector2(240f, 290f), new Vector2(16f, 16f), 4, out sr);
|
||||||
|
|
@ -157,8 +193,15 @@ namespace TKS.OutGame
|
||||||
float v = TreasureRules.StatPct(db, S.Save, s);
|
float v = TreasureRules.StatPct(db, S.Save, s);
|
||||||
if (v > 0f) bonus.Add(TreasureRules.StatKo(s) + " +" + v.ToString("0.#") + "%");
|
if (v > 0f) bonus.Add(TreasureRules.StatKo(s) + " +" + v.ToString("0.#") + "%");
|
||||||
}
|
}
|
||||||
UiKit.Label(p, bonus.Count > 0 ? "전체 효과 " + string.Join(" · ", bonus.ToArray()) : "보물을 모으면 전 유닛에 상시 효과", 26, UiKit.InkSoft, TextAnchor.MiddleCenter,
|
string fx = bonus.Count > 0 ? "전체 효과 " + string.Join(" · ", bonus.ToArray()) : "보물을 모으면 전 유닛에 상시 효과";
|
||||||
new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 8f), new Vector2(1030f, 50f), false);
|
if (UISkin.Has("chip"))
|
||||||
|
{
|
||||||
|
// 아래 효과 줄 = 정보 칩(§5-6)
|
||||||
|
var c =UiKit.Skin(UiKit.Rect("Effects", p, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 4f), new Vector2(1032f, 54f)), "chip", UiKit.Col("chip_dark", UiKit.Dark));
|
||||||
|
var ft = UiKit.FillLabel(c.transform, fx, 26, UiKit.White, TextAnchor.MiddleCenter, false, 20f);
|
||||||
|
ft.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
}
|
||||||
|
else UiKit.Label(p, fx, 26, UiKit.InkSoft, TextAnchor.MiddleCenter, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 8f), new Vector2(1030f, 50f), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Detail(string id)
|
public void Detail(string id)
|
||||||
|
|
@ -317,6 +360,134 @@ namespace TKS.OutGame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 상자 탭(Fable 제안서 §4-5 · #1104) — 포인트 띠(BannerFrame05 · 가는 주황 바 · 「85 / 120」 · 오른쪽 보상 상자) →
|
||||||
|
/// 상자 카드(CardFrame03 상자 색 + 안쪽 + 광택 · 상자 아이콘 300 + 뒤 금빛 · 등급 칩 + % 한 줄 · 내용물 줄) · 좌우 화살표 →
|
||||||
|
/// 「열기」 Primary 노랑 + 보유 칩(없으면 회색) → 아래 상자 종류 행(ItemFrame 5층 상자 색 + 수량 칩 · 선택 = FocusLine 깜빡).
|
||||||
|
/// </summary>
|
||||||
|
void BuildChestsKit(RectTransform p)
|
||||||
|
{
|
||||||
|
var db = S.Db;
|
||||||
|
var d = S.Save;
|
||||||
|
var e = db.Economy;
|
||||||
|
var soft = UiKit.Col("text_soft", UiKit.InkSoft);
|
||||||
|
|
||||||
|
// 포인트 띠
|
||||||
|
var band = UiKit.Skin(UiKit.At(p, "Points", 24f, 6f, 1032f, 92f), "banner_point", UiKit.Col("banner_point", UiKit.White)).transform;
|
||||||
|
var pi = UiKit.Icon(band, "chest_point", new Vector2(0f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(46f, 2f), 76f);
|
||||||
|
if (pi != null) UiKit.DropShadow(pi, 3f);
|
||||||
|
var reward = db.Chests.Get(e.ChestPointReward);
|
||||||
|
UiKit.Label(band, Mathf.Max(0, e.ChestPointGoal - d.inv.chestPoints) + "포인트 더 모으면 " + (reward != null ? reward.nameKo : ""), 28, UiKit.White, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(112f, -6f), new Vector2(640f, 44f));
|
||||||
|
var bg = UiKit.Skin(UiKit.At(band, "Bar", 112f, 50f, 600f, 30f), "bar4_bg", UiKit.White);
|
||||||
|
var fill = UiKit.Skin(UiKit.At(bg.transform, "Fill", 4f, 4f, 592f, 20f), "bar4_fill", UiKit.White).rectTransform;
|
||||||
|
float v = Mathf.Clamp01(d.inv.chestPoints / (float)Mathf.Max(1, e.ChestPointGoal));
|
||||||
|
fill.sizeDelta = new Vector2(Mathf.Max(16f, 592f * v), 20f);
|
||||||
|
fill.gameObject.SetActive(v > 0.001f);
|
||||||
|
var pt = UiKit.Title(UiKit.Label(band, d.inv.chestPoints + " / " + e.ChestPointGoal, 30, UiKit.White, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(730f, -38f), new Vector2(180f, 50f)), true);
|
||||||
|
pt.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
if (reward != null)
|
||||||
|
{
|
||||||
|
var ri = UiKit.Icon(band, "chest_" + reward.id, new Vector2(1f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(-62f, 4f), 80f);
|
||||||
|
if (ri != null) UiKit.DropShadow(ri, 3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
var c = db.Chests.Get(SelectedChest);
|
||||||
|
if (c == null) return;
|
||||||
|
int count = TreasureRules.ChestCount(d, c.id);
|
||||||
|
|
||||||
|
// 상자 카드
|
||||||
|
const float Cw = 660f, Ch = 680f, Cy = 120f;
|
||||||
|
var card = UiKit.At(p, "Card", (1080f - Cw) * 0.5f, Cy, Cw, Ch);
|
||||||
|
UiKit.Skin(card, "card3_bg", ChestColor(c.id));
|
||||||
|
UiKit.Layer(card, "Inner", "card3_inner", UiKit.Col("card3_inner", Color.clear), 18f, 104f, 18f, 18f);
|
||||||
|
UiKit.Layer(card, "Light", "card3_light", UiKit.Col("card3_light", Color.clear), 6f, 6f, 6f, 10f);
|
||||||
|
var name = UiKit.Title(UiKit.Label(card, c.nameKo, 56, UiKit.White, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -16f), new Vector2(Cw - 40f, 80f)), true);
|
||||||
|
name.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
if (UISkin.Has("glow_circle"))
|
||||||
|
{
|
||||||
|
var glow = UiKit.Skin(UiKit.Rect("Glow", card, new Vector2(0.5f, 1f), new Vector2(0.5f, 0.5f), new Vector2(0f, -300f), new Vector2(520f, 520f)), "glow_circle", UiKit.Col("chest_glow", Color.clear));
|
||||||
|
var pulse = glow.gameObject.AddComponent<UiPulse>();
|
||||||
|
pulse.min = 0.7f;
|
||||||
|
pulse.period = 1.6f;
|
||||||
|
}
|
||||||
|
var ci = UiKit.Icon(card, "chest_" + c.id, new Vector2(0.5f, 1f), new Vector2(0.5f, 0.5f), new Vector2(0f, -300f), 300f);
|
||||||
|
if (ci != null) UiKit.DropShadow(ci, 8f);
|
||||||
|
var probs = new List<int>();
|
||||||
|
for (int i = 0; i < ChestDb.ProbGrades.Length; i++)
|
||||||
|
if (c.p[i] > 0f) probs.Add(i);
|
||||||
|
const float Pw = 178f, Pg = 14f;
|
||||||
|
float px = (Cw - probs.Count * Pw - (probs.Count - 1) * Pg) * 0.5f;
|
||||||
|
for (int k = 0; k < probs.Count; k++)
|
||||||
|
{
|
||||||
|
int i = probs[k];
|
||||||
|
string g = ChestDb.ProbGrades[i];
|
||||||
|
var chip = UiKit.Skin(UiKit.At(card, "P" + i, px + k * (Pw + Pg), 492f, Pw, 56f), "para_orange", GradeColor(g));
|
||||||
|
var ct = UiKit.Title(UiKit.FillLabel(chip.transform, TreasureRules.GradeKo(g) + " " + (c.p[i] * 100f).ToString("0.#") + "%", 28, UiKit.White), true);
|
||||||
|
ct.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
}
|
||||||
|
var extra = new List<string>();
|
||||||
|
if (c.goldMax > 0) extra.Add("골드 " + c.goldMin + "~" + c.goldMax);
|
||||||
|
if (c.gemMax > 0) extra.Add("보옥 " + c.gemMin + "~" + c.gemMax);
|
||||||
|
if (c.ironMax > 0) extra.Add("운철 " + c.ironMin + "~" + c.ironMax);
|
||||||
|
extra.Add("포인트 +" + c.points);
|
||||||
|
UiKit.Label(card, string.Join(" · ", extra.ToArray()), 26, UiKit.White, TextAnchor.MiddleCenter, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 40f), new Vector2(Cw - 60f, 50f), false);
|
||||||
|
|
||||||
|
// 좌우 화살표(카드 가운데 높이)
|
||||||
|
Arrow(p, "Prev", "arrow_prev", 30f, Cy + Ch * 0.5f - 70f, () => Step(-1));
|
||||||
|
Arrow(p, "Next", "arrow_next", 1080f - 30f - 100f, Cy + Ch * 0.5f - 70f, () => Step(1));
|
||||||
|
|
||||||
|
// 열기
|
||||||
|
var open = UiKit.SkinBtn(p, "Open", count > 0 ? "btn_l_yellow" : "btn_gray", UiKit.White, count > 0 ? "열기" : "상자 없음", 46,
|
||||||
|
count > 0 ? UiKit.Col("text_on_yellow", UiKit.Ink) : UiKit.White, (1080f - 460f) * 0.5f, Cy + Ch + 26f, 460f, 116f, () => DoOpen(SelectedChest));
|
||||||
|
open.interactable = count > 0;
|
||||||
|
if (count > 0) UiKit.BtnCost(open, "chest_" + c.id, "x" + count, 56f, 34);
|
||||||
|
UiKit.Label(p, "상자는 이 탭에서만 엽니다 · 중복 = 조각 · 천기 = 적장 토벌 전용", 26, soft, TextAnchor.MiddleCenter, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -(Cy + Ch + 156f)), new Vector2(1000f, 44f), false);
|
||||||
|
|
||||||
|
// 상자 종류 행(아래)
|
||||||
|
int n = db.Chests.chests.Count;
|
||||||
|
const float Tw = 150f;
|
||||||
|
float gap = n > 1 ? Mathf.Min(64f, (1032f - n * Tw) / (n - 1)) : 0f;
|
||||||
|
float tx0 = (1080f - n * Tw - (n - 1) * gap) * 0.5f;
|
||||||
|
float ty = OutGameRoot.BodyH - 118f - 24f - 40f - Tw;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
var ch = db.Chests.chests[i];
|
||||||
|
int k = i;
|
||||||
|
bool sel = i == chestIdx;
|
||||||
|
var cell = UiKit.At(p, "Chest_" + ch.id, tx0 + i * (Tw + gap), ty, Tw, Tw);
|
||||||
|
UiKit.ItemSlot(cell, "chest_" + ch.id + "_", sel);
|
||||||
|
var hit = cell.gameObject.AddComponent<Image>();
|
||||||
|
hit.color = Color.clear;
|
||||||
|
cell.gameObject.AddComponent<Button>().onClick.AddListener(() =>
|
||||||
|
{
|
||||||
|
chestIdx = k;
|
||||||
|
Refresh();
|
||||||
|
});
|
||||||
|
var ic = UiKit.Icon(cell, "chest_" + ch.id, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 6f), 104f);
|
||||||
|
if (ic != null) UiKit.DropShadow(ic, 4f);
|
||||||
|
UiKit.QtyChip(cell, "x" + TreasureRules.ChestCount(d, ch.id), 28);
|
||||||
|
if (sel && UISkin.Has("focus_line"))
|
||||||
|
{
|
||||||
|
var f = UiKit.Layer(cell, "Focus", "focus_line", UiKit.Col("select_line", UiKit.Coin), -8f, -8f, -8f, -8f);
|
||||||
|
f.gameObject.AddComponent<UiPulse>();
|
||||||
|
}
|
||||||
|
var nl = UiKit.Label(p, ch.nameKo, 26, sel ? UiKit.White : soft, TextAnchor.UpperCenter, new Vector2(0f, 1f), new Vector2(0.5f, 1f), new Vector2(tx0 + i * (Tw + gap) + Tw * 0.5f, -(ty + Tw + 10f)), new Vector2(Tw + gap, 36f), sel);
|
||||||
|
nl.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>화살표 버튼(투명 판 + 팩 화살표 아이콘 · 없으면 글자).</summary>
|
||||||
|
static void Arrow(Transform p, string name, string icon, float x, float y, System.Action onClick)
|
||||||
|
{
|
||||||
|
var rt = UiKit.At(p, name, x, y, 100f, 140f);
|
||||||
|
var img = rt.gameObject.AddComponent<Image>();
|
||||||
|
img.color = Color.clear;
|
||||||
|
rt.gameObject.AddComponent<Button>().onClick.AddListener(() => onClick());
|
||||||
|
var ic = UiKit.Icon(rt, icon, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 96f);
|
||||||
|
if (ic != null) UiKit.DropShadow(ic, 4f);
|
||||||
|
else UiKit.Title(UiKit.FillLabel(rt, name == "Prev" ? "◁" : "▷", 70, UiKit.White), true);
|
||||||
|
}
|
||||||
|
|
||||||
void Step(int dir)
|
void Step(int dir)
|
||||||
{
|
{
|
||||||
int n = Mathf.Max(1, S.Db.Chests.chests.Count);
|
int n = Mathf.Max(1, S.Db.Chests.chests.Count);
|
||||||
|
|
@ -350,17 +521,10 @@ namespace TKS.OutGame
|
||||||
new OutGameRoot.ModalButton("확인", UiKit.Dark, null));
|
new OutGameRoot.ModalButton("확인", UiKit.Dark, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>상자 대표 색 = 테마 chest_<id>(구 코드 상수 → ui_theme.csv · C45 · #1104).</summary>
|
||||||
public static Color ChestColor(string id)
|
public static Color ChestColor(string id)
|
||||||
{
|
{
|
||||||
switch (id)
|
return UiKit.Col("chest_" + id, UiKit.Slot);
|
||||||
{
|
|
||||||
case "bronze": return new Color(0.69f, 0.47f, 0.3f);
|
|
||||||
case "silver": return new Color(0.66f, 0.68f, 0.72f);
|
|
||||||
case "gold": return new Color(0.88f, 0.7f, 0.22f);
|
|
||||||
case "general": return new Color(0.62f, 0.25f, 0.22f);
|
|
||||||
case "gem": return new Color(0.3f, 0.65f, 0.57f);
|
|
||||||
}
|
|
||||||
return UiKit.Slot;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -720,7 +720,7 @@ namespace TKS.OutGame
|
||||||
var bt = UiKit.Title(UiKit.Label(row, "+" + gain, 40, UiKit.Col("ok", UiKit.Ok), TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(ax + 112f, -22f), new Vector2(140f, 60f)), true);
|
var bt = UiKit.Title(UiKit.Label(row, "+" + gain, 40, UiKit.Col("ok", UiKit.Ok), TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(ax + 112f, -22f), new Vector2(140f, 60f)), true);
|
||||||
bt.horizontalOverflow = HorizontalWrapMode.Overflow;
|
bt.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
UiKit.Label(row, note, 24, UiKit.Col("text_soft", UiKit.InkSoft), TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(30f, -96f), new Vector2(w - 380f, 36f), false);
|
UiKit.Label(row, note, 24, UiKit.Col("text_soft", UiKit.InkSoft), TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(30f, -96f), new Vector2(w - 380f, 36f), false);
|
||||||
var btn = UiKit.SkinBtn(row, "Btn", can || !UISkin.Has("btn_gray") ? skin : "btn_gray", UiKit.White, label, 38, can ? UiKit.White : UiKit.Col("disabled_text", UiKit.Disabled), w - Pad * 2f - 24f - 250f, 20f, 250f, 100f, onClick);
|
var btn = UiKit.SkinBtn(row, "Btn", can || !UISkin.Has("btn_gray") ? skin : "btn_gray", UiKit.White, label, 38, UiKit.White, w - Pad * 2f - 24f - 250f, 20f, 250f, 100f, onClick);
|
||||||
if (skin == "btn_s_green" && can) UiKit.BtnCost(btn, "ad", "", 36f, 24);
|
if (skin == "btn_s_green" && can) UiKit.BtnCost(btn, "ad", "", 36f, 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -797,7 +797,7 @@ namespace TKS.OutGame
|
||||||
ti.color = UiKit.White;
|
ti.color = UiKit.White;
|
||||||
UiKit.DropShadow(ti, 2f);
|
UiKit.DropShadow(ti, 2f);
|
||||||
}
|
}
|
||||||
var n = UiKit.Title(UiKit.Label(field, "×" + counts[kinds[k]], 36, UiKit.White, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 0.5f), new Vector2(cx + 50f, -y - 94f), new Vector2(100f, 50f)), true);
|
var n = UiKit.Title(UiKit.Label(field, "x" + counts[kinds[k]], 36, UiKit.White, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 0.5f), new Vector2(cx + 50f, -y - 94f), new Vector2(100f, 50f)), true);
|
||||||
n.horizontalOverflow = HorizontalWrapMode.Overflow;
|
n.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
}
|
}
|
||||||
y += 140f;
|
y += 140f;
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,7 @@ namespace TKS.OutGame
|
||||||
{
|
{
|
||||||
float h = size + 12f;
|
float h = size + 12f;
|
||||||
var chip = Skin(Rect("Qty", cell, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(8f, -8f), new Vector2(60f, h)), "chip", Col("chip_dark", Dark));
|
var chip = Skin(Rect("Qty", cell, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(8f, -8f), new Vector2(60f, h)), "chip", Col("chip_dark", Dark));
|
||||||
var t = Title(FillLabel(chip.transform, qty, size, White, TextAnchor.MiddleCenter, true, 0f), true);
|
var t = Title(FillLabel(chip.transform, qty.Replace("×", "x"), size, White, TextAnchor.MiddleCenter, true, 0f), true); // Sen 에 × 글리프 없음
|
||||||
t.horizontalOverflow = HorizontalWrapMode.Overflow;
|
t.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
chip.rectTransform.sizeDelta = new Vector2(Mathf.Max(h + 8f, Mathf.Ceil(t.preferredWidth) + 30f), h);
|
chip.rectTransform.sizeDelta = new Vector2(Mathf.Max(h + 8f, Mathf.Ceil(t.preferredWidth) + 30f), h);
|
||||||
return t;
|
return t;
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,27 @@ namespace TKS
|
||||||
Text skillPassive;
|
Text skillPassive;
|
||||||
Text skillLog;
|
Text skillLog;
|
||||||
|
|
||||||
|
// 유닛 정보 판 · 수 칩 · 스킬 빛(Fable 제안서 §4-8 · #1104 · 테마가 있을 때만)
|
||||||
|
RectTransform unitCard;
|
||||||
|
RectTransform unitBody;
|
||||||
|
Image portraitRing;
|
||||||
|
Image portraitArt;
|
||||||
|
Image typeRing;
|
||||||
|
Image typeIcon;
|
||||||
|
RectTransform hpFill;
|
||||||
|
Text nameText;
|
||||||
|
Text hpText;
|
||||||
|
Text atkText;
|
||||||
|
Text defText;
|
||||||
|
Text extraText;
|
||||||
|
Text stateText;
|
||||||
|
Text emptyText;
|
||||||
|
Unit shownUnit;
|
||||||
|
Text allyCount;
|
||||||
|
Text enemyCount;
|
||||||
|
Image skillGlow;
|
||||||
|
const float HpBarW = 360f;
|
||||||
|
|
||||||
Image minimapBg;
|
Image minimapBg;
|
||||||
Image minimapView;
|
Image minimapView;
|
||||||
readonly Dictionary<Unit, Image> minimapDots = new Dictionary<Unit, Image>();
|
readonly Dictionary<Unit, Image> minimapDots = new Dictionary<Unit, Image>();
|
||||||
|
|
@ -160,6 +181,8 @@ namespace TKS
|
||||||
var mmMid = MakeImage("Mid", minimapBg.transform, new Vector2(0f, 0.5f), new Vector2(1f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(0f, 2f), new Color(1f, 1f, 1f, 0.25f));
|
var mmMid = MakeImage("Mid", minimapBg.transform, new Vector2(0f, 0.5f), new Vector2(1f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(0f, 2f), new Color(1f, 1f, 1f, 0.25f));
|
||||||
minimapView = MakeImage("View", minimapBg.transform, Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(40f, 60f), new Color(1f, 1f, 1f, 0.2f));
|
minimapView = MakeImage("View", minimapBg.transform, Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(40f, 60f), new Color(1f, 1f, 1f, 0.2f));
|
||||||
|
|
||||||
|
if (UISkin.Has("hp_bg") && UISkin.Has("chip") && UISkin.Has("circle_frame")) BuildKit();
|
||||||
|
|
||||||
resultOverlay = MakeImage("ResultOverlay", transform, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero, new Color(0f, 0f, 0f, 0.65f)).gameObject;
|
resultOverlay = MakeImage("ResultOverlay", transform, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero, new Color(0f, 0f, 0f, 0.65f)).gameObject;
|
||||||
resultTitle = MakeText("Title", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 60f), new Vector2(1000f, 160f), 110, TextAnchor.MiddleCenter);
|
resultTitle = MakeText("Title", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 60f), new Vector2(1000f, 160f), 110, TextAnchor.MiddleCenter);
|
||||||
resultTitle.transform.SetParent(resultOverlay.transform, false);
|
resultTitle.transform.SetParent(resultOverlay.transform, false);
|
||||||
|
|
@ -169,6 +192,110 @@ namespace TKS
|
||||||
resultOverlay.SetActive(false);
|
resultOverlay.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fable 제안서 §4-8(#1104): 아래 유닛 판(초상 원 150 + 이름 · 병종 원 · 체력 바 · 공/방 칩 · 슬링/사거리 칩) ·
|
||||||
|
/// 오른쪽 위 수 칩 = 아군·적 아이콘 + 숫자 · 스킬 버튼 뒤 빛(사용 가능일 때 호흡) · 기본 조작 문장 삭제(상황 안내만 유지).
|
||||||
|
/// </summary>
|
||||||
|
void BuildKit()
|
||||||
|
{
|
||||||
|
var soft = UISkin.Col("text_soft", new Color(0.78f, 0.8f, 0.84f));
|
||||||
|
// 유닛 판(기존 UnitPanel 판 대신 · 왼쪽 아래 24 · 판 위 내용)
|
||||||
|
var old = transform.Find("UnitPanel");
|
||||||
|
if (old != null) old.gameObject.SetActive(false);
|
||||||
|
unitText.gameObject.SetActive(false);
|
||||||
|
var card = MakeImage("UnitCard", transform, Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(24f, 92f), new Vector2(720f, 196f), UISkin.Col("hud_panel", new Color(0.12f, 0.15f, 0.21f, 0.85f)));
|
||||||
|
UISkin.Apply(card, "card");
|
||||||
|
unitCard = card.rectTransform;
|
||||||
|
unitBody = OutGame.UiKit.Fill("Body", unitCard);
|
||||||
|
portraitRing = OutGame.UiKit.Skin(OutGame.UiKit.At(unitBody, "Ring", 18f, 22f, 152f, 152f), "circle_frame", Color.white);
|
||||||
|
var mask = MakeImage("Mask", portraitRing.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(132f, 132f), Color.white);
|
||||||
|
mask.sprite = OutGame.UiKit.Circle;
|
||||||
|
mask.gameObject.AddComponent<Mask>().showMaskGraphic = false;
|
||||||
|
portraitArt = MakeImage("Art", mask.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -40f), new Vector2(230f, 230f), Color.white);
|
||||||
|
portraitArt.preserveAspect = true;
|
||||||
|
typeRing = OutGame.UiKit.Skin(OutGame.UiKit.At(unitBody, "TypeRing", 188f, 20f, 52f, 52f), "circle_frame", Color.white);
|
||||||
|
typeIcon = OutGame.UiKit.Icon(typeRing.transform, "cls_infantry", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 34f);
|
||||||
|
nameText = OutGame.UiKit.Title(OutGame.UiKit.Label(unitBody, "", 36, Color.white, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(250f, -18f), new Vector2(300f, 56f)), true);
|
||||||
|
nameText.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
stateText = OutGame.UiKit.Label(unitBody, "", 24, soft, TextAnchor.MiddleRight, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-20f, -22f), new Vector2(220f, 48f), false);
|
||||||
|
var hpBg = OutGame.UiKit.Skin(OutGame.UiKit.At(unitBody, "Hp", 188f, 86f, HpBarW, 30f), "hp_bg", UISkin.Col("hp_bg", Color.white));
|
||||||
|
hpFill = OutGame.UiKit.At(hpBg.transform, "Fill", 4f, 4f, HpBarW - 8f, 22f);
|
||||||
|
OutGame.UiKit.Skin(hpFill, "hp_fill", UISkin.Col("hp_hi", Color.green));
|
||||||
|
hpText = OutGame.UiKit.Title(OutGame.UiKit.Label(unitBody, "", 26, Color.white, TextAnchor.MiddleLeft, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(188f + HpBarW + 14f, -80f), new Vector2(160f, 44f)), true);
|
||||||
|
hpText.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||||
|
atkText = OutGame.UiKit.InfoChip(unitBody, "Atk", 188f, 128f, 150f, 48f, "sword", "", 28);
|
||||||
|
defText = OutGame.UiKit.InfoChip(unitBody, "Def", 350f, 128f, 150f, 48f, "shield", "", 28);
|
||||||
|
extraText = OutGame.UiKit.InfoChip(unitBody, "Extra", 512f, 128f, 188f, 48f, null, "", 24);
|
||||||
|
emptyText = OutGame.UiKit.Label(unitCard, "유닛을 선택하세요", 30, soft, TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(680f, 60f), false);
|
||||||
|
|
||||||
|
// 수 칩 = 아군 · 적 아이콘 + 숫자(Sen)
|
||||||
|
var cc = transform.Find("CountChip");
|
||||||
|
if (cc != null && OutGame.UiKit.Icon(cc, "hud_ally", new Vector2(0f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(48f, 0f), 56f) != null)
|
||||||
|
{
|
||||||
|
countText.gameObject.SetActive(false);
|
||||||
|
OutGame.UiKit.Icon(cc, "hud_enemy", new Vector2(0f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(200f, 0f), 56f);
|
||||||
|
allyCount = OutGame.UiKit.Title(OutGame.UiKit.Label(cc, "", 40, Color.white, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(84f, 2f), new Vector2(80f, 60f)), true);
|
||||||
|
enemyCount = OutGame.UiKit.Title(OutGame.UiKit.Label(cc, "", 40, Color.white, TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(236f, 2f), new Vector2(80f, 60f)), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 스킬 버튼 뒤 빛(사용 가능 = 호흡)
|
||||||
|
if (UISkin.Has("glow_circle"))
|
||||||
|
{
|
||||||
|
skillGlow = MakeImage("SkillGlow", transform, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(0.5f, 0.5f), new Vector2(-24f - 125f, 100f + 125f), new Vector2(380f, 380f), UISkin.Col("skill_glow", new Color(0.85f, 0.25f, 0.18f, 0.4f)));
|
||||||
|
UISkin.Apply(skillGlow, "glow_circle");
|
||||||
|
skillGlow.transform.SetSiblingIndex(skillPanel.transform.GetSiblingIndex());
|
||||||
|
var pulse = skillGlow.gameObject.AddComponent<OutGame.UiPulse>();
|
||||||
|
pulse.min = 0.45f;
|
||||||
|
pulse.period = 1.2f;
|
||||||
|
skillGlow.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>유닛 판 값 갱신(매 프레임 · 초상은 선택이 바뀔 때만).</summary>
|
||||||
|
void RefreshUnitCard(Unit u)
|
||||||
|
{
|
||||||
|
bool on = u != null && u.IsAlive;
|
||||||
|
if (unitBody.gameObject.activeSelf != on) unitBody.gameObject.SetActive(on);
|
||||||
|
emptyText.gameObject.SetActive(!on);
|
||||||
|
if (!on)
|
||||||
|
{
|
||||||
|
shownUnit = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (shownUnit != u)
|
||||||
|
{
|
||||||
|
shownUnit = u;
|
||||||
|
var sp = OutGame.UiKit.ArtSprite(u.ArtId);
|
||||||
|
portraitArt.sprite = sp;
|
||||||
|
portraitArt.enabled = sp != null;
|
||||||
|
portraitRing.color = u.Faction == Faction.Player ? UISkin.Col("hud_turn_player", Color.blue) : UISkin.Col("hud_turn_enemy", Color.red);
|
||||||
|
typeRing.color = OutGame.UiKit.TypeColor(u.Type);
|
||||||
|
var tsp = UISkin.Icon(OutGame.UiKit.TypeIconId(u.Type));
|
||||||
|
if (typeIcon != null && tsp != null) typeIcon.sprite = tsp;
|
||||||
|
}
|
||||||
|
nameText.text = u.DisplayName + (u.IsBoss ? " <size=24>장수</size>" : "");
|
||||||
|
float r = u.MaxHp > 0 ? Mathf.Clamp01(u.Hp / (float)u.MaxHp) : 0f;
|
||||||
|
hpFill.sizeDelta = new Vector2(Mathf.Max(12f, (HpBarW - 8f) * r), hpFill.sizeDelta.y);
|
||||||
|
hpFill.gameObject.SetActive(r > 0f);
|
||||||
|
hpFill.GetComponent<Image>().color = r > 0.5f ? UISkin.Col("hp_hi", Color.green) : r > 0.25f ? UISkin.Col("hp_mid", Color.yellow) : UISkin.Col("hp_low", Color.red);
|
||||||
|
hpText.text = u.Hp + "/" + u.MaxHp;
|
||||||
|
atkText.text = u.Atk.ToString();
|
||||||
|
defText.text = u.Def.ToString();
|
||||||
|
string extra = "슬링 " + SkillMods.SlingMax(u).ToString("0.#");
|
||||||
|
if (UnitTypeInfo.IsRanged(u.Type)) extra = "사거리 " + SkillMods.Range(u).ToString("0.#");
|
||||||
|
else if (u.Type == UnitType.Spear) extra = "견제 " + SkillMods.OverwatchRadius(u).ToString("0.#");
|
||||||
|
if (u.Type == UnitType.Strategist) extra = "광역 " + SkillMods.SplashRadius(u, battle.Config).ToString("0.#");
|
||||||
|
extraText.text = extra;
|
||||||
|
string state = u.Faction == Faction.Player ? "아군" : "적군";
|
||||||
|
if (u.Faction == Faction.Player)
|
||||||
|
{
|
||||||
|
if (u.BonusMoveAvailable) state = "추가 이동";
|
||||||
|
else if (u.ActedThisTurn) state = "행동 완료";
|
||||||
|
}
|
||||||
|
if (u.Overwatch) state += " · 대기 중";
|
||||||
|
stateText.text = state;
|
||||||
|
}
|
||||||
|
|
||||||
Text MakeText(string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPos, Vector2 size, int fontSize, TextAnchor align)
|
Text MakeText(string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPos, Vector2 size, int fontSize, TextAnchor align)
|
||||||
{
|
{
|
||||||
var go = new GameObject(name);
|
var go = new GameObject(name);
|
||||||
|
|
@ -356,6 +483,11 @@ namespace TKS
|
||||||
? stage.chapter + "-" + stage.stage + " · " + stage.title
|
? stage.chapter + "-" + stage.stage + " · " + stage.title
|
||||||
: "제" + (battle.StageIndex + 1) + "전투 · " + stage.title + (string.IsNullOrEmpty(stage.subtitle) ? "" : " " + stage.subtitle);
|
: "제" + (battle.StageIndex + 1) + "전투 · " + stage.title + (string.IsNullOrEmpty(stage.subtitle) ? "" : " " + stage.subtitle);
|
||||||
countText.text = "아군 " + battle.AliveCount(Faction.Player) + " · 적 " + battle.AliveCount(Faction.Enemy);
|
countText.text = "아군 " + battle.AliveCount(Faction.Player) + " · 적 " + battle.AliveCount(Faction.Enemy);
|
||||||
|
if (allyCount != null)
|
||||||
|
{
|
||||||
|
allyCount.text = battle.AliveCount(Faction.Player).ToString();
|
||||||
|
enemyCount.text = battle.AliveCount(Faction.Enemy).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
switch (battle.Phase)
|
switch (battle.Phase)
|
||||||
{
|
{
|
||||||
|
|
@ -382,9 +514,10 @@ namespace TKS
|
||||||
}
|
}
|
||||||
else if (battle.Phase == BattlePhase.PlayerTurn)
|
else if (battle.Phase == BattlePhase.PlayerTurn)
|
||||||
{
|
{
|
||||||
|
// 기본 조작 문장은 테마 HUD 에서 삭제(Fable §4-8 · 첫 전투 튜토리얼 손으로 대체 예정) · 상황 안내만 유지
|
||||||
hintText.text = battle.OnlyBonusMovesRemain()
|
hintText.text = battle.OnlyBonusMovesRemain()
|
||||||
? "추가 이동: 유닛을 당겨 이동 · 빈 곳을 탭하면 건너뜀"
|
? "추가 이동: 유닛을 당겨 이동 · 빈 곳을 탭하면 건너뜀"
|
||||||
: "유닛을 잡고 뒤로 당겼다 놓기 = 이동·공격 · 유닛 탭 = 사거리 · 빈 곳 드래그 = 전장 이동";
|
: unitCard != null ? "" : "유닛을 잡고 뒤로 당겼다 놓기 = 이동·공격 · 유닛 탭 = 사거리 · 빈 곳 드래그 = 전장 이동";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -414,7 +547,14 @@ namespace TKS
|
||||||
{
|
{
|
||||||
unitText.text = "유닛을 선택하세요";
|
unitText.text = "유닛을 선택하세요";
|
||||||
}
|
}
|
||||||
|
if (unitCard != null) RefreshUnitCard(selected);
|
||||||
RefreshSkill();
|
RefreshSkill();
|
||||||
|
if (skillGlow != null)
|
||||||
|
{
|
||||||
|
bool ready = skillPanel.gameObject.activeSelf && battle.Skills != null && selected != null && selected.IsAlive && selected.Faction == Faction.Player
|
||||||
|
&& battle.Skills.StateOf(selected) == SkillSystem.ActiveState.Ready;
|
||||||
|
if (skillGlow.gameObject.activeSelf != ready) skillGlow.gameObject.SetActive(ready);
|
||||||
|
}
|
||||||
|
|
||||||
bool result = battle.Phase == BattlePhase.StageClear || battle.Phase == BattlePhase.Defeat;
|
bool result = battle.Phase == BattlePhase.StageClear || battle.Phase == BattlePhase.Defeat;
|
||||||
if (resultOverlay.activeSelf != result) resultOverlay.SetActive(result);
|
if (resultOverlay.activeSelf != result) resultOverlay.SetActive(result);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue